diff --git a/.github/VOUCHED.td b/.github/VOUCHED.td index 412716a18d..28535b5779 100644 --- a/.github/VOUCHED.td +++ b/.github/VOUCHED.td @@ -8,7 +8,9 @@ # - Denounce with minus prefix: -username or -platform:username. # - Optional details after a space following the handle. adamdotdevin +-agusbasari29 AI PR slop ariane-emory +edemaine -florianleibert fwang iamdavidhill diff --git a/.github/actions/setup-bun/action.yml b/.github/actions/setup-bun/action.yml index 20d53e81e8..6c632f7e07 100644 --- a/.github/actions/setup-bun/action.yml +++ b/.github/actions/setup-bun/action.yml @@ -11,10 +11,25 @@ runs: restore-keys: | ${{ runner.os }}-bun- + - name: Get baseline download URL + id: bun-url + shell: bash + run: | + if [ "$RUNNER_ARCH" = "X64" ]; then + V=$(node -p "require('./package.json').packageManager.split('@')[1]") + case "$RUNNER_OS" in + macOS) OS=darwin ;; + Linux) OS=linux ;; + Windows) OS=windows ;; + esac + echo "url=https://github.com/oven-sh/bun/releases/download/bun-v${V}/bun-${OS}-x64-baseline.zip" >> "$GITHUB_OUTPUT" + fi + - name: Setup Bun uses: oven-sh/setup-bun@v2 with: - bun-version-file: package.json + bun-version-file: ${{ !steps.bun-url.outputs.url && 'package.json' || '' }} + bun-download-url: ${{ steps.bun-url.outputs.url }} - name: Install dependencies run: bun install diff --git a/.github/workflows/beta.yml b/.github/workflows/beta.yml index 20d2bc18d8..a7106667b1 100644 --- a/.github/workflows/beta.yml +++ b/.github/workflows/beta.yml @@ -27,7 +27,11 @@ jobs: opencode-app-id: ${{ vars.OPENCODE_APP_ID }} opencode-app-secret: ${{ secrets.OPENCODE_APP_SECRET }} + - name: Install OpenCode + run: bun i -g opencode-ai + - name: Sync beta branch env: GH_TOKEN: ${{ steps.setup-git-committer.outputs.token }} + OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }} run: bun script/beta.ts diff --git a/.github/workflows/compliance-close.yml b/.github/workflows/compliance-close.yml index 5b424d0adf..c3bcf9f686 100644 --- a/.github/workflows/compliance-close.yml +++ b/.github/workflows/compliance-close.yml @@ -65,6 +65,15 @@ jobs: body: closeMessage, }); + try { + await github.rest.issues.removeLabel({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: item.number, + name: 'needs:compliance', + }); + } catch (e) {} + if (isPR) { await github.rest.pulls.update({ owner: context.repo.owner, diff --git a/.github/workflows/docs-locale-sync.yml b/.github/workflows/docs-locale-sync.yml index 8cd0cc52e2..fff2ec4292 100644 --- a/.github/workflows/docs-locale-sync.yml +++ b/.github/workflows/docs-locale-sync.yml @@ -12,13 +12,14 @@ jobs: if: github.actor != 'opencode-agent[bot]' runs-on: blacksmith-4vcpu-ubuntu-2404 permissions: - id-token: write contents: write steps: - name: Checkout repository uses: actions/checkout@v4 with: + persist-credentials: false fetch-depth: 0 + ref: ${{ github.ref_name }} - name: Setup Bun uses: ./.github/actions/setup-bun @@ -46,15 +47,26 @@ jobs: echo "EOF" } >> "$GITHUB_OUTPUT" + - name: Install OpenCode + if: steps.changes.outputs.has_changes == 'true' + run: curl -fsSL https://opencode.ai/install | bash + - name: Sync locale docs with OpenCode if: steps.changes.outputs.has_changes == 'true' - uses: sst/opencode/github@latest env: OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }} - with: - model: opencode/gpt-5.2 - agent: docs - prompt: | + OPENCODE_CONFIG_CONTENT: | + { + "permission": { + "*": "deny", + "read": "allow", + "edit": "allow", + "glob": "allow", + "task": "allow" + } + } + run: | + opencode run --agent docs --model opencode/gpt-5.3-codex <<'EOF' Update localized docs to match the latest English docs changes. Changed English doc files: @@ -67,10 +79,12 @@ jobs: 2. You MUST use the Task tool for translation work and launch subagents with subagent_type `translator` (defined in .opencode/agent/translator.md). 3. Do not translate directly in the primary agent. Use translator subagent output as the source for locale text updates. 4. Run translator subagent Task calls in parallel whenever file/locale translation work is independent. - 5. Preserve frontmatter keys, internal links, code blocks, and existing locale-specific metadata unless the English change requires an update. - 6. Keep locale docs structure aligned with their corresponding English pages. - 7. Do not modify English source docs in packages/web/src/content/docs/*.mdx. - 8. If no locale updates are needed, make no changes. + 5. Use only the minimum tools needed for this task (read/glob, file edits, and translator Task). Do not use shell, web, search, or GitHub tools for translation work. + 6. Preserve frontmatter keys, internal links, code blocks, and existing locale-specific metadata unless the English change requires an update. + 7. Keep locale docs structure aligned with their corresponding English pages. + 8. Do not modify English source docs in packages/web/src/content/docs/*.mdx. + 9. If no locale updates are needed, make no changes. + EOF - name: Commit and push locale docs updates if: steps.changes.outputs.has_changes == 'true' diff --git a/.github/workflows/pr-standards.yml b/.github/workflows/pr-standards.yml index 27581d06b7..1edbd5d061 100644 --- a/.github/workflows/pr-standards.yml +++ b/.github/workflows/pr-standards.yml @@ -108,11 +108,11 @@ jobs: await removeLabel('needs:title'); - // Step 2: Check for linked issue (skip for docs/refactor PRs) - const skipIssueCheck = /^(docs|refactor)\s*(\([a-zA-Z0-9-]+\))?\s*:/.test(title); + // Step 2: Check for linked issue (skip for docs/refactor/feat PRs) + const skipIssueCheck = /^(docs|refactor|feat)\s*(\([a-zA-Z0-9-]+\))?\s*:/.test(title); if (skipIssueCheck) { await removeLabel('needs:issue'); - console.log('Skipping issue check for docs/refactor PR'); + console.log('Skipping issue check for docs/refactor/feat PR'); return; } const query = ` @@ -189,7 +189,7 @@ jobs: const body = pr.body || ''; const title = pr.title; - const isDocsOrRefactor = /^(docs|refactor)\s*(\([a-zA-Z0-9-]+\))?\s*:/.test(title); + const isDocsRefactorOrFeat = /^(docs|refactor|feat)\s*(\([a-zA-Z0-9-]+\))?\s*:/.test(title); const issues = []; @@ -225,8 +225,8 @@ jobs: } } - // Check: issue reference (skip for docs/refactor) - if (!isDocsOrRefactor && hasIssueSection) { + // Check: issue reference (skip for docs/refactor/feat) + if (!isDocsRefactorOrFeat && hasIssueSection) { const issueMatch = body.match(/### Issue for this PR\s*\n([\s\S]*?)(?=###|$)/); const issueContent = issueMatch ? issueMatch[1].trim() : ''; const hasIssueRef = /(closes|fixes|resolves)\s+#\d+/i.test(issueContent) || /#\d+/.test(issueContent); diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 8d4c9038a7..0dbd04f821 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -99,7 +99,6 @@ jobs: with: name: opencode-cli path: packages/opencode/dist - outputs: version: ${{ needs.version.outputs.version }} @@ -240,11 +239,131 @@ jobs: APPLE_API_KEY: ${{ secrets.APPLE_API_KEY }} APPLE_API_KEY_PATH: ${{ runner.temp }}/apple-api-key.p8 + build-electron: + needs: + - build-cli + - version + continue-on-error: false + strategy: + fail-fast: false + matrix: + settings: + - host: macos-latest + target: x86_64-apple-darwin + platform_flag: --mac --x64 + - host: macos-latest + target: aarch64-apple-darwin + platform_flag: --mac --arm64 + - host: "blacksmith-4vcpu-windows-2025" + target: x86_64-pc-windows-msvc + platform_flag: --win + - host: "blacksmith-4vcpu-ubuntu-2404" + target: x86_64-unknown-linux-gnu + platform_flag: --linux + - host: "blacksmith-4vcpu-ubuntu-2404" + target: aarch64-unknown-linux-gnu + platform_flag: --linux + runs-on: ${{ matrix.settings.host }} + # if: github.ref_name == 'beta' + steps: + - uses: actions/checkout@v3 + + - uses: apple-actions/import-codesign-certs@v2 + if: runner.os == 'macOS' + with: + keychain: build + p12-file-base64: ${{ secrets.APPLE_CERTIFICATE }} + p12-password: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} + + - name: Setup Apple API Key + if: runner.os == 'macOS' + run: echo "${{ secrets.APPLE_API_KEY_PATH }}" > $RUNNER_TEMP/apple-api-key.p8 + + - uses: ./.github/actions/setup-bun + + - uses: actions/setup-node@v4 + with: + node-version: "24" + + - name: Cache apt packages + if: contains(matrix.settings.host, 'ubuntu') + uses: actions/cache@v4 + with: + path: ~/apt-cache + key: ${{ runner.os }}-${{ matrix.settings.target }}-apt-electron-${{ hashFiles('.github/workflows/publish.yml') }} + restore-keys: | + ${{ runner.os }}-${{ matrix.settings.target }}-apt-electron- + + - name: Install dependencies (ubuntu only) + if: contains(matrix.settings.host, 'ubuntu') + run: | + mkdir -p ~/apt-cache && chmod -R a+rw ~/apt-cache + sudo apt-get update + sudo apt-get install -y --no-install-recommends -o dir::cache::archives="$HOME/apt-cache" rpm + sudo chmod -R a+rw ~/apt-cache + + - name: Setup git committer + id: committer + uses: ./.github/actions/setup-git-committer + with: + opencode-app-id: ${{ vars.OPENCODE_APP_ID }} + opencode-app-secret: ${{ secrets.OPENCODE_APP_SECRET }} + + - name: Prepare + run: bun ./scripts/prepare.ts + working-directory: packages/desktop-electron + env: + OPENCODE_VERSION: ${{ needs.version.outputs.version }} + OPENCODE_CHANNEL: ${{ (github.ref_name == 'beta' && 'beta') || 'prod' }} + RUST_TARGET: ${{ matrix.settings.target }} + GH_TOKEN: ${{ github.token }} + GITHUB_RUN_ID: ${{ github.run_id }} + + - name: Build + run: bun run build + working-directory: packages/desktop-electron + env: + OPENCODE_CHANNEL: ${{ (github.ref_name == 'beta' && 'beta') || 'prod' }} + + - name: Package and publish + if: needs.version.outputs.release + run: npx electron-builder ${{ matrix.settings.platform_flag }} --publish always --config electron-builder.config.ts + working-directory: packages/desktop-electron + timeout-minutes: 60 + env: + OPENCODE_CHANNEL: ${{ (github.ref_name == 'beta' && 'beta') || 'prod' }} + GH_TOKEN: ${{ steps.committer.outputs.token }} + CSC_LINK: ${{ secrets.APPLE_CERTIFICATE }} + CSC_KEY_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} + APPLE_API_KEY: ${{ runner.temp }}/apple-api-key.p8 + APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY }} + APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }} + + - name: Package (no publish) + if: ${{ !needs.version.outputs.release }} + run: npx electron-builder ${{ matrix.settings.platform_flag }} --publish never --config electron-builder.config.ts + working-directory: packages/desktop-electron + timeout-minutes: 60 + env: + OPENCODE_CHANNEL: ${{ (github.ref_name == 'beta' && 'beta') || 'prod' }} + + - uses: actions/upload-artifact@v4 + with: + name: opencode-electron-${{ matrix.settings.target }} + path: packages/desktop-electron/dist/* + + - uses: actions/upload-artifact@v4 + if: needs.version.outputs.release + with: + name: latest-yml-${{ matrix.settings.target }} + path: packages/desktop-electron/dist/latest*.yml + publish: needs: - version - build-cli - build-tauri + - build-electron runs-on: blacksmith-4vcpu-ubuntu-2404 steps: - uses: actions/checkout@v3 @@ -281,6 +400,12 @@ jobs: name: opencode-cli path: packages/opencode/dist + - uses: actions/download-artifact@v4 + if: needs.version.outputs.release + with: + pattern: latest-yml-* + path: /tmp/latest-yml + - name: Cache apt packages (AUR) uses: actions/cache@v4 with: @@ -308,3 +433,4 @@ jobs: GITHUB_TOKEN: ${{ steps.committer.outputs.token }} GH_REPO: ${{ needs.version.outputs.repo }} NPM_CONFIG_PROVENANCE: false + LATEST_YML_DIR: /tmp/latest-yml diff --git a/.github/workflows/storybook.yml b/.github/workflows/storybook.yml new file mode 100644 index 0000000000..6d143a8a22 --- /dev/null +++ b/.github/workflows/storybook.yml @@ -0,0 +1,38 @@ +name: storybook + +on: + push: + branches: [dev] + paths: + - ".github/workflows/storybook.yml" + - "package.json" + - "bun.lock" + - "packages/storybook/**" + - "packages/ui/**" + pull_request: + branches: [dev] + paths: + - ".github/workflows/storybook.yml" + - "package.json" + - "bun.lock" + - "packages/storybook/**" + - "packages/ui/**" + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + name: storybook build + runs-on: blacksmith-4vcpu-ubuntu-2404 + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Bun + uses: ./.github/actions/setup-bun + + - name: Build Storybook + run: bun --cwd packages/storybook build diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 647b9e1886..f7b00516f8 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -8,8 +8,16 @@ on: workflow_dispatch: jobs: unit: - name: unit (linux) - runs-on: blacksmith-4vcpu-ubuntu-2404 + name: unit (${{ matrix.settings.name }}) + strategy: + fail-fast: false + matrix: + settings: + - name: linux + host: blacksmith-4vcpu-ubuntu-2404 + - name: windows + host: blacksmith-4vcpu-windows-2025 + runs-on: ${{ matrix.settings.host }} defaults: run: shell: bash diff --git a/.github/workflows/vouch-check-issue.yml b/.github/workflows/vouch-check-issue.yml index 94569f4731..4c2aa960b2 100644 --- a/.github/workflows/vouch-check-issue.yml +++ b/.github/workflows/vouch-check-issue.yml @@ -42,15 +42,17 @@ jobs: throw error; } - // Parse the .td file for denounced users + // Parse the .td file for vouched and denounced users + const vouched = new Set(); const denounced = new Map(); for (const line of content.split('\n')) { const trimmed = line.trim(); if (!trimmed || trimmed.startsWith('#')) continue; - if (!trimmed.startsWith('-')) continue; - const rest = trimmed.slice(1).trim(); + const isDenounced = trimmed.startsWith('-'); + const rest = isDenounced ? trimmed.slice(1).trim() : trimmed; if (!rest) continue; + const spaceIdx = rest.indexOf(' '); const handle = spaceIdx === -1 ? rest : rest.slice(0, spaceIdx); const reason = spaceIdx === -1 ? null : rest.slice(spaceIdx + 1).trim(); @@ -65,32 +67,50 @@ jobs: const username = colonIdx === -1 ? handle : handle.slice(colonIdx + 1); if (!username) continue; - denounced.set(username.toLowerCase(), reason); + if (isDenounced) { + denounced.set(username.toLowerCase(), reason); + continue; + } + + vouched.add(username.toLowerCase()); } // Check if the author is denounced const reason = denounced.get(author.toLowerCase()); - if (reason === undefined) { - core.info(`User ${author} is not denounced. Allowing issue.`); + if (reason !== undefined) { + // Author is denounced — close the issue + const body = 'This issue has been automatically closed.'; + + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issueNumber, + body, + }); + + await github.rest.issues.update({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issueNumber, + state: 'closed', + state_reason: 'not_planned', + }); + + core.info(`Closed issue #${issueNumber} from denounced user ${author}`); return; } - // Author is denounced — close the issue - const body = 'This issue has been automatically closed.'; + // Author is positively vouched — add label + if (!vouched.has(author.toLowerCase())) { + core.info(`User ${author} is not denounced or vouched. Allowing issue.`); + return; + } - await github.rest.issues.createComment({ + await github.rest.issues.addLabels({ owner: context.repo.owner, repo: context.repo.repo, issue_number: issueNumber, - body, + labels: ['Vouched'], }); - await github.rest.issues.update({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: issueNumber, - state: 'closed', - state_reason: 'not_planned', - }); - - core.info(`Closed issue #${issueNumber} from denounced user ${author}`); + core.info(`Added vouched label to issue #${issueNumber} from ${author}`); diff --git a/.github/workflows/vouch-check-pr.yml b/.github/workflows/vouch-check-pr.yml index 470b8e0a5a..51816dfb75 100644 --- a/.github/workflows/vouch-check-pr.yml +++ b/.github/workflows/vouch-check-pr.yml @@ -6,6 +6,7 @@ on: permissions: contents: read + issues: write pull-requests: write jobs: @@ -42,15 +43,17 @@ jobs: throw error; } - // Parse the .td file for denounced users + // Parse the .td file for vouched and denounced users + const vouched = new Set(); const denounced = new Map(); for (const line of content.split('\n')) { const trimmed = line.trim(); if (!trimmed || trimmed.startsWith('#')) continue; - if (!trimmed.startsWith('-')) continue; - const rest = trimmed.slice(1).trim(); + const isDenounced = trimmed.startsWith('-'); + const rest = isDenounced ? trimmed.slice(1).trim() : trimmed; if (!rest) continue; + const spaceIdx = rest.indexOf(' '); const handle = spaceIdx === -1 ? rest : rest.slice(0, spaceIdx); const reason = spaceIdx === -1 ? null : rest.slice(spaceIdx + 1).trim(); @@ -65,29 +68,47 @@ jobs: const username = colonIdx === -1 ? handle : handle.slice(colonIdx + 1); if (!username) continue; - denounced.set(username.toLowerCase(), reason); + if (isDenounced) { + denounced.set(username.toLowerCase(), reason); + continue; + } + + vouched.add(username.toLowerCase()); } // Check if the author is denounced const reason = denounced.get(author.toLowerCase()); - if (reason === undefined) { - core.info(`User ${author} is not denounced. Allowing PR.`); + if (reason !== undefined) { + // Author is denounced — close the PR + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: prNumber, + body: 'This pull request has been automatically closed.', + }); + + await github.rest.pulls.update({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: prNumber, + state: 'closed', + }); + + core.info(`Closed PR #${prNumber} from denounced user ${author}`); return; } - // Author is denounced — close the PR - await github.rest.issues.createComment({ + // Author is positively vouched — add label + if (!vouched.has(author.toLowerCase())) { + core.info(`User ${author} is not denounced or vouched. Allowing PR.`); + return; + } + + await github.rest.issues.addLabels({ owner: context.repo.owner, repo: context.repo.repo, issue_number: prNumber, - body: 'This pull request has been automatically closed.', + labels: ['Vouched'], }); - await github.rest.pulls.update({ - owner: context.repo.owner, - repo: context.repo.repo, - pull_number: prNumber, - state: 'closed', - }); - - core.info(`Closed PR #${prNumber} from denounced user ${author}`); + core.info(`Added vouched label to PR #${prNumber} from ${author}`); diff --git a/.github/workflows/vouch-manage-by-issue.yml b/.github/workflows/vouch-manage-by-issue.yml index cf0524c21a..9604bf87f3 100644 --- a/.github/workflows/vouch-manage-by-issue.yml +++ b/.github/workflows/vouch-manage-by-issue.yml @@ -33,5 +33,6 @@ jobs: with: issue-id: ${{ github.event.issue.number }} comment-id: ${{ github.event.comment.id }} + roles: admin,maintain env: GITHUB_TOKEN: ${{ steps.committer.outputs.token }} diff --git a/.opencode/agent/translator.md b/.opencode/agent/translator.md index 0c2e176d8b..263afbe9b5 100644 --- a/.opencode/agent/translator.md +++ b/.opencode/agent/translator.md @@ -1,7 +1,7 @@ --- description: Translate content for a specified locale while preserving technical terms mode: subagent -model: opencode/gemini-3.1-pro +model: opencode/gemini-3-pro --- You are a professional translator and localization specialist. @@ -13,10 +13,25 @@ Requirements: - Preserve meaning, intent, tone, and formatting (including Markdown/MDX structure). - Preserve all technical terms and artifacts exactly: product/company names, API names, identifiers, code, commands/flags, file paths, URLs, versions, error messages, config keys/values, and anything inside inline code or code blocks. - Also preserve every term listed in the Do-Not-Translate glossary below. +- Also apply locale-specific guidance from `.opencode/glossary/.md` when available (for example, `zh-cn.md`). - Do not modify fenced code blocks. - Output ONLY the translation (no commentary). If the target locale is missing, ask the user to provide it. +If no locale-specific glossary exists, use the global glossary only. + +--- + +# Locale-Specific Glossaries + +When a locale glossary exists, use it to: + +- Apply preferred wording for recurring UI/docs terms in that locale +- Preserve locale-specific do-not-translate terms and casing decisions +- Prefer natural phrasing over literal translation when the locale file calls it out +- If the repo uses a locale alias slug, apply that file too (for example, `pt-BR` maps to `br.md` in this repo) + +Locale guidance does not override code/command preservation rules or the global Do-Not-Translate glossary below. --- diff --git a/.opencode/glossary/README.md b/.opencode/glossary/README.md new file mode 100644 index 0000000000..983900381c --- /dev/null +++ b/.opencode/glossary/README.md @@ -0,0 +1,63 @@ +# Locale Glossaries + +Use this folder for locale-specific translation guidance that supplements `.opencode/agent/translator.md`. + +The global glossary in `translator.md` remains the source of truth for shared do-not-translate terms (commands, code, paths, product names, etc.). These locale files capture community learnings about phrasing and terminology preferences. + +## File Naming + +- One file per locale +- Use lowercase locale slugs that match docs locales when possible (for example, `zh-cn.md`, `zh-tw.md`) +- If only language-level guidance exists, use the language code (for example, `fr.md`) +- Some repo locale slugs may be aliases/non-BCP47 for consistency (for example, `br` for Brazilian Portuguese / `pt-BR`) + +## What To Put In A Locale File + +- **Sources**: PRs/issues/discussions that motivated the guidance +- **Do Not Translate (Locale Additions)**: locale-specific terms or casing decisions +- **Preferred Terms**: recurring UI/docs words with preferred translations +- **Guidance**: tone, style, and consistency notes +- **Avoid** (optional): common literal translations or wording we should avoid +- If the repo uses a locale alias slug, document the alias in **Guidance** (for example, prose may mention `pt-BR` while config/examples use `br`) + +Prefer guidance that is: + +- Repeated across multiple docs/screens +- Easy to apply consistently +- Backed by a community contribution or review discussion + +## Template + +```md +# Glossary + +## Sources + +- PR #12345: https://github.com/anomalyco/opencode/pull/12345 + +## Do Not Translate (Locale Additions) + +- `OpenCode` (preserve casing) + +## Preferred Terms + +| English | Preferred | Notes | +| ------- | --------- | --------- | +| prompt | ... | preferred | +| session | ... | preferred | + +## Guidance + +- Prefer natural phrasing over literal translation + +## Avoid + +- Avoid ... when ... +``` + +## Contribution Notes + +- Mark entries as preferred when they may evolve +- Keep examples short +- Add or update the `Sources` section whenever you add a new rule +- Prefer PR-backed guidance over invented term mappings; start with general guidance if no term-level corrections exist yet diff --git a/.opencode/glossary/ar.md b/.opencode/glossary/ar.md new file mode 100644 index 0000000000..37355522a0 --- /dev/null +++ b/.opencode/glossary/ar.md @@ -0,0 +1,28 @@ +# ar Glossary + +## Sources + +- PR #9947: https://github.com/anomalyco/opencode/pull/9947 + +## Do Not Translate (Locale Additions) + +- `OpenCode` (preserve casing in prose; keep `opencode` only in commands, package names, paths, or code) +- `OpenCode CLI` +- `CLI`, `TUI`, `MCP`, `OAuth` +- Commands, flags, file paths, and code literals (keep exactly as written) + +## Preferred Terms + +No PR-backed term mappings yet. Add entries here when review PRs introduce repeated wording corrections. + +## Guidance + +- Prefer natural Arabic phrasing over literal translation +- Keep tone clear and direct in UI labels and docs prose +- Preserve technical artifacts exactly: commands, flags, code, URLs, model IDs, and file paths +- For RTL text, treat code, commands, and paths as LTR artifacts and keep their character order unchanged + +## Avoid + +- Avoid translating product and protocol names that are fixed identifiers +- Avoid mixing multiple Arabic terms for the same recurring UI action once a preferred term is established diff --git a/.opencode/glossary/br.md b/.opencode/glossary/br.md new file mode 100644 index 0000000000..fd3e7251cd --- /dev/null +++ b/.opencode/glossary/br.md @@ -0,0 +1,34 @@ +# br Glossary + +## Sources + +- PR #10086: https://github.com/anomalyco/opencode/pull/10086 + +## Do Not Translate (Locale Additions) + +- `OpenCode` (preserve casing in prose; keep `opencode` only in commands, package names, paths, or code) +- `OpenCode CLI` +- `CLI`, `TUI`, `MCP`, `OAuth` +- Locale code `br` in repo config, code, and paths (repo alias for Brazilian Portuguese) + +## Preferred Terms + +These are PR-backed locale naming preferences and may evolve. + +| English / Context | Preferred | Notes | +| ---------------------------------------- | ------------------------------ | ------------------------------------------------------------- | +| Brazilian Portuguese (prose locale name) | `pt-BR` | Use standard locale naming in prose when helpful | +| Repo locale slug (code/config) | `br` | PR #10086 uses `br` for consistency/simplicity | +| Browser locale detection | `pt`, `pt-br`, `pt-BR` -> `br` | Preserve this mapping in docs/examples about locale detection | + +## Guidance + +- This file covers Brazilian Portuguese (`pt-BR`), but the repo locale code is `br` +- Use natural Brazilian Portuguese phrasing over literal translation +- Preserve technical artifacts exactly: commands, flags, code, URLs, model IDs, and file paths +- Keep repo locale identifiers as implemented in code/config (`br`) even when prose mentions `pt-BR` + +## Avoid + +- Avoid changing repo locale code references from `br` to `pt-br` in code snippets, paths, or config examples +- Avoid mixing Portuguese variants when a Brazilian Portuguese form is established diff --git a/.opencode/glossary/bs.md b/.opencode/glossary/bs.md new file mode 100644 index 0000000000..aa3bd96f6f --- /dev/null +++ b/.opencode/glossary/bs.md @@ -0,0 +1,33 @@ +# bs Glossary + +## Sources + +- PR #12283: https://github.com/anomalyco/opencode/pull/12283 + +## Do Not Translate (Locale Additions) + +- `OpenCode` (preserve casing in prose; keep `opencode` only in commands, package names, paths, or code) +- `OpenCode CLI` +- `CLI`, `TUI`, `MCP`, `OAuth` +- Commands, flags, file paths, and code literals (keep exactly as written) + +## Preferred Terms + +These are PR-backed locale naming preferences and may evolve. + +| English / Context | Preferred | Notes | +| ---------------------------------- | ---------- | ------------------------------------------------- | +| Bosnian language label (UI) | `Bosanski` | PR #12283 tested switching language to `Bosanski` | +| Repo locale slug (code/config) | `bs` | Preserve in code, config, paths, and examples | +| Browser locale detection (Bosnian) | `bs` | PR #12283 added `bs` locale auto-detection | + +## Guidance + +- Use natural Bosnian phrasing over literal translation +- Preserve technical artifacts exactly: commands, flags, code, URLs, model IDs, and file paths +- Keep repo locale references as `bs` in code/config, and use `Bosanski` for the user-facing language name when applicable + +## Avoid + +- Avoid changing repo locale references from `bs` to another slug in code snippets or config examples +- Avoid translating product and protocol names that are fixed identifiers diff --git a/.opencode/glossary/da.md b/.opencode/glossary/da.md new file mode 100644 index 0000000000..e632221701 --- /dev/null +++ b/.opencode/glossary/da.md @@ -0,0 +1,27 @@ +# da Glossary + +## Sources + +- PR #9821: https://github.com/anomalyco/opencode/pull/9821 + +## Do Not Translate (Locale Additions) + +- `OpenCode` (preserve casing in prose; keep `opencode` only in commands, package names, paths, or code) +- `OpenCode CLI` +- `CLI`, `TUI`, `MCP`, `OAuth` +- Commands, flags, file paths, and code literals (keep exactly as written) + +## Preferred Terms + +No PR-backed term mappings yet. Add entries here when review PRs introduce repeated wording corrections. + +## Guidance + +- Prefer natural Danish phrasing over literal translation +- Keep tone clear and direct in UI labels and docs prose +- Preserve technical artifacts exactly: commands, flags, code, URLs, model IDs, and file paths + +## Avoid + +- Avoid translating product and protocol names that are fixed identifiers +- Avoid mixing multiple Danish terms for the same recurring UI action once a preferred term is established diff --git a/.opencode/glossary/de.md b/.opencode/glossary/de.md new file mode 100644 index 0000000000..0d2c49face --- /dev/null +++ b/.opencode/glossary/de.md @@ -0,0 +1,27 @@ +# de Glossary + +## Sources + +- PR #9817: https://github.com/anomalyco/opencode/pull/9817 + +## Do Not Translate (Locale Additions) + +- `OpenCode` (preserve casing in prose; keep `opencode` only in commands, package names, paths, or code) +- `OpenCode CLI` +- `CLI`, `TUI`, `MCP`, `OAuth` +- Commands, flags, file paths, and code literals (keep exactly as written) + +## Preferred Terms + +No PR-backed term mappings yet. Add entries here when review PRs introduce repeated wording corrections. + +## Guidance + +- Prefer natural German phrasing over literal translation +- Keep tone clear and direct in UI labels and docs prose +- Preserve technical artifacts exactly: commands, flags, code, URLs, model IDs, and file paths + +## Avoid + +- Avoid translating product and protocol names that are fixed identifiers +- Avoid mixing multiple German terms for the same recurring UI action once a preferred term is established diff --git a/.opencode/glossary/es.md b/.opencode/glossary/es.md new file mode 100644 index 0000000000..dc9b977ecf --- /dev/null +++ b/.opencode/glossary/es.md @@ -0,0 +1,27 @@ +# es Glossary + +## Sources + +- PR #9817: https://github.com/anomalyco/opencode/pull/9817 + +## Do Not Translate (Locale Additions) + +- `OpenCode` (preserve casing in prose; keep `opencode` only in commands, package names, paths, or code) +- `OpenCode CLI` +- `CLI`, `TUI`, `MCP`, `OAuth` +- Commands, flags, file paths, and code literals (keep exactly as written) + +## Preferred Terms + +No PR-backed term mappings yet. Add entries here when review PRs introduce repeated wording corrections. + +## Guidance + +- Prefer natural Spanish phrasing over literal translation +- Keep tone clear and direct in UI labels and docs prose +- Preserve technical artifacts exactly: commands, flags, code, URLs, model IDs, and file paths + +## Avoid + +- Avoid translating product and protocol names that are fixed identifiers +- Avoid mixing multiple Spanish terms for the same recurring UI action once a preferred term is established diff --git a/.opencode/glossary/fr.md b/.opencode/glossary/fr.md new file mode 100644 index 0000000000..074c4de110 --- /dev/null +++ b/.opencode/glossary/fr.md @@ -0,0 +1,27 @@ +# fr Glossary + +## Sources + +- PR #9821: https://github.com/anomalyco/opencode/pull/9821 + +## Do Not Translate (Locale Additions) + +- `OpenCode` (preserve casing in prose; keep `opencode` only in commands, package names, paths, or code) +- `OpenCode CLI` +- `CLI`, `TUI`, `MCP`, `OAuth` +- Commands, flags, file paths, and code literals (keep exactly as written) + +## Preferred Terms + +No PR-backed term mappings yet. Add entries here when review PRs introduce repeated wording corrections. + +## Guidance + +- Prefer natural French phrasing over literal translation +- Keep tone clear and direct in UI labels and docs prose +- Preserve technical artifacts exactly: commands, flags, code, URLs, model IDs, and file paths + +## Avoid + +- Avoid translating product and protocol names that are fixed identifiers +- Avoid mixing multiple French terms for the same recurring UI action once a preferred term is established diff --git a/.opencode/glossary/ja.md b/.opencode/glossary/ja.md new file mode 100644 index 0000000000..f0159ca966 --- /dev/null +++ b/.opencode/glossary/ja.md @@ -0,0 +1,33 @@ +# ja Glossary + +## Sources + +- PR #9821: https://github.com/anomalyco/opencode/pull/9821 +- PR #13160: https://github.com/anomalyco/opencode/pull/13160 + +## Do Not Translate (Locale Additions) + +- `OpenCode` (preserve casing in prose; keep `opencode` only in commands, package names, paths, or code) +- `OpenCode CLI` +- `CLI`, `TUI`, `MCP`, `OAuth` +- Commands, flags, file paths, and code literals (keep exactly as written) + +## Preferred Terms + +These are PR-backed wording preferences and may evolve. + +| English / Context | Preferred | Notes | +| --------------------------- | ----------------------- | ------------------------------------- | +| WSL integration (UI label) | `WSL連携` | PR #13160 prefers this over `WSL統合` | +| WSL integration description | `WindowsのWSL環境で...` | PR #13160 improved phrasing naturally | + +## Guidance + +- Prefer natural Japanese phrasing over literal translation +- Preserve technical artifacts exactly: commands, flags, code, URLs, model IDs, and file paths +- In WSL integration text, follow PR #13160 wording direction for more natural Japanese phrasing + +## Avoid + +- Avoid `WSL統合` in the WSL integration UI context where `WSL連携` is the reviewed wording +- Avoid translating product and protocol names that are fixed identifiers diff --git a/.opencode/glossary/ko.md b/.opencode/glossary/ko.md new file mode 100644 index 0000000000..71385c8a10 --- /dev/null +++ b/.opencode/glossary/ko.md @@ -0,0 +1,27 @@ +# ko Glossary + +## Sources + +- PR #9817: https://github.com/anomalyco/opencode/pull/9817 + +## Do Not Translate (Locale Additions) + +- `OpenCode` (preserve casing in prose; keep `opencode` only in commands, package names, paths, or code) +- `OpenCode CLI` +- `CLI`, `TUI`, `MCP`, `OAuth` +- Commands, flags, file paths, and code literals (keep exactly as written) + +## Preferred Terms + +No PR-backed term mappings yet. Add entries here when review PRs introduce repeated wording corrections. + +## Guidance + +- Prefer natural Korean phrasing over literal translation +- Keep tone clear and direct in UI labels and docs prose +- Preserve technical artifacts exactly: commands, flags, code, URLs, model IDs, and file paths + +## Avoid + +- Avoid translating product and protocol names that are fixed identifiers +- Avoid mixing multiple Korean terms for the same recurring UI action once a preferred term is established diff --git a/.opencode/glossary/no.md b/.opencode/glossary/no.md new file mode 100644 index 0000000000..d7159dca41 --- /dev/null +++ b/.opencode/glossary/no.md @@ -0,0 +1,38 @@ +# no Glossary + +## Sources + +- PR #10018: https://github.com/anomalyco/opencode/pull/10018 +- PR #12935: https://github.com/anomalyco/opencode/pull/12935 + +## Do Not Translate (Locale Additions) + +- `OpenCode` (preserve casing in prose; keep `opencode` only in commands, package names, paths, or code) +- `OpenCode CLI` +- `CLI`, `TUI`, `MCP`, `OAuth` +- Sound names (PR #10018 notes these were intentionally left untranslated) + +## Preferred Terms + +These are PR-backed corrections and may evolve. + +| English / Context | Preferred | Notes | +| ----------------------------------- | ------------ | ----------------------------- | +| Save (data persistence action) | `Lagre` | Prefer over `Spare` | +| Disabled (feature/state) | `deaktivert` | Prefer over `funksjonshemmet` | +| API keys | `API Nøkler` | Prefer over `API Taster` | +| Cost (noun) | `Kostnad` | Prefer over verb form `Koste` | +| Show/View (imperative button label) | `Vis` | Prefer over `Utsikt` | + +## Guidance + +- Prefer natural Norwegian Bokmal (Bokmål) wording over literal translation +- Keep tone clear and practical in UI labels +- Preserve technical artifacts exactly: commands, flags, code, URLs, model IDs, and file paths +- Keep recurring UI terms consistent once a preferred term is chosen + +## Avoid + +- Avoid `Spare` for save actions in persistence contexts +- Avoid `funksjonshemmet` for disabled feature states +- Avoid `API Taster`, `Koste`, and `Utsikt` in the corrected contexts above diff --git a/.opencode/glossary/pl.md b/.opencode/glossary/pl.md new file mode 100644 index 0000000000..e9bad7a515 --- /dev/null +++ b/.opencode/glossary/pl.md @@ -0,0 +1,27 @@ +# pl Glossary + +## Sources + +- PR #9884: https://github.com/anomalyco/opencode/pull/9884 + +## Do Not Translate (Locale Additions) + +- `OpenCode` (preserve casing in prose; keep `opencode` only in commands, package names, paths, or code) +- `OpenCode CLI` +- `CLI`, `TUI`, `MCP`, `OAuth` +- Commands, flags, file paths, and code literals (keep exactly as written) + +## Preferred Terms + +No PR-backed term mappings yet. Add entries here when review PRs introduce repeated wording corrections. + +## Guidance + +- Prefer natural Polish phrasing over literal translation +- Keep tone clear and direct in UI labels and docs prose +- Preserve technical artifacts exactly: commands, flags, code, URLs, model IDs, and file paths + +## Avoid + +- Avoid translating product and protocol names that are fixed identifiers +- Avoid mixing multiple Polish terms for the same recurring UI action once a preferred term is established diff --git a/.opencode/glossary/ru.md b/.opencode/glossary/ru.md new file mode 100644 index 0000000000..6fee0f94c0 --- /dev/null +++ b/.opencode/glossary/ru.md @@ -0,0 +1,27 @@ +# ru Glossary + +## Sources + +- PR #9882: https://github.com/anomalyco/opencode/pull/9882 + +## Do Not Translate (Locale Additions) + +- `OpenCode` (preserve casing in prose; keep `opencode` only in commands, package names, paths, or code) +- `OpenCode CLI` +- `CLI`, `TUI`, `MCP`, `OAuth` +- Commands, flags, file paths, and code literals (keep exactly as written) + +## Preferred Terms + +No PR-backed term mappings yet. Add entries here when review PRs introduce repeated wording corrections. + +## Guidance + +- Prefer natural Russian phrasing over literal translation +- Keep tone clear and direct in UI labels and docs prose +- Preserve technical artifacts exactly: commands, flags, code, URLs, model IDs, and file paths + +## Avoid + +- Avoid translating product and protocol names that are fixed identifiers +- Avoid mixing multiple Russian terms for the same recurring UI action once a preferred term is established diff --git a/.opencode/glossary/th.md b/.opencode/glossary/th.md new file mode 100644 index 0000000000..7b5a31d16b --- /dev/null +++ b/.opencode/glossary/th.md @@ -0,0 +1,34 @@ +# th Glossary + +## Sources + +- PR #10809: https://github.com/anomalyco/opencode/pull/10809 +- PR #11496: https://github.com/anomalyco/opencode/pull/11496 + +## Do Not Translate (Locale Additions) + +- `OpenCode` (preserve casing in prose; keep `opencode` only in commands, package names, paths, or code) +- `OpenCode CLI` +- `CLI`, `TUI`, `MCP`, `OAuth` +- Commands, flags, file paths, and code literals (keep exactly as written) + +## Preferred Terms + +These are PR-backed preferences and may evolve. + +| English / Context | Preferred | Notes | +| ------------------------------------- | --------------------- | -------------------------------------------------------------------------------- | +| Thai language label in language lists | `ไทย` | PR #10809 standardized this across locales | +| Language names in language pickers | Native names (static) | PR #11496: keep names like `English`, `Deutsch`, `ไทย` consistent across locales | + +## Guidance + +- Prefer natural Thai phrasing over literal translation +- Keep tone short and clear for buttons and labels +- Preserve technical artifacts exactly: commands, flags, code, URLs, model IDs, and file paths +- Keep language names static/native in language pickers instead of translating them per current locale (PR #11496) + +## Avoid + +- Avoid translating language names differently per current locale in language lists +- Avoid changing `ไทย` to another display form for the Thai language option unless the product standard changes diff --git a/.opencode/glossary/tr.md b/.opencode/glossary/tr.md new file mode 100644 index 0000000000..72b1cdfb40 --- /dev/null +++ b/.opencode/glossary/tr.md @@ -0,0 +1,38 @@ +# tr Glossary + +## Sources + +- PR #15835: https://github.com/anomalyco/opencode/pull/15835 + +## Do Not Translate (Locale Additions) + +- `OpenCode` (preserve casing in prose, docs, and UI copy) +- Keep lowercase `opencode` in commands, package names, paths, URLs, and other exact identifiers +- `` stays the literal key token in code blocks; use `Tab` for the nearby explanatory label in prose +- Commands, flags, file paths, and code literals (keep exactly as written) + +## Preferred Terms + +These are PR-backed wording preferences and may evolve. + +| English / Context | Preferred | Notes | +| ------------------------- | --------------------------------------- | ------------------------------------------------------------- | +| available in beta | `beta olarak mevcut` | Prefer this over `beta olarak kullanılabilir` | +| privacy-first | `Gizlilik öncelikli tasarlandı` | Prefer this over `Önce gizlilik için tasarlandı` | +| connect your local models | `yerel modellerinizi bağlayabilirsiniz` | Use the fuller, more direct action phrase | +| `` key label | `Tab` | Use `Tab` in prose; keep `` in literal UI or code blocks | +| cross-platform | `cross-platform (tüm platformlarda)` | Keep the English term, add a short clarification when helpful | + +## Guidance + +- Prefer natural Turkish phrasing over literal translation +- Merge broken sentence fragments into one clear sentence when the source is a single thought +- Keep product naming consistent: `OpenCode` in prose, `opencode` only for exact technical identifiers +- When an English technical term is intentionally kept, add a short Turkish clarification only if it improves readability + +## Avoid + +- Avoid `beta olarak kullanılabilir` when `beta olarak mevcut` fits +- Avoid `Önce gizlilik için tasarlandı`; use the more natural reviewed wording instead +- Avoid `Sekme` for the translated key label in prose when referring to `` +- Avoid changing `opencode` to `OpenCode` inside commands, URLs, package names, or code literals diff --git a/.opencode/glossary/zh-cn.md b/.opencode/glossary/zh-cn.md new file mode 100644 index 0000000000..054e94b7e8 --- /dev/null +++ b/.opencode/glossary/zh-cn.md @@ -0,0 +1,42 @@ +# zh-cn Glossary + +## Sources + +- PR #13942: https://github.com/anomalyco/opencode/pull/13942 + +## Do Not Translate (Locale Additions) + +- `OpenCode` (preserve casing in prose; keep `opencode` only when it is part of commands, package names, paths, or code) +- `OpenCode Zen` +- `OpenCode CLI` +- `CLI`, `TUI`, `MCP`, `OAuth` +- `Model Context Protocol` (prefer the English expansion when introducing `MCP`) + +## Preferred Terms + +These are preferred terms for docs/UI prose and may evolve. + +| English | Preferred | Notes | +| ----------------------- | --------- | ------------------------------------------- | +| prompt | 提示词 | Keep `--prompt` unchanged in flags/code | +| session | 会话 | | +| provider | 提供商 | | +| share link / shared URL | 分享链接 | Prefer `分享` for user-facing share actions | +| headless (server) | 无界面 | Docs wording | +| authentication | 认证 | Prefer in auth/OAuth contexts | +| cache | 缓存 | | +| keybind / shortcut | 快捷键 | User-facing docs wording | +| workflow | 工作流 | e.g. GitHub Actions workflow | + +## Guidance + +- Prefer natural, concise phrasing over literal translation +- Keep the tone direct and friendly (PR #13942 consistently moved wording in this direction) +- Preserve technical artifacts exactly: commands, flags, code, inline code, URLs, file paths, model IDs +- Keep enum-like values in English when they are literals (for example, `default`, `json`) +- Prefer consistent terminology across pages once a term is chosen (`会话`, `提供商`, `提示词`, etc.) + +## Avoid + +- Avoid `opencode` in prose when referring to the product name; use `OpenCode` +- Avoid mixing alternative terms for the same concept across docs when a preferred term is already established diff --git a/.opencode/glossary/zh-tw.md b/.opencode/glossary/zh-tw.md new file mode 100644 index 0000000000..283660e121 --- /dev/null +++ b/.opencode/glossary/zh-tw.md @@ -0,0 +1,42 @@ +# zh-tw Glossary + +## Sources + +- PR #13942: https://github.com/anomalyco/opencode/pull/13942 + +## Do Not Translate (Locale Additions) + +- `OpenCode` (preserve casing in prose; keep `opencode` only when it is part of commands, package names, paths, or code) +- `OpenCode Zen` +- `OpenCode CLI` +- `CLI`, `TUI`, `MCP`, `OAuth` +- `Model Context Protocol` (prefer the English expansion when introducing `MCP`) + +## Preferred Terms + +These are preferred terms for docs/UI prose and may evolve. + +| English | Preferred | Notes | +| ----------------------- | --------- | ------------------------------------------- | +| prompt | 提示詞 | Keep `--prompt` unchanged in flags/code | +| session | 工作階段 | | +| provider | 供應商 | | +| share link / shared URL | 分享連結 | Prefer `分享` for user-facing share actions | +| headless (server) | 無介面 | Docs wording | +| authentication | 認證 | Prefer in auth/OAuth contexts | +| cache | 快取 | | +| keybind / shortcut | 快捷鍵 | User-facing docs wording | +| workflow | 工作流程 | e.g. GitHub Actions workflow | + +## Guidance + +- Prefer natural, concise phrasing over literal translation +- Keep the tone direct and friendly (PR #13942 consistently moved wording in this direction) +- Preserve technical artifacts exactly: commands, flags, code, inline code, URLs, file paths, model IDs +- Keep enum-like values in English when they are literals (for example, `default`, `json`) +- Prefer consistent terminology across pages once a term is chosen (`工作階段`, `供應商`, `提示詞`, etc.) + +## Avoid + +- Avoid `opencode` in prose when referring to the product name; use `OpenCode` +- Avoid mixing alternative terms for the same concept across docs when a preferred term is already established diff --git a/.opencode/opencode.jsonc b/.opencode/opencode.jsonc index 3497847a67..8380f7f719 100644 --- a/.opencode/opencode.jsonc +++ b/.opencode/opencode.jsonc @@ -5,6 +5,11 @@ "options": {}, }, }, + "permission": { + "edit": { + "packages/opencode/migration/*": "deny", + }, + }, "mcp": {}, "tools": { "github-triage": false, diff --git a/.opencode/tool/github-pr-search.txt b/.opencode/tool/github-pr-search.txt index 28d8643f13..1b658e71c4 100644 --- a/.opencode/tool/github-pr-search.txt +++ b/.opencode/tool/github-pr-search.txt @@ -1,6 +1,6 @@ Use this tool to search GitHub pull requests by title and description. -This tool searches PRs in the sst/opencode repository and returns LLM-friendly results including: +This tool searches PRs in the anomalyco/opencode repository and returns LLM-friendly results including: - PR number and title - Author - State (open/closed/merged) diff --git a/AGENTS.md b/AGENTS.md index 758714d10a..2158d73af1 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -20,6 +20,17 @@ Prefer single word names for variables and functions. Only use multiple words if necessary. +### Naming Enforcement (Read This) + +THIS RULE IS MANDATORY FOR AGENT WRITTEN CODE. + +- Use single word names by default for new locals, params, and helper functions. +- Multi-word names are allowed only when a single word would be unclear or ambiguous. +- Do not introduce new camelCase compounds when a short single-word alternative is clear. +- Before finishing edits, review touched lines and shorten newly introduced identifiers where possible. +- Good short names to prefer: `pid`, `cfg`, `err`, `opts`, `dir`, `root`, `child`, `state`, `timeout`. +- Examples to avoid unless truly required: `inputPID`, `existingClient`, `connectTimeout`, `workerPath`. + ```ts // Good const foo = 1 diff --git a/README.ar.md b/README.ar.md index f24e598d5e..beb44589e6 100644 --- a/README.ar.md +++ b/README.ar.md @@ -27,12 +27,16 @@ 日本語 | Polski | Русский | + Bosanski | العربية | Norsk | Português (Brasil) | ไทย | Türkçe | - Українська + Українська | + বাংলা | + Ελληνικά | + Tiếng Việt

[![OpenCode Terminal UI](packages/web/src/assets/lander/screenshot.png)](https://opencode.ai) diff --git a/README.bn.md b/README.bn.md new file mode 100644 index 0000000000..c7abc7346a --- /dev/null +++ b/README.bn.md @@ -0,0 +1,141 @@ +

+ + + + + OpenCode logo + + +

+

ওপেন সোর্স এআই কোডিং এজেন্ট।

+

+ Discord + npm + Build status +

+ +

+ English | + 简体中文 | + 繁體中文 | + 한국어 | + Deutsch | + Español | + Français | + Italiano | + Dansk | + 日本語 | + Polski | + Русский | + Bosanski | + العربية | + Norsk | + Português (Brasil) | + ไทย | + Türkçe | + Українська | + বাংলা | + Ελληνικά | + Tiếng Việt +

+ +[![OpenCode Terminal UI](packages/web/src/assets/lander/screenshot.png)](https://opencode.ai) + +--- + +### ইনস্টলেশন (Installation) + +```bash +# YOLO +curl -fsSL https://opencode.ai/install | bash + +# Package managers +npm i -g opencode-ai@latest # or bun/pnpm/yarn +scoop install opencode # Windows +choco install opencode # Windows +brew install anomalyco/tap/opencode # macOS and Linux (recommended, always up to date) +brew install opencode # macOS and Linux (official brew formula, updated less) +sudo pacman -S opencode # Arch Linux (Stable) +paru -S opencode-bin # Arch Linux (Latest from AUR) +mise use -g opencode # Any OS +nix run nixpkgs#opencode # or github:anomalyco/opencode for latest dev branch +``` + +> [!TIP] +> ইনস্টল করার আগে ০.১.x এর চেয়ে পুরোনো ভার্সনগুলো মুছে ফেলুন। + +### ডেস্কটপ অ্যাপ (BETA) + +OpenCode ডেস্কটপ অ্যাপ্লিকেশন হিসেবেও উপলব্ধ। সরাসরি [রিলিজ পেজ](https://github.com/anomalyco/opencode/releases) অথবা [opencode.ai/download](https://opencode.ai/download) থেকে ডাউনলোড করুন। + +| প্ল্যাটফর্ম | ডাউনলোড | +| --------------------- | ------------------------------------- | +| macOS (Apple Silicon) | `opencode-desktop-darwin-aarch64.dmg` | +| macOS (Intel) | `opencode-desktop-darwin-x64.dmg` | +| Windows | `opencode-desktop-windows-x64.exe` | +| Linux | `.deb`, `.rpm`, or AppImage | + +```bash +# macOS (Homebrew) +brew install --cask opencode-desktop +# Windows (Scoop) +scoop bucket add extras; scoop install extras/opencode-desktop +``` + +#### ইনস্টলেশন ডিরেক্টরি (Installation Directory) + +ইনস্টল স্ক্রিপ্টটি ইনস্টলেশন পাতের জন্য নিম্নলিখিত অগ্রাধিকার ক্রম মেনে চলে: + +1. `$OPENCODE_INSTALL_DIR` - কাস্টম ইনস্টলেশন ডিরেক্টরি +2. `$XDG_BIN_DIR` - XDG বেস ডিরেক্টরি স্পেসিফিকেশন সমর্থিত পাথ +3. `$HOME/bin` - সাধারণ ব্যবহারকারী বাইনারি ডিরেক্টরি (যদি বিদ্যমান থাকে বা তৈরি করা যায়) +4. `$HOME/.opencode/bin` - ডিফল্ট ফলব্যাক + +```bash +# উদাহরণ +OPENCODE_INSTALL_DIR=/usr/local/bin curl -fsSL https://opencode.ai/install | bash +XDG_BIN_DIR=$HOME/.local/bin curl -fsSL https://opencode.ai/install | bash +``` + +### এজেন্টস (Agents) + +OpenCode এ দুটি বিল্ট-ইন এজেন্ট রয়েছে যা আপনি `Tab` কি(key) দিয়ে পরিবর্তন করতে পারবেন। + +- **build** - ডিফল্ট, ডেভেলপমেন্টের কাজের জন্য সম্পূর্ণ অ্যাক্সেসযুক্ত এজেন্ট +- **plan** - বিশ্লেষণ এবং কোড এক্সপ্লোরেশনের জন্য রিড-ওনলি এজেন্ট + - ডিফল্টভাবে ফাইল এডিট করতে দেয় না + - ব্যাশ কমান্ড চালানোর আগে অনুমতি চায় + - অপরিচিত কোডবেস এক্সপ্লোর করা বা পরিবর্তনের পরিকল্পনা করার জন্য আদর্শ + +এছাড়াও জটিল অনুসন্ধান এবং মাল্টিস্টেপ টাস্কের জন্য একটি **general** সাবএজেন্ট অন্তর্ভুক্ত রয়েছে। +এটি অভ্যন্তরীণভাবে ব্যবহৃত হয় এবং মেসেজে `@general` লিখে ব্যবহার করা যেতে পারে। + +এজেন্টদের সম্পর্কে আরও জানুন: [docs](https://opencode.ai/docs/agents)। + +### ডকুমেন্টেশন (Documentation) + +কিভাবে OpenCode কনফিগার করবেন সে সম্পর্কে আরও তথ্যের জন্য, [**আমাদের ডকস দেখুন**](https://opencode.ai/docs)। + +### অবদান (Contributing) + +আপনি যদি OpenCode এ অবদান রাখতে চান, অনুগ্রহ করে একটি পুল রিকোয়েস্ট সাবমিট করার আগে আমাদের [কন্ট্রিবিউটিং ডকস](./CONTRIBUTING.md) পড়ে নিন। + +### OpenCode এর উপর বিল্ডিং (Building on OpenCode) + +আপনি যদি এমন প্রজেক্টে কাজ করেন যা OpenCode এর সাথে সম্পর্কিত এবং প্রজেক্টের নামের অংশ হিসেবে "opencode" ব্যবহার করেন, উদাহরণস্বরূপ "opencode-dashboard" বা "opencode-mobile", তবে দয়া করে আপনার README তে একটি নোট যোগ করে স্পষ্ট করুন যে এই প্রজেক্টটি OpenCode দল দ্বারা তৈরি হয়নি এবং আমাদের সাথে এর কোনো সরাসরি সম্পর্ক নেই। + +### সচরাচর জিজ্ঞাসিত প্রশ্নাবলী (FAQ) + +#### এটি ক্লড কোড (Claude Code) থেকে কীভাবে আলাদা? + +ক্যাপাবিলিটির দিক থেকে এটি ক্লড কোডের (Claude Code) মতই। এখানে মূল পার্থক্যগুলো দেওয়া হলো: + +- ১০০% ওপেন সোর্স +- কোনো প্রোভাইডারের সাথে আবদ্ধ নয়। যদিও আমরা [OpenCode Zen](https://opencode.ai/zen) এর মাধ্যমে মডেলসমূহ ব্যবহারের পরামর্শ দিই, OpenCode ক্লড (Claude), ওপেনএআই (OpenAI), গুগল (Google), অথবা লোকাল মডেলগুলোর সাথেও ব্যবহার করা যেতে পারে। যেমন যেমন মডেলগুলো উন্নত হবে, তাদের মধ্যকার পার্থক্য কমে আসবে এবং দামও কমবে, তাই প্রোভাইডার-অজ্ঞাস্টিক হওয়া খুবই গুরুত্বপূর্ণ। +- আউট-অফ-দ্য-বক্স LSP সাপোর্ট +- TUI এর উপর ফোকাস। OpenCode নিওভিম (neovim) ব্যবহারকারী এবং [terminal.shop](https://terminal.shop) এর নির্মাতাদের দ্বারা তৈরি; আমরা টার্মিনালে কী কী সম্ভব তার সীমাবদ্ধতা ছাড়িয়ে যাওয়ার চেষ্টা করছি। +- ক্লায়েন্ট/সার্ভার আর্কিটেকচার। এটি যেমন OpenCode কে আপনার কম্পিউটারে চালানোর সুযোগ দেয়, তেমনি আপনি মোবাইল অ্যাপ থেকে রিমোটলি এটি নিয়ন্ত্রণ করতে পারবেন, অর্থাৎ TUI ফ্রন্টএন্ড কেবল সম্ভাব্য ক্লায়েন্টগুলোর মধ্যে একটি। + +--- + +**আমাদের কমিউনিটিতে যুক্ত হোন** [Discord](https://discord.gg/opencode) | [X.com](https://x.com/opencode) diff --git a/README.br.md b/README.br.md index 4802c4996f..6d1de21562 100644 --- a/README.br.md +++ b/README.br.md @@ -27,12 +27,16 @@ 日本語 | Polski | Русский | + Bosanski | العربية | Norsk | Português (Brasil) | ไทย | Türkçe | - Українська + Українська | + বাংলা | + Ελληνικά | + Tiếng Việt

[![OpenCode Terminal UI](packages/web/src/assets/lander/screenshot.png)](https://opencode.ai) diff --git a/README.bs.md b/README.bs.md index 9ad6852018..2cff8e0279 100644 --- a/README.bs.md +++ b/README.bs.md @@ -33,7 +33,10 @@ Português (Brasil) | ไทย | Türkçe | - Українська + Українська | + বাংলা | + Ελληνικά | + Tiếng Việt

[![OpenCode Terminal UI](packages/web/src/assets/lander/screenshot.png)](https://opencode.ai) diff --git a/README.da.md b/README.da.md index 4b1302dbc3..ac522f29c4 100644 --- a/README.da.md +++ b/README.da.md @@ -27,12 +27,16 @@ 日本語 | Polski | Русский | + Bosanski | العربية | Norsk | Português (Brasil) | ไทย | Türkçe | - Українська + Українська | + বাংলা | + Ελληνικά | + Tiếng Việt

[![OpenCode Terminal UI](packages/web/src/assets/lander/screenshot.png)](https://opencode.ai) diff --git a/README.de.md b/README.de.md index 16116dc72f..87a670f3fc 100644 --- a/README.de.md +++ b/README.de.md @@ -27,12 +27,16 @@ 日本語 | Polski | Русский | + Bosanski | العربية | Norsk | Português (Brasil) | ไทย | Türkçe | - Українська + Українська | + বাংলা | + Ελληνικά | + Tiếng Việt

[![OpenCode Terminal UI](packages/web/src/assets/lander/screenshot.png)](https://opencode.ai) diff --git a/README.es.md b/README.es.md index 5c18ff4aca..9e456af1c0 100644 --- a/README.es.md +++ b/README.es.md @@ -27,12 +27,16 @@ 日本語 | Polski | Русский | + Bosanski | العربية | Norsk | Português (Brasil) | ไทย | Türkçe | - Українська + Українська | + বাংলা | + Ελληνικά | + Tiếng Việt

[![OpenCode Terminal UI](packages/web/src/assets/lander/screenshot.png)](https://opencode.ai) diff --git a/README.fr.md b/README.fr.md index 0382164bed..c1fca23376 100644 --- a/README.fr.md +++ b/README.fr.md @@ -27,12 +27,16 @@ 日本語 | Polski | Русский | + Bosanski | العربية | Norsk | Português (Brasil) | ไทย | Türkçe | - Українська + Українська | + বাংলা | + Ελληνικά | + Tiếng Việt

[![OpenCode Terminal UI](packages/web/src/assets/lander/screenshot.png)](https://opencode.ai) diff --git a/README.gr.md b/README.gr.md new file mode 100644 index 0000000000..2b2c2679d8 --- /dev/null +++ b/README.gr.md @@ -0,0 +1,141 @@ +

+ + + + + OpenCode logo + + +

+

Ο πράκτορας τεχνητής νοημοσύνης ανοικτού κώδικα για προγραμματισμό.

+

+ Discord + npm + Build status +

+ +

+ English | + 简体中文 | + 繁體中文 | + 한국어 | + Deutsch | + Español | + Français | + Italiano | + Dansk | + 日本語 | + Polski | + Русский | + Bosanski | + العربية | + Norsk | + Português (Brasil) | + ไทย | + Türkçe | + Українська | + বাংলা | + Ελληνικά | + Tiếng Việt +

+ +[![OpenCode Terminal UI](packages/web/src/assets/lander/screenshot.png)](https://opencode.ai) + +--- + +### Εγκατάσταση + +```bash +# YOLO +curl -fsSL https://opencode.ai/install | bash + +# Διαχειριστές πακέτων +npm i -g opencode-ai@latest # ή bun/pnpm/yarn +scoop install opencode # Windows +choco install opencode # Windows +brew install anomalyco/tap/opencode # macOS και Linux (προτείνεται, πάντα ενημερωμένο) +brew install opencode # macOS και Linux (επίσημος τύπος brew, λιγότερο συχνές ενημερώσεις) +sudo pacman -S opencode # Arch Linux (Σταθερό) +paru -S opencode-bin # Arch Linux (Τελευταία έκδοση από AUR) +mise use -g opencode # Οποιοδήποτε λειτουργικό σύστημα +nix run nixpkgs#opencode # ή github:anomalyco/opencode με βάση την πιο πρόσφατη αλλαγή από το dev branch +``` + +> [!TIP] +> Αφαίρεσε παλαιότερες εκδόσεις από τη 0.1.x πριν από την εγκατάσταση. + +### Εφαρμογή Desktop (BETA) + +Το OpenCode είναι επίσης διαθέσιμο ως εφαρμογή. Κατέβασε το απευθείας από τη [σελίδα εκδόσεων](https://github.com/anomalyco/opencode/releases) ή το [opencode.ai/download](https://opencode.ai/download). + +| Πλατφόρμα | Λήψη | +| --------------------- | ------------------------------------- | +| macOS (Apple Silicon) | `opencode-desktop-darwin-aarch64.dmg` | +| macOS (Intel) | `opencode-desktop-darwin-x64.dmg` | +| Windows | `opencode-desktop-windows-x64.exe` | +| Linux | `.deb`, `.rpm`, ή AppImage | + +```bash +# macOS (Homebrew) +brew install --cask opencode-desktop +# Windows (Scoop) +scoop bucket add extras; scoop install extras/opencode-desktop +``` + +#### Κατάλογος Εγκατάστασης + +Το script εγκατάστασης τηρεί την ακόλουθη σειρά προτεραιότητας για τη διαδρομή εγκατάστασης: + +1. `$OPENCODE_INSTALL_DIR` - Προσαρμοσμένος κατάλογος εγκατάστασης +2. `$XDG_BIN_DIR` - Διαδρομή συμβατή με τις προδιαγραφές XDG Base Directory +3. `$HOME/bin` - Τυπικός κατάλογος εκτελέσιμων αρχείων χρήστη (εάν υπάρχει ή μπορεί να δημιουργηθεί) +4. `$HOME/.opencode/bin` - Προεπιλεγμένη εφεδρική διαδρομή + +```bash +# Παραδείγματα +OPENCODE_INSTALL_DIR=/usr/local/bin curl -fsSL https://opencode.ai/install | bash +XDG_BIN_DIR=$HOME/.local/bin curl -fsSL https://opencode.ai/install | bash +``` + +### Πράκτορες + +Το OpenCode περιλαμβάνει δύο ενσωματωμένους πράκτορες μεταξύ των οποίων μπορείτε να εναλλάσσεστε με το πλήκτρο `Tab`. + +- **build** - Προεπιλεγμένος πράκτορας με πλήρη πρόσβαση για εργασία πάνω σε κώδικα +- **plan** - Πράκτορας μόνο ανάγνωσης για ανάλυση και εξερεύνηση κώδικα + - Αρνείται την επεξεργασία αρχείων από προεπιλογή + - Ζητά άδεια πριν εκτελέσει εντολές bash + - Ιδανικός για εξερεύνηση άγνωστων αρχείων πηγαίου κώδικα ή σχεδιασμό αλλαγών + +Περιλαμβάνεται επίσης ένας **general** υποπράκτορας για σύνθετες αναζητήσεις και πολυβηματικές διεργασίες. +Χρησιμοποιείται εσωτερικά και μπορεί να κληθεί χρησιμοποιώντας `@general` στα μηνύματα. + +Μάθετε περισσότερα για τους [πράκτορες](https://opencode.ai/docs/agents). + +### Οδηγός Χρήσης + +Για περισσότερες πληροφορίες σχετικά με τη ρύθμιση του OpenCode, [**πλοηγήσου στον οδηγό χρήσης μας**](https://opencode.ai/docs). + +### Συνεισφορά + +Εάν ενδιαφέρεσαι να συνεισφέρεις στο OpenCode, διαβάστε τα [οδηγό χρήσης συνεισφοράς](./CONTRIBUTING.md) πριν υποβάλεις ένα pull request. + +### Δημιουργία πάνω στο OpenCode + +Εάν εργάζεσαι σε ένα έργο σχετικό με το OpenCode και χρησιμοποιείτε το "opencode" ως μέρος του ονόματός του, για παράδειγμα "opencode-dashboard" ή "opencode-mobile", πρόσθεσε μια σημείωση στο README σας για να διευκρινίσεις ότι δεν είναι κατασκευασμένο από την ομάδα του OpenCode και δεν έχει καμία σχέση με εμάς. + +### Συχνές Ερωτήσεις + +#### Πώς διαφέρει αυτό από το Claude Code; + +Είναι πολύ παρόμοιο με το Claude Code ως προς τις δυνατότητες. Ακολουθούν οι βασικές διαφορές: + +- 100% ανοιχτού κώδικα +- Δεν είναι συνδεδεμένο με κανέναν πάροχο. Αν και συνιστούμε τα μοντέλα που παρέχουμε μέσω του [OpenCode Zen](https://opencode.ai/zen), το OpenCode μπορεί να χρησιμοποιηθεί με Claude, OpenAI, Google, ή ακόμα και τοπικά μοντέλα. Καθώς τα μοντέλα εξελίσσονται, τα κενά μεταξύ τους θα κλείσουν και οι τιμές θα μειωθούν, οπότε είναι σημαντικό να είσαι ανεξάρτητος από τον πάροχο. +- Out-of-the-box υποστήριξη LSP +- Εστίαση στο TUI. Το OpenCode είναι κατασκευασμένο από χρήστες που χρησιμοποιούν neovim και τους δημιουργούς του [terminal.shop](https://terminal.shop)· θα εξαντλήσουμε τα όρια του τι είναι δυνατό στο terminal. +- Αρχιτεκτονική client/server. Αυτό, για παράδειγμα, μπορεί να επιτρέψει στο OpenCode να τρέχει στον υπολογιστή σου ενώ το χειρίζεσαι εξ αποστάσεως από μια εφαρμογή κινητού, που σημαίνει ότι το TUI frontend είναι μόνο ένας από τους πιθανούς clients. + +--- + +**Γίνε μέλος της κοινότητάς μας** [Discord](https://discord.gg/opencode) | [X.com](https://x.com/opencode) diff --git a/README.it.md b/README.it.md index c966ccec49..3e516a9027 100644 --- a/README.it.md +++ b/README.it.md @@ -27,12 +27,16 @@ 日本語 | Polski | Русский | + Bosanski | العربية | Norsk | Português (Brasil) | ไทย | Türkçe | - Українська + Українська | + বাংলা | + Ελληνικά | + Tiếng Việt

[![OpenCode Terminal UI](packages/web/src/assets/lander/screenshot.png)](https://opencode.ai) diff --git a/README.ja.md b/README.ja.md index 11109e7eb4..144dc7b6f8 100644 --- a/README.ja.md +++ b/README.ja.md @@ -27,12 +27,16 @@ 日本語 | Polski | Русский | + Bosanski | العربية | Norsk | Português (Brasil) | ไทย | Türkçe | - Українська + Українська | + বাংলা | + Ελληνικά | + Tiếng Việt

[![OpenCode Terminal UI](packages/web/src/assets/lander/screenshot.png)](https://opencode.ai) diff --git a/README.ko.md b/README.ko.md index 23fea76b1e..32defc0a5e 100644 --- a/README.ko.md +++ b/README.ko.md @@ -27,12 +27,16 @@ 日本語 | Polski | Русский | + Bosanski | العربية | Norsk | Português (Brasil) | ไทย | Türkçe | - Українська + Українська | + বাংলা | + Ελληνικά | + Tiếng Việt

[![OpenCode Terminal UI](packages/web/src/assets/lander/screenshot.png)](https://opencode.ai) diff --git a/README.md b/README.md index 99b4b2c50f..79ccf8b349 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,10 @@ Português (Brasil) | ไทย | Türkçe | - Українська + Українська | + বাংলা | + Ελληνικά | + Tiếng Việt

[![OpenCode Terminal UI](packages/web/src/assets/lander/screenshot.png)](https://opencode.ai) diff --git a/README.no.md b/README.no.md index 9b9e90dc38..c3348286b2 100644 --- a/README.no.md +++ b/README.no.md @@ -27,12 +27,16 @@ 日本語 | Polski | Русский | + Bosanski | العربية | Norsk | Português (Brasil) | ไทย | Türkçe | - Українська + Українська | + বাংলা | + Ελληνικά | + Tiếng Việt

[![OpenCode Terminal UI](packages/web/src/assets/lander/screenshot.png)](https://opencode.ai) diff --git a/README.pl.md b/README.pl.md index fced98dfc3..4c5a076656 100644 --- a/README.pl.md +++ b/README.pl.md @@ -27,12 +27,16 @@ 日本語 | Polski | Русский | + Bosanski | العربية | Norsk | Português (Brasil) | ไทย | Türkçe | - Українська + Українська | + বাংলা | + Ελληνικά | + Tiếng Việt

[![OpenCode Terminal UI](packages/web/src/assets/lander/screenshot.png)](https://opencode.ai) diff --git a/README.ru.md b/README.ru.md index a7c590c16b..e507be70e6 100644 --- a/README.ru.md +++ b/README.ru.md @@ -27,12 +27,16 @@ 日本語 | Polski | Русский | + Bosanski | العربية | Norsk | Português (Brasil) | ไทย | Türkçe | - Українська + Українська | + বাংলা | + Ελληνικά | + Tiếng Việt

[![OpenCode Terminal UI](packages/web/src/assets/lander/screenshot.png)](https://opencode.ai) diff --git a/README.th.md b/README.th.md index 0999167f23..4a4ea62c95 100644 --- a/README.th.md +++ b/README.th.md @@ -27,12 +27,16 @@ 日本語 | Polski | Русский | + Bosanski | العربية | Norsk | Português (Brasil) | ไทย | Türkçe | - Українська + Українська | + বাংলা | + Ελληνικά | + Tiếng Việt

[![OpenCode Terminal UI](packages/web/src/assets/lander/screenshot.png)](https://opencode.ai) diff --git a/README.tr.md b/README.tr.md index 67f84e4ddb..e88b40f875 100644 --- a/README.tr.md +++ b/README.tr.md @@ -27,12 +27,16 @@ 日本語 | Polski | Русский | + Bosanski | العربية | Norsk | Português (Brasil) | ไทย | Türkçe | - Українська + Українська | + বাংলা | + Ελληνικά | + Tiếng Việt

[![OpenCode Terminal UI](packages/web/src/assets/lander/screenshot.png)](https://opencode.ai) diff --git a/README.uk.md b/README.uk.md index 77e859a45d..a1a0259b6d 100644 --- a/README.uk.md +++ b/README.uk.md @@ -33,7 +33,10 @@ Português (Brasil) | ไทย | Türkçe | - Українська + Українська | + বাংলা | + Ελληνικά | + Tiếng Việt

[![OpenCode Terminal UI](packages/web/src/assets/lander/screenshot.png)](https://opencode.ai) diff --git a/README.vi.md b/README.vi.md new file mode 100644 index 0000000000..0932c50f78 --- /dev/null +++ b/README.vi.md @@ -0,0 +1,141 @@ +

+ + + + + OpenCode logo + + +

+

Trợ lý lập trình AI mã nguồn mở.

+

+ Discord + npm + Build status +

+ +

+ English | + 简体中文 | + 繁體中文 | + 한국어 | + Deutsch | + Español | + Français | + Italiano | + Dansk | + 日本語 | + Polski | + Русский | + Bosanski | + العربية | + Norsk | + Português (Brasil) | + ไทย | + Türkçe | + Українська | + বাংলা | + Ελληνικά | + Tiếng Việt +

+ +[![OpenCode Terminal UI](packages/web/src/assets/lander/screenshot.png)](https://opencode.ai) + +--- + +### Cài đặt + +```bash +# YOLO +curl -fsSL https://opencode.ai/install | bash + +# Các trình quản lý gói (Package managers) +npm i -g opencode-ai@latest # hoặc bun/pnpm/yarn +scoop install opencode # Windows +choco install opencode # Windows +brew install anomalyco/tap/opencode # macOS và Linux (khuyên dùng, luôn cập nhật) +brew install opencode # macOS và Linux (công thức brew chính thức, ít cập nhật hơn) +sudo pacman -S opencode # Arch Linux (Bản ổn định) +paru -S opencode-bin # Arch Linux (Bản mới nhất từ AUR) +mise use -g opencode # Mọi hệ điều hành +nix run nixpkgs#opencode # hoặc github:anomalyco/opencode cho nhánh dev mới nhất +``` + +> [!TIP] +> Hãy xóa các phiên bản cũ hơn 0.1.x trước khi cài đặt. + +### Ứng dụng Desktop (BETA) + +OpenCode cũng có sẵn dưới dạng ứng dụng desktop. Tải trực tiếp từ [trang releases](https://github.com/anomalyco/opencode/releases) hoặc [opencode.ai/download](https://opencode.ai/download). + +| Nền tảng | Tải xuống | +| --------------------- | ------------------------------------- | +| macOS (Apple Silicon) | `opencode-desktop-darwin-aarch64.dmg` | +| macOS (Intel) | `opencode-desktop-darwin-x64.dmg` | +| Windows | `opencode-desktop-windows-x64.exe` | +| Linux | `.deb`, `.rpm`, hoặc AppImage | + +```bash +# macOS (Homebrew) +brew install --cask opencode-desktop +# Windows (Scoop) +scoop bucket add extras; scoop install extras/opencode-desktop +``` + +#### Thư mục cài đặt + +Tập lệnh cài đặt tuân theo thứ tự ưu tiên sau cho đường dẫn cài đặt: + +1. `$OPENCODE_INSTALL_DIR` - Thư mục cài đặt tùy chỉnh +2. `$XDG_BIN_DIR` - Đường dẫn tuân thủ XDG Base Directory Specification +3. `$HOME/bin` - Thư mục nhị phân tiêu chuẩn của người dùng (nếu tồn tại hoặc có thể tạo) +4. `$HOME/.opencode/bin` - Mặc định dự phòng + +```bash +# Ví dụ +OPENCODE_INSTALL_DIR=/usr/local/bin curl -fsSL https://opencode.ai/install | bash +XDG_BIN_DIR=$HOME/.local/bin curl -fsSL https://opencode.ai/install | bash +``` + +### Agents (Đại diện) + +OpenCode bao gồm hai agent được tích hợp sẵn mà bạn có thể chuyển đổi bằng phím `Tab`. + +- **build** - Agent mặc định, có toàn quyền truy cập cho công việc lập trình +- **plan** - Agent chỉ đọc dùng để phân tích và khám phá mã nguồn + - Mặc định từ chối việc chỉnh sửa tệp + - Hỏi quyền trước khi chạy các lệnh bash + - Lý tưởng để khám phá các codebase lạ hoặc lên kế hoạch thay đổi + +Ngoài ra còn có một subagent **general** dùng cho các tìm kiếm phức tạp và tác vụ nhiều bước. +Agent này được sử dụng nội bộ và có thể gọi bằng cách dùng `@general` trong tin nhắn. + +Tìm hiểu thêm về [agents](https://opencode.ai/docs/agents). + +### Tài liệu + +Để biết thêm thông tin về cách cấu hình OpenCode, [**hãy truy cập tài liệu của chúng tôi**](https://opencode.ai/docs). + +### Đóng góp + +Nếu bạn muốn đóng góp cho OpenCode, vui lòng đọc [tài liệu hướng dẫn đóng góp](./CONTRIBUTING.md) trước khi gửi pull request. + +### Xây dựng trên nền tảng OpenCode + +Nếu bạn đang làm việc trên một dự án liên quan đến OpenCode và sử dụng "opencode" như một phần của tên dự án, ví dụ "opencode-dashboard" hoặc "opencode-mobile", vui lòng thêm một ghi chú vào README của bạn để làm rõ rằng dự án đó không được xây dựng bởi đội ngũ OpenCode và không liên kết với chúng tôi dưới bất kỳ hình thức nào. + +### Các câu hỏi thường gặp (FAQ) + +#### OpenCode khác biệt thế nào so với Claude Code? + +Về mặt tính năng, nó rất giống Claude Code. Dưới đây là những điểm khác biệt chính: + +- 100% mã nguồn mở +- Không bị ràng buộc với bất kỳ nhà cung cấp nào. Mặc dù chúng tôi khuyên dùng các mô hình được cung cấp qua [OpenCode Zen](https://opencode.ai/zen), OpenCode có thể được sử dụng với Claude, OpenAI, Google, hoặc thậm chí các mô hình chạy cục bộ. Khi các mô hình phát triển, khoảng cách giữa chúng sẽ thu hẹp lại và giá cả sẽ giảm, vì vậy việc không phụ thuộc vào nhà cung cấp là rất quan trọng. +- Hỗ trợ LSP ngay từ đầu +- Tập trung vào TUI (Giao diện người dùng dòng lệnh). OpenCode được xây dựng bởi những người dùng neovim và đội ngũ tạo ra [terminal.shop](https://terminal.shop); chúng tôi sẽ đẩy giới hạn của những gì có thể làm được trên terminal lên mức tối đa. +- Kiến trúc client/server. Chẳng hạn, điều này cho phép OpenCode chạy trên máy tính của bạn trong khi bạn điều khiển nó từ xa qua một ứng dụng di động, nghĩa là frontend TUI chỉ là một trong những client có thể dùng. + +--- + +**Tham gia cộng đồng của chúng tôi** [Discord](https://discord.gg/opencode) | [X.com](https://x.com/opencode) diff --git a/README.zh.md b/README.zh.md index 113d476b2e..b11d9857c9 100644 --- a/README.zh.md +++ b/README.zh.md @@ -27,12 +27,16 @@ 日本語 | Polski | Русский | + Bosanski | العربية | Norsk | Português (Brasil) | ไทย | Türkçe | - Українська + Українська | + বাংলা | + Ελληνικά | + Tiếng Việt

[![OpenCode Terminal UI](packages/web/src/assets/lander/screenshot.png)](https://opencode.ai) diff --git a/README.zht.md b/README.zht.md index b518104443..573ca85ab4 100644 --- a/README.zht.md +++ b/README.zht.md @@ -27,12 +27,16 @@ 日本語 | Polski | Русский | + Bosanski | العربية | Norsk | Português (Brasil) | ไทย | Türkçe | - Українська + Українська | + বাংলা | + Ελληνικά | + Tiếng Việt

[![OpenCode Terminal UI](packages/web/src/assets/lander/screenshot.png)](https://opencode.ai) diff --git a/bun.lock b/bun.lock index 04da112cf7..4b7097232a 100644 --- a/bun.lock +++ b/bun.lock @@ -15,17 +15,18 @@ "@actions/artifact": "5.0.1", "@tsconfig/bun": "catalog:", "@types/mime-types": "3.0.1", + "@typescript/native-preview": "catalog:", "glob": "13.0.5", "husky": "9.1.7", "prettier": "3.6.2", "semver": "^7.6.0", "sst": "3.18.10", - "turbo": "2.5.6", + "turbo": "2.8.13", }, }, "packages/app": { "name": "@opencode-ai/app", - "version": "1.2.10", + "version": "1.2.24", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -46,7 +47,7 @@ "@thisbeyond/solid-dnd": "0.7.5", "diff": "catalog:", "fuzzysort": "catalog:", - "ghostty-web": "0.4.0", + "ghostty-web": "github:anomalyco/ghostty-web#main", "luxon": "catalog:", "marked": "catalog:", "marked-shiki": "catalog:", @@ -75,7 +76,7 @@ }, "packages/console/app": { "name": "@opencode-ai/console-app", - "version": "1.2.10", + "version": "1.2.24", "dependencies": { "@cloudflare/vite-plugin": "1.15.2", "@ibm/plex": "6.4.1", @@ -109,7 +110,7 @@ }, "packages/console/core": { "name": "@opencode-ai/console-core", - "version": "1.2.10", + "version": "1.2.24", "dependencies": { "@aws-sdk/client-sts": "3.782.0", "@jsx-email/render": "1.1.1", @@ -136,7 +137,7 @@ }, "packages/console/function": { "name": "@opencode-ai/console-function", - "version": "1.2.10", + "version": "1.2.24", "dependencies": { "@ai-sdk/anthropic": "2.0.0", "@ai-sdk/openai": "2.0.2", @@ -160,7 +161,7 @@ }, "packages/console/mail": { "name": "@opencode-ai/console-mail", - "version": "1.2.10", + "version": "1.2.24", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", @@ -184,7 +185,7 @@ }, "packages/desktop": { "name": "@opencode-ai/desktop", - "version": "1.2.10", + "version": "1.2.24", "dependencies": { "@opencode-ai/app": "workspace:*", "@opencode-ai/ui": "workspace:*", @@ -215,9 +216,39 @@ "vite": "catalog:", }, }, + "packages/desktop-electron": { + "name": "@opencode-ai/desktop-electron", + "version": "1.2.24", + "dependencies": { + "@opencode-ai/app": "workspace:*", + "@opencode-ai/ui": "workspace:*", + "@solid-primitives/i18n": "2.2.1", + "@solid-primitives/storage": "catalog:", + "@solidjs/meta": "catalog:", + "@solidjs/router": "0.15.4", + "electron-log": "^5", + "electron-store": "^10", + "electron-updater": "^6", + "electron-window-state": "^5.0.3", + "marked": "^15", + "solid-js": "catalog:", + "tree-kill": "^1.2.2", + }, + "devDependencies": { + "@actions/artifact": "4.0.0", + "@types/bun": "catalog:", + "@types/node": "catalog:", + "@typescript/native-preview": "catalog:", + "electron": "40.4.1", + "electron-builder": "^26", + "electron-vite": "^5", + "typescript": "~5.6.2", + "vite": "catalog:", + }, + }, "packages/enterprise": { "name": "@opencode-ai/enterprise", - "version": "1.2.10", + "version": "1.2.24", "dependencies": { "@opencode-ai/ui": "workspace:*", "@opencode-ai/util": "workspace:*", @@ -246,7 +277,7 @@ }, "packages/function": { "name": "@opencode-ai/function", - "version": "1.2.10", + "version": "1.2.24", "dependencies": { "@octokit/auth-app": "8.0.1", "@octokit/rest": "catalog:", @@ -262,7 +293,7 @@ }, "packages/opencode": { "name": "opencode", - "version": "1.2.10", + "version": "1.2.24", "bin": { "opencode": "./bin/opencode", }, @@ -304,8 +335,8 @@ "@opencode-ai/sdk": "workspace:*", "@opencode-ai/util": "workspace:*", "@openrouter/ai-sdk-provider": "1.5.4", - "@opentui/core": "0.1.79", - "@opentui/solid": "0.1.79", + "@opentui/core": "0.1.86", + "@opentui/solid": "0.1.86", "@parcel/watcher": "2.5.1", "@pierre/diffs": "catalog:", "@solid-primitives/event-bus": "1.1.2", @@ -320,7 +351,7 @@ "clipboardy": "4.0.0", "decimal.js": "10.5.0", "diff": "catalog:", - "drizzle-orm": "1.0.0-beta.12-a5629fb", + "drizzle-orm": "1.0.0-beta.16-ea816b6", "fuzzysort": "3.1.0", "glob": "13.0.5", "google-auth-library": "10.5.0", @@ -335,6 +366,7 @@ "opentui-spinner": "0.0.6", "partial-json": "0.1.7", "remeda": "catalog:", + "semver": "^7.6.3", "solid-js": "catalog:", "strip-ansi": "7.1.2", "tree-sitter-bash": "0.25.0", @@ -342,6 +374,7 @@ "ulid": "catalog:", "vscode-jsonrpc": "8.2.1", "web-tree-sitter": "0.25.10", + "which": "6.0.1", "xdg-basedir": "5.1.0", "yargs": "18.0.0", "zod": "catalog:", @@ -363,11 +396,13 @@ "@types/babel__core": "7.20.5", "@types/bun": "catalog:", "@types/mime-types": "3.0.1", + "@types/semver": "^7.5.8", "@types/turndown": "5.0.5", + "@types/which": "3.0.4", "@types/yargs": "17.0.33", "@typescript/native-preview": "catalog:", - "drizzle-kit": "1.0.0-beta.12-a5629fb", - "drizzle-orm": "1.0.0-beta.12-a5629fb", + "drizzle-kit": "1.0.0-beta.16-ea816b6", + "drizzle-orm": "1.0.0-beta.16-ea816b6", "typescript": "catalog:", "vscode-languageserver-types": "3.17.5", "why-is-node-running": "3.2.2", @@ -376,7 +411,7 @@ }, "packages/plugin": { "name": "@opencode-ai/plugin", - "version": "1.2.10", + "version": "1.2.24", "dependencies": { "@opencode-ai/sdk": "workspace:*", "zod": "catalog:", @@ -390,13 +425,17 @@ }, "packages/script": { "name": "@opencode-ai/script", + "dependencies": { + "semver": "^7.6.3", + }, "devDependencies": { "@types/bun": "catalog:", + "@types/semver": "^7.5.8", }, }, "packages/sdk/js": { "name": "@opencode-ai/sdk", - "version": "1.2.10", + "version": "1.2.24", "devDependencies": { "@hey-api/openapi-ts": "0.90.10", "@tsconfig/node22": "catalog:", @@ -407,7 +446,7 @@ }, "packages/slack": { "name": "@opencode-ai/slack", - "version": "1.2.10", + "version": "1.2.24", "dependencies": { "@opencode-ai/sdk": "workspace:*", "@slack/bolt": "^3.17.1", @@ -418,9 +457,31 @@ "typescript": "catalog:", }, }, + "packages/storybook": { + "name": "@opencode-ai/storybook", + "devDependencies": { + "@opencode-ai/ui": "workspace:*", + "@solidjs/meta": "catalog:", + "@storybook/addon-a11y": "^10.2.13", + "@storybook/addon-docs": "^10.2.13", + "@storybook/addon-links": "^10.2.13", + "@storybook/addon-onboarding": "^10.2.13", + "@storybook/addon-vitest": "^10.2.13", + "@tailwindcss/vite": "catalog:", + "@tsconfig/node22": "catalog:", + "@types/node": "catalog:", + "@types/react": "18.0.25", + "react": "18.2.0", + "solid-js": "catalog:", + "storybook": "^10.2.13", + "storybook-solidjs-vite": "^10.0.9", + "typescript": "catalog:", + "vite": "catalog:", + }, + }, "packages/ui": { "name": "@opencode-ai/ui", - "version": "1.2.10", + "version": "1.2.24", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -431,7 +492,7 @@ "@solid-primitives/media": "2.3.3", "@solid-primitives/resize-observer": "2.1.3", "@solidjs/meta": "catalog:", - "@typescript/native-preview": "catalog:", + "@solidjs/router": "catalog:", "dompurify": "3.3.1", "fuzzysort": "catalog:", "katex": "0.16.27", @@ -440,6 +501,9 @@ "marked-katex-extension": "5.1.6", "marked-shiki": "catalog:", "morphdom": "2.7.8", + "motion": "12.34.5", + "motion-dom": "12.34.3", + "motion-utils": "12.29.2", "remeda": "catalog:", "shiki": "catalog:", "solid-js": "catalog:", @@ -453,6 +517,7 @@ "@types/bun": "catalog:", "@types/katex": "0.16.7", "@types/luxon": "catalog:", + "@typescript/native-preview": "catalog:", "tailwindcss": "catalog:", "typescript": "catalog:", "vite": "catalog:", @@ -462,7 +527,7 @@ }, "packages/util": { "name": "@opencode-ai/util", - "version": "1.2.10", + "version": "1.2.24", "dependencies": { "zod": "catalog:", }, @@ -473,7 +538,7 @@ }, "packages/web": { "name": "@opencode-ai/web", - "version": "1.2.10", + "version": "1.2.24", "dependencies": { "@astrojs/cloudflare": "12.6.3", "@astrojs/markdown-remark": "6.3.1", @@ -506,6 +571,7 @@ }, }, "trustedDependencies": [ + "electron", "esbuild", "web-tree-sitter", "tree-sitter-bash", @@ -524,7 +590,7 @@ "@kobalte/core": "0.13.11", "@octokit/rest": "22.0.0", "@openauthjs/openauth": "0.0.0-20250322224806", - "@pierre/diffs": "1.1.0-beta.13", + "@pierre/diffs": "1.1.0-beta.18", "@playwright/test": "1.51.0", "@solid-primitives/storage": "4.3.3", "@solidjs/meta": "0.29.4", @@ -541,8 +607,8 @@ "ai": "5.0.124", "diff": "8.0.2", "dompurify": "3.3.1", - "drizzle-kit": "1.0.0-beta.12-a5629fb", - "drizzle-orm": "1.0.0-beta.12-a5629fb", + "drizzle-kit": "1.0.0-beta.16-ea816b6", + "drizzle-orm": "1.0.0-beta.16-ea816b6", "fuzzysort": "3.1.0", "hono": "4.10.7", "hono-openapi": "1.1.2", @@ -562,6 +628,8 @@ "zod": "4.1.8", }, "packages": { + "7zip-bin": ["7zip-bin@5.2.0", "", {}, "sha512-ukTPVhqG4jNzMro2qA9HSCSSVJN3aN7tlb+hfqYCt3ER0yWroeA2VR38MNrOHLQ/cVj+DaIMad0kFCtWWowh/A=="], + "@actions/artifact": ["@actions/artifact@5.0.1", "", { "dependencies": { "@actions/core": "^2.0.0", "@actions/github": "^6.0.1", "@actions/http-client": "^3.0.0", "@azure/storage-blob": "^12.29.1", "@octokit/core": "^5.2.1", "@octokit/plugin-request-log": "^1.0.4", "@octokit/plugin-retry": "^3.0.9", "@octokit/request": "^8.4.1", "@octokit/request-error": "^5.1.1", "@protobuf-ts/plugin": "^2.2.3-alpha.1", "archiver": "^7.0.1", "jwt-decode": "^3.1.2", "unzip-stream": "^0.3.1" } }, "sha512-dHJ5rHduhCKUikKTT9eXeWoUvfKia3IjR1sO/VTAV3DVAL4yMTRnl2iO5mcfiBjySHLwPNezwENAVskKYU5ymw=="], "@actions/core": ["@actions/core@1.11.1", "", { "dependencies": { "@actions/exec": "^1.1.1", "@actions/http-client": "^2.0.1" } }, "sha512-hXJCSrkwfA46Vd9Z3q4cpEpHB1rL5NG04+/rbqW9d3+CSvtB1tYe8UTpAlixa1vj0m/ULglfEK2UKxMGxCxv5A=="], @@ -834,6 +902,8 @@ "@babel/plugin-syntax-typescript": ["@babel/plugin-syntax-typescript@7.28.6", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A=="], + "@babel/plugin-transform-arrow-functions": ["@babel/plugin-transform-arrow-functions@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA=="], + "@babel/plugin-transform-modules-commonjs": ["@babel/plugin-transform-modules-commonjs@7.28.6", "", { "dependencies": { "@babel/helper-module-transforms": "^7.28.6", "@babel/helper-plugin-utils": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-jppVbf8IV9iWWwWTQIxJMAJCWBuuKx71475wHwYytrRGQ2CWiDvYlADQno3tcYpS/T2UUWFQp3nVtYfK/YBQrA=="], "@babel/plugin-transform-react-jsx-self": ["@babel/plugin-transform-react-jsx-self@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw=="], @@ -886,12 +956,30 @@ "@ctrl/tinycolor": ["@ctrl/tinycolor@4.2.0", "", {}, "sha512-kzyuwOAQnXJNLS9PSyrk0CWk35nWJW/zl/6KvnTBMFK65gm7U1/Z5BqjxeapjZCIhQcM/DsrEmcbRwDyXyXK4A=="], + "@develar/schema-utils": ["@develar/schema-utils@2.6.5", "", { "dependencies": { "ajv": "^6.12.0", "ajv-keywords": "^3.4.1" } }, "sha512-0cp4PsWQ/9avqTVMCtZ+GirikIA36ikvjtHweU4/j8yLtgObI0+JUPhYFScgwlteveGB1rt3Cm8UhN04XayDig=="], + "@dimforge/rapier2d-simd-compat": ["@dimforge/rapier2d-simd-compat@0.17.3", "", {}, "sha512-bijvwWz6NHsNj5e5i1vtd3dU2pDhthSaTUZSh14DUGGKJfw8eMnlWZsxwHBxB/a3AXVNDjL9abuHw1k9FGR+jg=="], "@dot/log": ["@dot/log@0.1.5", "", { "dependencies": { "chalk": "^4.1.2", "loglevelnext": "^6.0.0", "p-defer": "^3.0.0" } }, "sha512-ECraEVJWv2f2mWK93lYiefUkphStVlKD6yKDzisuoEmxuLKrxO9iGetHK2DoEAkj7sxjE886n0OUVVCUx0YPNg=="], "@drizzle-team/brocli": ["@drizzle-team/brocli@0.11.0", "", {}, "sha512-hD3pekGiPg0WPCCGAZmusBBJsDqGUR66Y452YgQsZOnkdQ7ViEPKuyP4huUGEZQefp8g34RRodXYmJ2TbCH+tg=="], + "@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/fuses": ["@electron/fuses@1.8.0", "", { "dependencies": { "chalk": "^4.1.1", "fs-extra": "^9.0.1", "minimist": "^1.2.5" }, "bin": { "electron-fuses": "dist/bin.js" } }, "sha512-zx0EIq78WlY/lBb1uXlziZmDZI4ubcCXIMJ4uGjXzZW0nS19TjSPeXPAjzzTmKQlJUZm0SbmZhPKP7tuQ1SsEw=="], + + "@electron/get": ["@electron/get@2.0.3", "", { "dependencies": { "debug": "^4.1.1", "env-paths": "^2.2.0", "fs-extra": "^8.1.0", "got": "^11.8.5", "progress": "^2.0.3", "semver": "^6.2.0", "sumchecker": "^3.0.1" }, "optionalDependencies": { "global-agent": "^3.0.0" } }, "sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ=="], + + "@electron/notarize": ["@electron/notarize@2.5.0", "", { "dependencies": { "debug": "^4.1.1", "fs-extra": "^9.0.1", "promise-retry": "^2.0.1" } }, "sha512-jNT8nwH1f9X5GEITXaQ8IF/KdskvIkOFfB2CvwumsveVidzpSc+mvhhTMdAGSYF3O+Nq49lJ7y+ssODRXu06+A=="], + + "@electron/osx-sign": ["@electron/osx-sign@1.3.3", "", { "dependencies": { "compare-version": "^0.1.2", "debug": "^4.3.4", "fs-extra": "^10.0.0", "isbinaryfile": "^4.0.8", "minimist": "^1.2.6", "plist": "^3.0.5" }, "bin": { "electron-osx-flat": "bin/electron-osx-flat.js", "electron-osx-sign": "bin/electron-osx-sign.js" } }, "sha512-KZ8mhXvWv2rIEgMbWZ4y33bDHyUKMXnx4M0sTyPNK/vcB81ImdeY9Ggdqy0SWbMDgmbqyQ+phgejh6V3R2QuSg=="], + + "@electron/rebuild": ["@electron/rebuild@4.0.3", "", { "dependencies": { "@malept/cross-spawn-promise": "^2.0.0", "debug": "^4.1.1", "detect-libc": "^2.0.1", "got": "^11.7.0", "graceful-fs": "^4.2.11", "node-abi": "^4.2.0", "node-api-version": "^0.2.1", "node-gyp": "^11.2.0", "ora": "^5.1.0", "read-binary-file-arch": "^1.0.6", "semver": "^7.3.5", "tar": "^7.5.6", "yargs": "^17.0.1" }, "bin": { "electron-rebuild": "lib/cli.js" } }, "sha512-u9vpTHRMkOYCs/1FLiSVAFZ7FbjsXK+bQuzviJZa+lG7BHZl1nz52/IcGvwa3sk80/fc3llutBkbCq10Vh8WQA=="], + + "@electron/universal": ["@electron/universal@2.0.3", "", { "dependencies": { "@electron/asar": "^3.3.1", "@malept/cross-spawn-promise": "^2.0.0", "debug": "^4.3.1", "dir-compare": "^4.2.0", "fs-extra": "^11.1.1", "minimatch": "^9.0.3", "plist": "^3.1.0" } }, "sha512-Wn9sPYIVFRFl5HmwMJkARCCf7rqK/EurkfQ/rJZ14mHP3iYTjZSIOSVonEAnhWeAXwtw7zOekGRlc6yTtZ0t+g=="], + + "@electron/windows-sign": ["@electron/windows-sign@1.2.2", "", { "dependencies": { "cross-dirname": "^0.1.0", "debug": "^4.3.4", "fs-extra": "^11.1.1", "minimist": "^1.2.8", "postject": "^1.0.0-alpha.6" }, "bin": { "electron-windows-sign": "bin/electron-windows-sign.js" } }, "sha512-dfZeox66AvdPtb2lD8OsIIQh12Tp0GNCRUDfBHIKGpbmopZto2/A8nSpYYLoedPIHpqkeblZ/k8OV0Gy7PYuyQ=="], + "@emmetio/abbreviation": ["@emmetio/abbreviation@2.3.3", "", { "dependencies": { "@emmetio/scanner": "^1.0.4" } }, "sha512-mgv58UrU3rh4YgbE/TzgLQwJ3pFsHHhCLqY20aJq+9comytTXUDNGG/SMtSeMJdkpxgXSXunBGLD8Boka3JyVA=="], "@emmetio/css-abbreviation": ["@emmetio/css-abbreviation@2.1.8", "", { "dependencies": { "@emmetio/scanner": "^1.0.4" } }, "sha512-s9yjhJ6saOO/uk1V74eifykk2CBYi01STTK3WlXWGOepyKa23ymJ053+DNQjpFcy1ingpaO7AxCcwLvHFY9tuw=="], @@ -1004,6 +1092,8 @@ "@fontsource/inter": ["@fontsource/inter@5.2.8", "", {}, "sha512-P6r5WnJoKiNVV+zvW2xM13gNdFhAEpQ9dQJHt3naLvfg+LkF2ldgSLiF4T41lf1SQCM9QmkqPTn4TH568IRagg=="], + "@gar/promisify": ["@gar/promisify@1.1.3", "", {}, "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw=="], + "@gitlab/gitlab-ai-provider": ["@gitlab/gitlab-ai-provider@3.6.0", "", { "dependencies": { "@anthropic-ai/sdk": "^0.71.0", "@anycable/core": "^0.9.2", "graphql-request": "^6.1.0", "isomorphic-ws": "^5.0.0", "openai": "^6.16.0", "socket.io-client": "^4.8.1", "vscode-jsonrpc": "^8.2.1", "zod": "^3.25.76" }, "peerDependencies": { "@ai-sdk/provider": ">=2.0.0", "@ai-sdk/provider-utils": ">=3.0.0" } }, "sha512-8LmcIQ86xkMtC7L4P1/QYVEC+yKMTRerfPeniaaQGalnzXKtX6iMHLjLPOL9Rxp55lOXi6ed0WrFuJzZx+fNRg=="], "@gitlab/opencode-gitlab-auth": ["@gitlab/opencode-gitlab-auth@1.3.3", "", { "dependencies": { "@fastify/rate-limit": "^10.2.0", "@opencode-ai/plugin": "*", "fastify": "^5.2.0", "open": "^10.0.0" } }, "sha512-FT+KsCmAJjtqWr1YAq0MywGgL9kaLQ4apmsoowAXrPqHtoYf2i/nY10/A+L06kNj22EATeEDRpbB1NWXMto/SA=="], @@ -1136,6 +1226,8 @@ "@jimp/utils": ["@jimp/utils@1.6.0", "", { "dependencies": { "@jimp/types": "1.6.0", "tinycolor2": "^1.6.0" } }, "sha512-gqFTGEosKbOkYF/WFj26jMHOI5OH2jeP1MmC/zbK6BF6VJBf8rIC5898dPfSzZEbSA0wbbV5slbntWVc5PKLFA=="], + "@joshwooding/vite-plugin-react-docgen-typescript": ["@joshwooding/vite-plugin-react-docgen-typescript@0.6.4", "", { "dependencies": { "glob": "^13.0.1", "react-docgen-typescript": "^2.2.2" }, "peerDependencies": { "typescript": ">= 4.3.x", "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" }, "optionalPeers": ["typescript"] }, "sha512-6PyZBYKnnVNqOSB0YFly+62R7dmov8segT27A+RVTBVd4iAE6kbW9QBJGlyR2yG4D4ohzhZSTIu7BK1UTtmFFA=="], + "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="], "@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="], @@ -1206,8 +1298,14 @@ "@lukeed/ms": ["@lukeed/ms@2.0.2", "", {}, "sha512-9I2Zn6+NJLfaGoz9jN3lpwDgAYvfGeNYdbAIjJOqzs4Tpc+VU3Jqq4IofSUBKajiDS8k9fZIg18/z13mpk1bsA=="], + "@malept/cross-spawn-promise": ["@malept/cross-spawn-promise@2.0.0", "", { "dependencies": { "cross-spawn": "^7.0.1" } }, "sha512-1DpKU0Z5ThltBwjNySMC14g0CkbyhCaz9FkhxqNsZI6uAPJXFS8cMXlBKo26FJ8ZuW6S9GCMcR9IO5k2X5/9Fg=="], + + "@malept/flatpak-bundler": ["@malept/flatpak-bundler@0.4.0", "", { "dependencies": { "debug": "^4.1.1", "fs-extra": "^9.0.0", "lodash": "^4.17.15", "tmp-promise": "^3.0.2" } }, "sha512-9QOtNffcOF/c1seMCDnjckb3R9WHcG34tky+FHpNKKCW0wc/scYLwMtO+ptyGUfMW0/b/n4qRiALlaFHc9Oj7Q=="], + "@mdx-js/mdx": ["@mdx-js/mdx@3.1.1", "", { "dependencies": { "@types/estree": "^1.0.0", "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", "@types/mdx": "^2.0.0", "acorn": "^8.0.0", "collapse-white-space": "^2.0.0", "devlop": "^1.0.0", "estree-util-is-identifier-name": "^3.0.0", "estree-util-scope": "^1.0.0", "estree-walker": "^3.0.0", "hast-util-to-jsx-runtime": "^2.0.0", "markdown-extensions": "^2.0.0", "recma-build-jsx": "^1.0.0", "recma-jsx": "^1.0.0", "recma-stringify": "^1.0.0", "rehype-recma": "^1.0.0", "remark-mdx": "^3.0.0", "remark-parse": "^11.0.0", "remark-rehype": "^11.0.0", "source-map": "^0.7.0", "unified": "^11.0.0", "unist-util-position-from-estree": "^2.0.0", "unist-util-stringify-position": "^4.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.0" } }, "sha512-f6ZO2ifpwAQIpzGWaBQT2TXxPv6z3RBzQKpVftEWN78Vl/YweF1uwussDx8ECAXVtr3Rs89fKyG9YlzUs9DyGQ=="], + "@mdx-js/react": ["@mdx-js/react@3.1.1", "", { "dependencies": { "@types/mdx": "^2.0.0" }, "peerDependencies": { "@types/react": ">=16", "react": ">=16" } }, "sha512-f++rKLQgUVYDAtECQ6fn/is15GkEH9+nZPM3MS0RcxVqoTfawHvDlSCH7JbMhAM6uJ32v3eXLvLmLvjGu7PTQw=="], + "@mixmark-io/domino": ["@mixmark-io/domino@2.2.0", "", {}, "sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw=="], "@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.25.2", "", { "dependencies": { "@hono/node-server": "^1.19.7", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.0.1", "express-rate-limit": "^7.5.0", "jose": "^6.1.1", "json-schema-typed": "^8.0.2", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.25 || ^4.0", "zod-to-json-schema": "^3.25.0" }, "peerDependencies": { "@cfworker/json-schema": "^4.1.1" }, "optionalPeers": ["@cfworker/json-schema"] }, "sha512-LZFeo4F9M5qOhC/Uc1aQSrBHxMrvxett+9KLHt7OhcExtoiRN9DKgbZffMP/nxjutWDQpfMDfP3nkHI4X9ijww=="], @@ -1232,6 +1330,12 @@ "@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="], + "@npmcli/agent": ["@npmcli/agent@3.0.0", "", { "dependencies": { "agent-base": "^7.1.0", "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.1", "lru-cache": "^10.0.1", "socks-proxy-agent": "^8.0.3" } }, "sha512-S79NdEgDQd/NGCay6TCoVzXSj74skRZIKJcpJjC5lOq34SZzyI6MqtiiWoiVWoVrTcGjNeC4ipbh1VIHlpfF5Q=="], + + "@npmcli/fs": ["@npmcli/fs@1.1.1", "", { "dependencies": { "@gar/promisify": "^1.0.1", "semver": "^7.3.5" } }, "sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ=="], + + "@npmcli/move-file": ["@npmcli/move-file@1.1.2", "", { "dependencies": { "mkdirp": "^1.0.4", "rimraf": "^3.0.2" } }, "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg=="], + "@octokit/auth-app": ["@octokit/auth-app@8.0.1", "", { "dependencies": { "@octokit/auth-oauth-app": "^9.0.1", "@octokit/auth-oauth-user": "^6.0.0", "@octokit/request": "^10.0.2", "@octokit/request-error": "^7.0.0", "@octokit/types": "^14.0.0", "toad-cache": "^3.7.0", "universal-github-app-jwt": "^2.2.0", "universal-user-agent": "^7.0.0" } }, "sha512-P2J5pB3pjiGwtJX4WqJVYCtNkcZ+j5T2Wm14aJAEIC3WJOrv12jvBley3G1U/XI8q9o1A7QMG54LiFED2BiFlg=="], "@octokit/auth-oauth-app": ["@octokit/auth-oauth-app@9.0.3", "", { "dependencies": { "@octokit/auth-oauth-device": "^8.0.3", "@octokit/auth-oauth-user": "^6.0.2", "@octokit/request": "^10.0.6", "@octokit/types": "^16.0.0", "universal-user-agent": "^7.0.0" } }, "sha512-+yoFQquaF8OxJSxTb7rnytBIC2ZLbLqA/yb71I4ZXT9+Slw4TziV9j/kyGhUFRRTF2+7WlnIWsePZCWHs+OGjg=="], @@ -1290,6 +1394,8 @@ "@opencode-ai/desktop": ["@opencode-ai/desktop@workspace:packages/desktop"], + "@opencode-ai/desktop-electron": ["@opencode-ai/desktop-electron@workspace:packages/desktop-electron"], + "@opencode-ai/enterprise": ["@opencode-ai/enterprise@workspace:packages/enterprise"], "@opencode-ai/function": ["@opencode-ai/function@workspace:packages/function"], @@ -1302,6 +1408,8 @@ "@opencode-ai/slack": ["@opencode-ai/slack@workspace:packages/slack"], + "@opencode-ai/storybook": ["@opencode-ai/storybook@workspace:packages/storybook"], + "@opencode-ai/ui": ["@opencode-ai/ui@workspace:packages/ui"], "@opencode-ai/util": ["@opencode-ai/util@workspace:packages/util"], @@ -1314,21 +1422,21 @@ "@opentelemetry/api": ["@opentelemetry/api@1.9.0", "", {}, "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg=="], - "@opentui/core": ["@opentui/core@0.1.79", "", { "dependencies": { "bun-ffi-structs": "0.1.2", "diff": "8.0.2", "jimp": "1.6.0", "marked": "17.0.1", "yoga-layout": "3.2.1" }, "optionalDependencies": { "@dimforge/rapier2d-simd-compat": "^0.17.3", "@opentui/core-darwin-arm64": "0.1.79", "@opentui/core-darwin-x64": "0.1.79", "@opentui/core-linux-arm64": "0.1.79", "@opentui/core-linux-x64": "0.1.79", "@opentui/core-win32-arm64": "0.1.79", "@opentui/core-win32-x64": "0.1.79", "bun-webgpu": "0.1.4", "planck": "^1.4.2", "three": "0.177.0" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-job/t09w8A/aHb/WuaVbimu5fIffyN+PCuVO5cYhXEg/NkOkC/WdFi80B8bwncR/DBPyLAh6oJ3EG86grOVo5g=="], + "@opentui/core": ["@opentui/core@0.1.86", "", { "dependencies": { "bun-ffi-structs": "0.1.2", "diff": "8.0.2", "jimp": "1.6.0", "marked": "17.0.1", "yoga-layout": "3.2.1" }, "optionalDependencies": { "@dimforge/rapier2d-simd-compat": "^0.17.3", "@opentui/core-darwin-arm64": "0.1.86", "@opentui/core-darwin-x64": "0.1.86", "@opentui/core-linux-arm64": "0.1.86", "@opentui/core-linux-x64": "0.1.86", "@opentui/core-win32-arm64": "0.1.86", "@opentui/core-win32-x64": "0.1.86", "bun-webgpu": "0.1.5", "planck": "^1.4.2", "three": "0.177.0" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-3tRLbI9ADrQE1jEEn4x2aJexEOQZkv9Emk2BixMZqxfVhz2zr2SxtpimDAX0vmZK3+GnWAwBWxuaCAsxZpY4+w=="], - "@opentui/core-darwin-arm64": ["@opentui/core-darwin-arm64@0.1.79", "", { "os": "darwin", "cpu": "arm64" }, "sha512-kgsGniV+DM5G1P3GideyJhvfnthNKcVCAm2mPTIr9InQ3L0gS/Feh7zgwOS/jxDvdlQbOWGKMk2Z3JApeC1MLw=="], + "@opentui/core-darwin-arm64": ["@opentui/core-darwin-arm64@0.1.86", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Zp7q64+d+Dcx6YrH3mRcnHq8EOBnrfc1RvjgSWLhpXr49hY6LzuhqpfZM57aGErPYlR+ff8QM6e5FUkFnDfyjw=="], - "@opentui/core-darwin-x64": ["@opentui/core-darwin-x64@0.1.79", "", { "os": "darwin", "cpu": "x64" }, "sha512-OpyAmFqAAKQ2CeFmf/oLWcNksmP6Ryx/3R5dbKXThOudMCeQvfvInJTRbc2jTn9VFpf+Qj4BgHkJg1h90tf/EA=="], + "@opentui/core-darwin-x64": ["@opentui/core-darwin-x64@0.1.86", "", { "os": "darwin", "cpu": "x64" }, "sha512-NcxfjCJm1kLnTMVOpAPdRYNi8W8XdAXNa6N7i9khiVFrl2v5KRQfUjbrSOUYVxFJNc3jKFG6rsn3jEApvn92qA=="], - "@opentui/core-linux-arm64": ["@opentui/core-linux-arm64@0.1.79", "", { "os": "linux", "cpu": "arm64" }, "sha512-DCa5YaknS4bWhFt8TMEGH+qmTinyzuY8hoZbO4crtWXAxofPP7Pas76Cwxlvis/PyLffA+pPxAl1l5sUZpsvqw=="], + "@opentui/core-linux-arm64": ["@opentui/core-linux-arm64@0.1.86", "", { "os": "linux", "cpu": "arm64" }, "sha512-EDHAvqSOr8CXzbDvo1aE5blJ6wu1aSbR2LqoXtoeXHemr2T2W42D2TdIWewG6K+/BuRbzZnqt9wnYFBksLW6lw=="], - "@opentui/core-linux-x64": ["@opentui/core-linux-x64@0.1.79", "", { "os": "linux", "cpu": "x64" }, "sha512-V6xjvFfHh3NGvsuuDae1KHPRZXHMEE8XL0A/GM6v4I4OCC23kDmkK60Vn6OptQwAzwwbz0X0IX+Ut/GQU9qGgA=="], + "@opentui/core-linux-x64": ["@opentui/core-linux-x64@0.1.86", "", { "os": "linux", "cpu": "x64" }, "sha512-VBaBkVdQDxYV4WcKjb+jgyMS5PiVHepvfaoKWpz1Bq+J01xXW4XPcXyPGkgR1+2R93KzaugEnLscTW4mWtLHlQ=="], - "@opentui/core-win32-arm64": ["@opentui/core-win32-arm64@0.1.79", "", { "os": "win32", "cpu": "arm64" }, "sha512-sPRKnVzOdT5szI59tte7pxwwkYA+07EQN+6miFAvkFuiLmRUngONUD8HVjL7nCnxcPFqxaU4Rvl1y40ST86g8g=="], + "@opentui/core-win32-arm64": ["@opentui/core-win32-arm64@0.1.86", "", { "os": "win32", "cpu": "arm64" }, "sha512-xKbT7sEKYKGwUPkoqmLfHjbJU+vwHPDwf/r/mIunL41JXQBB35CSZ3/QgIwpp2kkteu7oE1tdBdg15ogUU4OMg=="], - "@opentui/core-win32-x64": ["@opentui/core-win32-x64@0.1.79", "", { "os": "win32", "cpu": "x64" }, "sha512-vmQcFTvKf9fqajnDtgU6/uAsiTGwx8//khqHVBmiTEXUsiT792Ki9l8sgNughbuldqG5iZOiF6IaAWU1H67UpA=="], + "@opentui/core-win32-x64": ["@opentui/core-win32-x64@0.1.86", "", { "os": "win32", "cpu": "x64" }, "sha512-HRfgAUlcu71/MrtgfX4Gj7PsDtfXZiuC506Pkn1OnRN1Xomcu10BVRDweUa0/g8ldU9i9kLjMGGnpw6/NjaBFg=="], - "@opentui/solid": ["@opentui/solid@0.1.79", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.1.79", "babel-plugin-module-resolver": "5.0.2", "babel-preset-solid": "1.9.9", "s-js": "^0.4.9" }, "peerDependencies": { "solid-js": "1.9.9" } }, "sha512-c5+0jexKxb8GwRDDkQ/U6isZZqClAzHccXmYiLYmSnqdoQQp2lIGHLartL+K8lfIQrsKClzP2ZHumN6nexRfRg=="], + "@opentui/solid": ["@opentui/solid@0.1.86", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.1.86", "babel-plugin-module-resolver": "5.0.2", "babel-preset-solid": "1.9.9", "s-js": "^0.4.9" }, "peerDependencies": { "solid-js": "1.9.9" } }, "sha512-pOZC9dlZIH+bpstVVZ2AvYukBnslZTKSl/y5H8FWcMTHGv/BzpGxXBxstL65E/IQASqPFbvFcs7yMRzdLhynmA=="], "@oslojs/asn1": ["@oslojs/asn1@1.0.0", "", { "dependencies": { "@oslojs/binary": "1.0.0" } }, "sha512-zw/wn0sj0j0QKbIXfIlnEcTviaCzYOY3V5rAyjR6YtOByFtJiT574+8p9Wlach0lZH9fddD4yb9laEAIl4vXQA=="], @@ -1442,7 +1550,9 @@ "@parcel/watcher-win32-x64": ["@parcel/watcher-win32-x64@2.5.1", "", { "os": "win32", "cpu": "x64" }, "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA=="], - "@pierre/diffs": ["@pierre/diffs@1.1.0-beta.13", "", { "dependencies": { "@shikijs/transformers": "^3.0.0", "diff": "8.0.3", "hast-util-to-html": "9.0.5", "lru_map": "0.4.1", "shiki": "^3.0.0" }, "peerDependencies": { "react": "^18.3.1 || ^19.0.0", "react-dom": "^18.3.1 || ^19.0.0" } }, "sha512-D35rxDu5V7XHX5aVGU6PF12GhscL+I+9QYgxK/i3h0d2XSirAxDdVNm49aYwlOhgmdvL0NbS1IHxPswVB5yJvw=="], + "@pierre/diffs": ["@pierre/diffs@1.1.0-beta.18", "", { "dependencies": { "@pierre/theme": "0.0.22", "@shikijs/transformers": "^3.0.0", "diff": "8.0.3", "hast-util-to-html": "9.0.5", "lru_map": "0.4.1", "shiki": "^3.0.0" }, "peerDependencies": { "react": "^18.3.1 || ^19.0.0", "react-dom": "^18.3.1 || ^19.0.0" } }, "sha512-7ZF3YD9fxdbYsPnltz5cUqHacN7ztp8RX/fJLxwv8wIEORpP4+7dHz1h/qx3o4EW2xUrIhmbM8ImywLasB787Q=="], + + "@pierre/theme": ["@pierre/theme@0.0.22", "", {}, "sha512-ePUIdQRNGjrveELTU7fY89Xa7YGHHEy5Po5jQy/18lm32eRn96+tnYJEtFooGdffrx55KBUtOXfvVy/7LDFFhA=="], "@pinojs/redact": ["@pinojs/redact@0.4.0", "", {}, "sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg=="], @@ -1602,7 +1712,7 @@ "@shikijs/vscode-textmate": ["@shikijs/vscode-textmate@10.0.2", "", {}, "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg=="], - "@sindresorhus/is": ["@sindresorhus/is@7.2.0", "", {}, "sha512-P1Cz1dWaFfR4IR+U13mqqiGsLFf1KbayybWwdd2vfctdV6hDpUkgCY0nKOLLTMSoRd/jJNjtbqzf13K8DCCXQw=="], + "@sindresorhus/is": ["@sindresorhus/is@4.6.0", "", {}, "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw=="], "@slack/bolt": ["@slack/bolt@3.22.0", "", { "dependencies": { "@slack/logger": "^4.0.0", "@slack/oauth": "^2.6.3", "@slack/socket-mode": "^1.3.6", "@slack/types": "^2.13.0", "@slack/web-api": "^6.13.0", "@types/express": "^4.16.1", "@types/promise.allsettled": "^1.0.3", "@types/tsscmp": "^1.0.0", "axios": "^1.7.4", "express": "^4.21.0", "path-to-regexp": "^8.1.0", "promise.allsettled": "^1.0.2", "raw-body": "^2.3.3", "tsscmp": "^1.0.6" } }, "sha512-iKDqGPEJDnrVwxSVlFW6OKTkijd7s4qLBeSufoBsTM0reTyfdp/5izIQVkxNfzjHi3o6qjdYbRXkYad5HBsBog=="], @@ -1774,10 +1884,32 @@ "@standard-schema/spec": ["@standard-schema/spec@1.0.0", "", {}, "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA=="], + "@storybook/addon-a11y": ["@storybook/addon-a11y@10.2.13", "", { "dependencies": { "@storybook/global": "^5.0.0", "axe-core": "^4.2.0" }, "peerDependencies": { "storybook": "^10.2.13" } }, "sha512-zuR1n1xgWoieEnr6E5xdTR40BI61IBQahgmsRpTvqRffL3mxAs5aFoORDmA5pZWI2LE9URdMkY85h218ijuLiw=="], + + "@storybook/addon-docs": ["@storybook/addon-docs@10.2.13", "", { "dependencies": { "@mdx-js/react": "^3.0.0", "@storybook/csf-plugin": "10.2.13", "@storybook/icons": "^2.0.1", "@storybook/react-dom-shim": "10.2.13", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "ts-dedent": "^2.0.0" }, "peerDependencies": { "storybook": "^10.2.13" } }, "sha512-puMxpJbt/CuodLIbKDxWrW1ZgADYomfNHWEKp2d2l2eJjp17rADx0h3PABuNbX+YHbJwYcDdqluSnQwMysFEOA=="], + + "@storybook/addon-links": ["@storybook/addon-links@10.2.13", "", { "dependencies": { "@storybook/global": "^5.0.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "storybook": "^10.2.13" }, "optionalPeers": ["react"] }, "sha512-8wnAomGiHaUpNIc+lOzmazTrebxa64z9rihIbM/Q59vkOImHQNkGp7KP/qNgJA4GPTFtu8+fLjX2qCoAQPM0jQ=="], + + "@storybook/addon-onboarding": ["@storybook/addon-onboarding@10.2.13", "", { "peerDependencies": { "storybook": "^10.2.13" } }, "sha512-kw2GgIY67UR8YXKfuVS0k+mfWL1joNQHeSe5DlDL4+7qbgp9zfV6cRJ199BMdfRAQNMzQoxHgRUcAMAqs3Rkpw=="], + + "@storybook/addon-vitest": ["@storybook/addon-vitest@10.2.13", "", { "dependencies": { "@storybook/global": "^5.0.0", "@storybook/icons": "^2.0.1" }, "peerDependencies": { "@vitest/browser": "^3.0.0 || ^4.0.0", "@vitest/browser-playwright": "^4.0.0", "@vitest/runner": "^3.0.0 || ^4.0.0", "storybook": "^10.2.13", "vitest": "^3.0.0 || ^4.0.0" }, "optionalPeers": ["@vitest/browser", "@vitest/browser-playwright", "@vitest/runner", "vitest"] }, "sha512-qQD3xzxc31cQHS0loF9enGWi5sgA6zBTbaJ0HuSUNGO81iwfLSALh8L/1vrD5NfN2vlBeUMTsgv3EkCuLfe9EQ=="], + + "@storybook/builder-vite": ["@storybook/builder-vite@10.2.10", "", { "dependencies": { "@storybook/csf-plugin": "10.2.10", "ts-dedent": "^2.0.0" }, "peerDependencies": { "storybook": "^10.2.10", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-Wd6CYL7LvRRNiXMz977x9u/qMm7nmMw/7Dow2BybQo+Xbfy1KhVjIoZ/gOiG515zpojSozctNrJUbM0+jH1jwg=="], + + "@storybook/csf-plugin": ["@storybook/csf-plugin@10.2.13", "", { "dependencies": { "unplugin": "^2.3.5" }, "peerDependencies": { "esbuild": "*", "rollup": "*", "storybook": "^10.2.13", "vite": "*", "webpack": "*" }, "optionalPeers": ["esbuild", "rollup", "vite", "webpack"] }, "sha512-gUCR7PmyrWYj3dIJJgxOm25dcXFolPIUPmug3z90Aaon7YPXw3pUN+dNDx8KqDJqRK1WDIB4HaefgYZIm5V7iA=="], + + "@storybook/global": ["@storybook/global@5.0.0", "", {}, "sha512-FcOqPAXACP0I3oJ/ws6/rrPT9WGhu915Cg8D02a9YxLo0DE9zI+a9A5gRGvmQ09fiWPukqI8ZAEoQEdWUKMQdQ=="], + + "@storybook/icons": ["@storybook/icons@2.0.1", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-/smVjw88yK3CKsiuR71vNgWQ9+NuY2L+e8X7IMrFjexjm6ZR8ULrV2DRkTA61aV6ryefslzHEGDInGpnNeIocg=="], + + "@storybook/react-dom-shim": ["@storybook/react-dom-shim@10.2.13", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "storybook": "^10.2.13" } }, "sha512-ZSduoB10qTI0V9z22qeULmQLsvTs8d/rtJi03qbVxpPiMRor86AmyAaBrfhGGmWBxWQZpOGQQm6yIT2YLoPs7w=="], + "@stripe/stripe-js": ["@stripe/stripe-js@8.6.1", "", {}, "sha512-UJ05U2062XDgydbUcETH1AoRQLNhigQ2KmDn1BG8sC3xfzu6JKg95Qt6YozdzFpxl1Npii/02m2LEWFt1RYjVA=="], "@swc/helpers": ["@swc/helpers@0.5.18", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-TXTnIcNJQEKwThMMqBXsZ4VGAza6bvN4pa41Rkqoio6QBKMvo+5lexeTMScGCIxtzgQJzElcvIltani+adC5PQ=="], + "@szmarczak/http-timer": ["@szmarczak/http-timer@4.0.6", "", { "dependencies": { "defer-to-connect": "^2.0.0" } }, "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w=="], + "@tailwindcss/node": ["@tailwindcss/node@4.1.11", "", { "dependencies": { "@ampproject/remapping": "^2.3.0", "enhanced-resolve": "^5.18.1", "jiti": "^2.4.2", "lightningcss": "1.30.1", "magic-string": "^0.30.17", "source-map-js": "^1.2.1", "tailwindcss": "4.1.11" } }, "sha512-yzhzuGRmv5QyU9qLNg4GTlYI6STedBWRE7NjxP45CsFYYq9taI0zJXZBMqIC/c8fViNLhmrbpSFS57EoxUmD6Q=="], "@tailwindcss/oxide": ["@tailwindcss/oxide@4.1.11", "", { "dependencies": { "detect-libc": "^2.0.4", "tar": "^7.4.3" }, "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.1.11", "@tailwindcss/oxide-darwin-arm64": "4.1.11", "@tailwindcss/oxide-darwin-x64": "4.1.11", "@tailwindcss/oxide-freebsd-x64": "4.1.11", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.11", "@tailwindcss/oxide-linux-arm64-gnu": "4.1.11", "@tailwindcss/oxide-linux-arm64-musl": "4.1.11", "@tailwindcss/oxide-linux-x64-gnu": "4.1.11", "@tailwindcss/oxide-linux-x64-musl": "4.1.11", "@tailwindcss/oxide-wasm32-wasi": "4.1.11", "@tailwindcss/oxide-win32-arm64-msvc": "4.1.11", "@tailwindcss/oxide-win32-x64-msvc": "4.1.11" } }, "sha512-Q69XzrtAhuyfHo+5/HMgr1lAiPP/G40OMFAnws7xcFEYqcypZmdW8eGXaOUIeOl1dzPJBPENXgbjsOyhg2nkrg=="], @@ -1866,16 +1998,26 @@ "@tediousjs/connection-string": ["@tediousjs/connection-string@0.5.0", "", {}, "sha512-7qSgZbincDDDFyRweCIEvZULFAw5iz/DeunhvuxpL31nfntX3P4Yd4HkHBRg9H8CdqY1e5WFN1PZIz/REL9MVQ=="], + "@testing-library/dom": ["@testing-library/dom@10.4.1", "", { "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", "@types/aria-query": "^5.0.1", "aria-query": "5.3.0", "dom-accessibility-api": "^0.5.9", "lz-string": "^1.5.0", "picocolors": "1.1.1", "pretty-format": "^27.0.2" } }, "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg=="], + + "@testing-library/jest-dom": ["@testing-library/jest-dom@6.9.1", "", { "dependencies": { "@adobe/css-tools": "^4.4.0", "aria-query": "^5.0.0", "css.escape": "^1.5.1", "dom-accessibility-api": "^0.6.3", "picocolors": "^1.1.1", "redent": "^3.0.0" } }, "sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA=="], + + "@testing-library/user-event": ["@testing-library/user-event@14.6.1", "", { "peerDependencies": { "@testing-library/dom": ">=7.21.4" } }, "sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw=="], + "@thisbeyond/solid-dnd": ["@thisbeyond/solid-dnd@0.7.5", "", { "peerDependencies": { "solid-js": "^1.5" } }, "sha512-DfI5ff+yYGpK9M21LhYwIPlbP2msKxN2ARwuu6GF8tT1GgNVDTI8VCQvH4TJFoVApP9d44izmAcTh/iTCH2UUw=="], "@tokenizer/token": ["@tokenizer/token@0.3.0", "", {}, "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A=="], + "@tootallnate/once": ["@tootallnate/once@1.1.2", "", {}, "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw=="], + "@tsconfig/bun": ["@tsconfig/bun@1.0.9", "", {}, "sha512-4M0/Ivfwcpz325z6CwSifOBZYji3DFOEpY6zEUt0+Xi2qRhzwvmqQN9XAHJh3OVvRJuAqVTLU2abdCplvp6mwQ=="], "@tsconfig/node22": ["@tsconfig/node22@22.0.2", "", {}, "sha512-Kmwj4u8sDRDrMYRoN9FDEcXD8UpBSaPQQ24Gz+Gamqfm7xxn+GBR7ge/Z7pK8OXNGyUzbSwJj+TH6B+DS/epyA=="], "@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="], + "@types/aria-query": ["@types/aria-query@5.0.4", "", {}, "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw=="], + "@types/babel__core": ["@types/babel__core@7.20.5", "", { "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" } }, "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA=="], "@types/babel__generator": ["@types/babel__generator@7.27.0", "", { "dependencies": { "@babel/types": "^7.0.0" } }, "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg=="], @@ -1890,6 +2032,8 @@ "@types/bun": ["@types/bun@1.3.9", "", { "dependencies": { "bun-types": "1.3.9" } }, "sha512-KQ571yULOdWJiMH+RIWIOZ7B2RXQGpL1YQrBtLIV3FqDcCu6FsbFUBwhdKUlCKUpS3PJDsHlJ1QKlpxoVR+xtw=="], + "@types/cacheable-request": ["@types/cacheable-request@6.0.3", "", { "dependencies": { "@types/http-cache-semantics": "*", "@types/keyv": "^3.1.4", "@types/node": "*", "@types/responselike": "^1.0.0" } }, "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw=="], + "@types/chai": ["@types/chai@5.2.3", "", { "dependencies": { "@types/deep-eql": "*", "assertion-error": "^2.0.1" } }, "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA=="], "@types/connect": ["@types/connect@3.4.38", "", { "dependencies": { "@types/node": "*" } }, "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug=="], @@ -1908,8 +2052,12 @@ "@types/fontkit": ["@types/fontkit@2.0.8", "", { "dependencies": { "@types/node": "*" } }, "sha512-wN+8bYxIpJf+5oZdrdtaX04qUuWHcKxcDEgRS9Qm9ZClSHjzEn13SxUC+5eRM+4yXIeTYk8mTzLAWGF64847ew=="], + "@types/fs-extra": ["@types/fs-extra@9.0.13", "", { "dependencies": { "@types/node": "*" } }, "sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA=="], + "@types/hast": ["@types/hast@3.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ=="], + "@types/http-cache-semantics": ["@types/http-cache-semantics@4.2.0", "", {}, "sha512-L3LgimLHXtGkWikKnsPg0/VFx9OGZaC+eN1u4r+OB1XRqH3meBIAVC2zr1WdMH+RHmnRkqliQAOHNJ/E0j/e0Q=="], + "@types/http-errors": ["@types/http-errors@2.0.5", "", {}, "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg=="], "@types/is-stream": ["@types/is-stream@1.1.0", "", { "dependencies": { "@types/node": "*" } }, "sha512-jkZatu4QVbR60mpIzjINmtS1ZF4a/FqdTUTBeQDVOQ2PYyidtwFKr0B5G6ERukKwliq+7mIXvxyppwzG5EgRYg=="], @@ -1922,6 +2070,8 @@ "@types/katex": ["@types/katex@0.16.7", "", {}, "sha512-HMwFiRujE5PjrgwHQ25+bsLJgowjGjm5Z8FVSf0N6PwgJrwxH0QxzHYDcKsTfV3wva0vzrpqMTJS2jXPr5BMEQ=="], + "@types/keyv": ["@types/keyv@3.1.4", "", { "dependencies": { "@types/node": "*" } }, "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg=="], + "@types/luxon": ["@types/luxon@3.7.1", "", {}, "sha512-H3iskjFIAn5SlJU7OuxUmTEpebK6TKB8rxZShDslBMZJ5u9S//KM1sbdAisiSrqwLQncVjnpi2OK2J51h+4lsg=="], "@types/mdast": ["@types/mdast@4.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA=="], @@ -1944,6 +2094,8 @@ "@types/node-fetch": ["@types/node-fetch@2.6.13", "", { "dependencies": { "@types/node": "*", "form-data": "^4.0.4" } }, "sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw=="], + "@types/plist": ["@types/plist@3.0.5", "", { "dependencies": { "@types/node": "*", "xmlbuilder": ">=11.0.1" } }, "sha512-E6OCaRmAe4WDmWNsL/9RMqdkkzDCY1etutkflWk4c+AcjDU07Pcz1fQwTX0TQz+Pxqn9i4L1TU3UFpjnrcDgxA=="], + "@types/promise.allsettled": ["@types/promise.allsettled@1.0.6", "", {}, "sha512-wA0UT0HeT2fGHzIFV9kWpYz5mdoyLxKrTgMdZQM++5h6pYAFH73HXcQhefg24nD1yivUFEn5KU+EF4b+CXJ4Wg=="], "@types/prop-types": ["@types/prop-types@15.7.15", "", {}, "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw=="], @@ -1956,12 +2108,16 @@ "@types/readable-stream": ["@types/readable-stream@4.0.23", "", { "dependencies": { "@types/node": "*" } }, "sha512-wwXrtQvbMHxCbBgjHaMGEmImFTQxxpfMOR/ZoQnXxB1woqkUbdLGFDgauo00Py9IudiaqSeiBiulSV9i6XIPig=="], + "@types/responselike": ["@types/responselike@1.0.3", "", { "dependencies": { "@types/node": "*" } }, "sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw=="], + "@types/retry": ["@types/retry@0.12.0", "", {}, "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA=="], "@types/sax": ["@types/sax@1.2.7", "", { "dependencies": { "@types/node": "*" } }, "sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A=="], "@types/scheduler": ["@types/scheduler@0.26.0", "", {}, "sha512-WFHp9YUJQ6CKshqoC37iOlHnQSmxNc795UhB26CyBBttrN9svdIrUjl/NjnNmfcwtncN0h/0PPAFWv9ovP8mLA=="], + "@types/semver": ["@types/semver@7.7.1", "", {}, "sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA=="], + "@types/send": ["@types/send@1.2.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ=="], "@types/serve-static": ["@types/serve-static@1.15.10", "", { "dependencies": { "@types/http-errors": "*", "@types/node": "*", "@types/send": "<1" } }, "sha512-tRs1dB+g8Itk72rlSI2ZrW6vZg0YrLI81iQSTkMmOqnqCaNr/8Ek4VwWcN5vZgCYWbg/JJSGBlUaYGAOP73qBw=="], @@ -1976,14 +2132,20 @@ "@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="], + "@types/verror": ["@types/verror@1.10.11", "", {}, "sha512-RlDm9K7+o5stv0Co8i8ZRGxDbrTxhJtgjqjFyVh/tXQyl/rYtTKlnTvZ88oSTeYREWurwx20Js4kTuKCsFkUtg=="], + "@types/whatwg-mimetype": ["@types/whatwg-mimetype@3.0.2", "", {}, "sha512-c2AKvDT8ToxLIOUlN51gTiHXflsfIFisS4pO7pDPoKouJCESkhZnEy623gwP9laCy5lnLDAw1vAzu2vM2YLOrA=="], + "@types/which": ["@types/which@3.0.4", "", {}, "sha512-liyfuo/106JdlgSchJzXEQCVArk0CvevqPote8F8HgWgJ3dRCcTHgJIsLDuee0kxk/mhbInzIZk3QWSZJ8R+2w=="], + "@types/ws": ["@types/ws@8.18.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="], "@types/yargs": ["@types/yargs@17.0.33", "", { "dependencies": { "@types/yargs-parser": "*" } }, "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA=="], "@types/yargs-parser": ["@types/yargs-parser@21.0.3", "", {}, "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ=="], + "@types/yauzl": ["@types/yauzl@2.10.3", "", { "dependencies": { "@types/node": "*" } }, "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q=="], + "@typescript/native-preview": ["@typescript/native-preview@7.0.0-dev.20251207.1", "", { "optionalDependencies": { "@typescript/native-preview-darwin-arm64": "7.0.0-dev.20251207.1", "@typescript/native-preview-darwin-x64": "7.0.0-dev.20251207.1", "@typescript/native-preview-linux-arm": "7.0.0-dev.20251207.1", "@typescript/native-preview-linux-arm64": "7.0.0-dev.20251207.1", "@typescript/native-preview-linux-x64": "7.0.0-dev.20251207.1", "@typescript/native-preview-win32-arm64": "7.0.0-dev.20251207.1", "@typescript/native-preview-win32-x64": "7.0.0-dev.20251207.1" }, "bin": { "tsgo": "bin/tsgo.js" } }, "sha512-4QcRnzB0pi9rS0AOvg8kWbmuwHv5X7B2EXHbgcms9+56hsZ8SZrZjNgBJb2rUIodJ4kU5mrkj/xlTTT4r9VcpQ=="], "@typescript/native-preview-darwin-arm64": ["@typescript/native-preview-darwin-arm64@7.0.0-dev.20251207.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-waWJnuuvkXh4WdpbTjYf7pyahJzx0ycesV2BylyHrE9OxU9FSKcD/cRLQYvbq3YcBSdF7sZwRLDBer7qTeLsYA=="], @@ -2010,7 +2172,7 @@ "@vitejs/plugin-react": ["@vitejs/plugin-react@4.7.0", "", { "dependencies": { "@babel/core": "^7.28.0", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", "@rolldown/pluginutils": "1.0.0-beta.27", "@types/babel__core": "^7.20.5", "react-refresh": "^0.17.0" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA=="], - "@vitest/expect": ["@vitest/expect@4.0.18", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "@types/chai": "^5.2.2", "@vitest/spy": "4.0.18", "@vitest/utils": "4.0.18", "chai": "^6.2.1", "tinyrainbow": "^3.0.3" } }, "sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ=="], + "@vitest/expect": ["@vitest/expect@3.2.4", "", { "dependencies": { "@types/chai": "^5.2.2", "@vitest/spy": "3.2.4", "@vitest/utils": "3.2.4", "chai": "^5.2.0", "tinyrainbow": "^2.0.0" } }, "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig=="], "@vitest/mocker": ["@vitest/mocker@4.0.18", "", { "dependencies": { "@vitest/spy": "4.0.18", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, "peerDependencies": { "msw": "^2.4.9", "vite": "^6.0.0 || ^7.0.0-0" }, "optionalPeers": ["msw", "vite"] }, "sha512-HhVd0MDnzzsgevnOWCBj5Otnzobjy5wLBe4EdeeFGv8luMsGcYqDuFRMcttKWZA5vVO8RFjexVovXvAM4JoJDQ=="], @@ -2020,7 +2182,7 @@ "@vitest/snapshot": ["@vitest/snapshot@4.0.18", "", { "dependencies": { "@vitest/pretty-format": "4.0.18", "magic-string": "^0.30.21", "pathe": "^2.0.3" } }, "sha512-PCiV0rcl7jKQjbgYqjtakly6T1uwv/5BQ9SwBLekVg/EaYeQFPiXcgrC2Y7vDMA8dM1SUEAEV82kgSQIlXNMvA=="], - "@vitest/spy": ["@vitest/spy@4.0.18", "", {}, "sha512-cbQt3PTSD7P2OARdVW3qWER5EGq7PHlvE+QfzSC0lbwO+xnt7+XH06ZzFjFRgzUX//JmpxrCu92VdwvEPlWSNw=="], + "@vitest/spy": ["@vitest/spy@3.2.4", "", { "dependencies": { "tinyspy": "^4.0.3" } }, "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw=="], "@vitest/utils": ["@vitest/utils@4.0.18", "", { "dependencies": { "@vitest/pretty-format": "4.0.18", "tinyrainbow": "^3.0.3" } }, "sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA=="], @@ -2042,6 +2204,8 @@ "@webgpu/types": ["@webgpu/types@0.1.54", "", {}, "sha512-81oaalC8LFrXjhsczomEQ0u3jG+TqE6V9QHLA8GNZq/Rnot0KDugu3LhSYSlie8tSdooAN1Hov05asrUUp9qgg=="], + "@xmldom/xmldom": ["@xmldom/xmldom@0.8.11", "", {}, "sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw=="], + "@zip.js/zip.js": ["@zip.js/zip.js@2.7.62", "", {}, "sha512-OaLvZ8j4gCkLn048ypkZu29KX30r8/OfFF2w4Jo5WXFr+J04J+lzJ5TKZBVgFXhlvSkqNFQdfnY1Q8TMTCyBVA=="], "abbrev": ["abbrev@2.0.0", "", {}, "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ=="], @@ -2062,6 +2226,8 @@ "agentkeepalive": ["agentkeepalive@4.6.0", "", { "dependencies": { "humanize-ms": "^1.2.1" } }, "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ=="], + "aggregate-error": ["aggregate-error@3.1.0", "", { "dependencies": { "clean-stack": "^2.0.0", "indent-string": "^4.0.0" } }, "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA=="], + "ai": ["ai@5.0.124", "", { "dependencies": { "@ai-sdk/gateway": "2.0.30", "@ai-sdk/provider": "2.0.1", "@ai-sdk/provider-utils": "3.0.20", "@opentelemetry/api": "1.9.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-Li6Jw9F9qsvFJXZPBfxj38ddP2iURCnMs96f9Q3OeQzrDVcl1hvtwSEAuxA/qmfh6SDV2ERqFUOFzigvr0697g=="], "ai-gateway-provider": ["ai-gateway-provider@2.3.1", "", { "dependencies": { "@ai-sdk/provider": "^2.0.0", "@ai-sdk/provider-utils": "^3.0.19", "ai": "^5.0.116" }, "optionalDependencies": { "@ai-sdk/amazon-bedrock": "^3.0.71", "@ai-sdk/anthropic": "^2.0.56", "@ai-sdk/azure": "^2.0.90", "@ai-sdk/cerebras": "^1.0.33", "@ai-sdk/cohere": "^2.0.21", "@ai-sdk/deepgram": "^1.0.21", "@ai-sdk/deepseek": "^1.0.32", "@ai-sdk/elevenlabs": "^1.0.21", "@ai-sdk/fireworks": "^1.0.30", "@ai-sdk/google": "^2.0.51", "@ai-sdk/google-vertex": "3.0.90", "@ai-sdk/groq": "^2.0.33", "@ai-sdk/mistral": "^2.0.26", "@ai-sdk/openai": "^2.0.88", "@ai-sdk/perplexity": "^2.0.22", "@ai-sdk/xai": "^2.0.42", "@openrouter/ai-sdk-provider": "^1.5.3" }, "peerDependencies": { "@ai-sdk/openai-compatible": "^1.0.29" } }, "sha512-PqI6TVNEDNwr7kOhy7XUGnA8XJB1SpeA9aLqGjr0CyWkKgH+y+ofPm8MZGZ74DOwVejDF+POZq0Qs9jKEKUeYg=="], @@ -2072,6 +2238,8 @@ "ajv-formats": ["ajv-formats@3.0.1", "", { "dependencies": { "ajv": "^8.0.0" } }, "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ=="], + "ajv-keywords": ["ajv-keywords@3.5.2", "", { "peerDependencies": { "ajv": "^6.9.1" } }, "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ=="], + "ansi-align": ["ansi-align@3.0.1", "", { "dependencies": { "string-width": "^4.1.0" } }, "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w=="], "ansi-colors": ["ansi-colors@4.1.3", "", {}, "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw=="], @@ -2088,12 +2256,20 @@ "anymatch": ["anymatch@3.1.3", "", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="], + "app-builder-bin": ["app-builder-bin@5.0.0-alpha.12", "", {}, "sha512-j87o0j6LqPL3QRr8yid6c+Tt5gC7xNfYo6uQIQkorAC6MpeayVMZrEDzKmJJ/Hlv7EnOQpaRm53k6ktDYZyB6w=="], + + "app-builder-lib": ["app-builder-lib@26.8.1", "", { "dependencies": { "@develar/schema-utils": "~2.6.5", "@electron/asar": "3.4.1", "@electron/fuses": "^1.8.0", "@electron/get": "^3.0.0", "@electron/notarize": "2.5.0", "@electron/osx-sign": "1.3.3", "@electron/rebuild": "^4.0.3", "@electron/universal": "2.0.3", "@malept/flatpak-bundler": "^0.4.0", "@types/fs-extra": "9.0.13", "async-exit-hook": "^2.0.1", "builder-util": "26.8.1", "builder-util-runtime": "9.5.1", "chromium-pickle-js": "^0.2.0", "ci-info": "4.3.1", "debug": "^4.3.4", "dotenv": "^16.4.5", "dotenv-expand": "^11.0.6", "ejs": "^3.1.8", "electron-publish": "26.8.1", "fs-extra": "^10.1.0", "hosted-git-info": "^4.1.0", "isbinaryfile": "^5.0.0", "jiti": "^2.4.2", "js-yaml": "^4.1.0", "json5": "^2.2.3", "lazy-val": "^1.0.5", "minimatch": "^10.0.3", "plist": "3.1.0", "proper-lockfile": "^4.1.2", "resedit": "^1.7.0", "semver": "~7.7.3", "tar": "^7.5.7", "temp-file": "^3.4.0", "tiny-async-pool": "1.3.0", "which": "^5.0.0" }, "peerDependencies": { "dmg-builder": "26.8.1", "electron-builder-squirrel-windows": "26.8.1" } }, "sha512-p0Im/Dx5C4tmz8QEE1Yn4MkuPC8PrnlRneMhWJj7BBXQfNTJUshM/bp3lusdEsDbvvfJZpXWnYesgSLvwtM2Zw=="], + + "aproba": ["aproba@2.1.0", "", {}, "sha512-tLIEcj5GuR2RSTnxNKdkK0dJ/GrC7P38sUkiDmDuHfsHmbagTFAxDVIBltoklXEVIQ/f14IL8IMJ5pn9Hez1Ew=="], + "archiver": ["archiver@7.0.1", "", { "dependencies": { "archiver-utils": "^5.0.2", "async": "^3.2.4", "buffer-crc32": "^1.0.0", "readable-stream": "^4.0.0", "readdir-glob": "^1.1.2", "tar-stream": "^3.0.0", "zip-stream": "^6.0.1" } }, "sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ=="], "archiver-utils": ["archiver-utils@5.0.2", "", { "dependencies": { "glob": "^10.0.0", "graceful-fs": "^4.2.0", "is-stream": "^2.0.1", "lazystream": "^1.0.0", "lodash": "^4.17.15", "normalize-path": "^3.0.0", "readable-stream": "^4.0.0" } }, "sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA=="], "arctic": ["arctic@2.3.4", "", { "dependencies": { "@oslojs/crypto": "1.0.1", "@oslojs/encoding": "1.1.0", "@oslojs/jwt": "0.2.0" } }, "sha512-+p30BOWsctZp+CVYCt7oAean/hWGW42sH5LAcRQX56ttEkFJWbzXBhmSpibbzwSJkRrotmsA+oAoJoVsU0f5xA=="], + "are-we-there-yet": ["are-we-there-yet@3.0.1", "", { "dependencies": { "delegates": "^1.0.0", "readable-stream": "^3.6.0" } }, "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg=="], + "arg": ["arg@5.0.2", "", {}, "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg=="], "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], @@ -2114,8 +2290,14 @@ "arraybuffer.prototype.slice": ["arraybuffer.prototype.slice@1.0.4", "", { "dependencies": { "array-buffer-byte-length": "^1.0.1", "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.5", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "is-array-buffer": "^3.0.4" } }, "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ=="], + "assert-plus": ["assert-plus@1.0.0", "", {}, "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw=="], + "assertion-error": ["assertion-error@2.0.1", "", {}, "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA=="], + "ast-types": ["ast-types@0.16.1", "", { "dependencies": { "tslib": "^2.0.1" } }, "sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg=="], + + "astral-regex": ["astral-regex@2.0.0", "", {}, "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ=="], + "astring": ["astring@1.9.0", "", { "bin": { "astring": "bin/astring" } }, "sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg=="], "astro": ["astro@5.7.13", "", { "dependencies": { "@astrojs/compiler": "^2.11.0", "@astrojs/internal-helpers": "0.6.1", "@astrojs/markdown-remark": "6.3.1", "@astrojs/telemetry": "3.2.1", "@capsizecss/unpack": "^2.4.0", "@oslojs/encoding": "^1.1.0", "@rollup/pluginutils": "^5.1.4", "acorn": "^8.14.1", "aria-query": "^5.3.2", "axobject-query": "^4.1.0", "boxen": "8.0.1", "ci-info": "^4.2.0", "clsx": "^2.1.1", "common-ancestor-path": "^1.0.1", "cookie": "^1.0.2", "cssesc": "^3.0.0", "debug": "^4.4.0", "deterministic-object-hash": "^2.0.2", "devalue": "^5.1.1", "diff": "^5.2.0", "dlv": "^1.1.3", "dset": "^3.1.4", "es-module-lexer": "^1.6.0", "esbuild": "^0.25.0", "estree-walker": "^3.0.3", "flattie": "^1.1.1", "fontace": "~0.3.0", "github-slugger": "^2.0.0", "html-escaper": "3.0.3", "http-cache-semantics": "^4.1.1", "js-yaml": "^4.1.0", "kleur": "^4.1.5", "magic-string": "^0.30.17", "magicast": "^0.3.5", "mrmime": "^2.0.1", "neotraverse": "^0.6.18", "p-limit": "^6.2.0", "p-queue": "^8.1.0", "package-manager-detector": "^1.1.0", "picomatch": "^4.0.2", "prompts": "^2.4.2", "rehype": "^13.0.2", "semver": "^7.7.1", "shiki": "^3.2.1", "tinyexec": "^0.3.2", "tinyglobby": "^0.2.12", "tsconfck": "^3.1.5", "ultrahtml": "^1.6.0", "unifont": "~0.5.0", "unist-util-visit": "^5.0.0", "unstorage": "^1.15.0", "vfile": "^6.0.3", "vite": "^6.3.4", "vitefu": "^1.0.6", "xxhash-wasm": "^1.1.0", "yargs-parser": "^21.1.1", "yocto-spinner": "^0.2.1", "zod": "^3.24.2", "zod-to-json-schema": "^3.24.5", "zod-to-ts": "^1.2.0" }, "optionalDependencies": { "sharp": "^0.33.3" }, "bin": { "astro": "astro.js" } }, "sha512-cRGq2llKOhV3XMcYwQpfBIUcssN6HEK5CRbcMxAfd9OcFhvWE7KUy50zLioAZVVl3AqgUTJoNTlmZfD2eG0G1w=="], @@ -2124,12 +2306,18 @@ "async": ["async@3.2.6", "", {}, "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA=="], + "async-exit-hook": ["async-exit-hook@2.0.1", "", {}, "sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw=="], + "async-function": ["async-function@1.0.0", "", {}, "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA=="], "asynckit": ["asynckit@0.4.0", "", {}, "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="], + "at-least-node": ["at-least-node@1.0.0", "", {}, "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg=="], + "atomic-sleep": ["atomic-sleep@1.0.0", "", {}, "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ=="], + "atomically": ["atomically@2.1.1", "", { "dependencies": { "stubborn-fs": "^2.0.0", "when-exit": "^2.1.4" } }, "sha512-P4w9o2dqARji6P7MHprklbfiArZAWvo07yW7qs3pdljb3BWr12FIB7W+p0zJiuiVsUpRO0iZn1kFFcpPegg0tQ=="], + "autoprefixer": ["autoprefixer@10.4.24", "", { "dependencies": { "browserslist": "^4.28.1", "caniuse-lite": "^1.0.30001766", "fraction.js": "^5.3.4", "picocolors": "^1.1.1", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.1.0" }, "bin": { "autoprefixer": "bin/autoprefixer" } }, "sha512-uHZg7N9ULTVbutaIsDRoUkoS8/h3bdsmVJYZ5l3wv8Cp/6UIIoRDm90hZ+BwxUj/hGBEzLxdHNSKuFpn8WOyZw=="], "available-typed-arrays": ["available-typed-arrays@1.0.7", "", { "dependencies": { "possible-typed-array-names": "^1.0.0" } }, "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ=="], @@ -2144,6 +2332,8 @@ "aws4fetch": ["aws4fetch@1.0.20", "", {}, "sha512-/djoAN709iY65ETD6LKCtyyEI04XIBP5xVvfmNxsEP0uJB5tyaGBztSryRr4HqMStr9R06PisQE7m9zDTXKu6g=="], + "axe-core": ["axe-core@4.11.1", "", {}, "sha512-BASOg+YwO2C+346x3LZOeoovTIoTrRqEsqMa6fmfAV0P+U9mFr9NsyOEpiYvFjbc64NMrSswhV50WdXzdb/Z5A=="], + "axios": ["axios@1.13.5", "", { "dependencies": { "follow-redirects": "^1.15.11", "form-data": "^4.0.5", "proxy-from-env": "^1.1.0" } }, "sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q=="], "axobject-query": ["axobject-query@4.1.0", "", {}, "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ=="], @@ -2182,6 +2372,8 @@ "binary-extensions": ["binary-extensions@2.3.0", "", {}, "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw=="], + "bindings": ["bindings@1.5.0", "", { "dependencies": { "file-uri-to-path": "1.0.0" } }, "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ=="], + "bl": ["bl@6.1.6", "", { "dependencies": { "@types/readable-stream": "^4.0.0", "buffer": "^6.0.3", "inherits": "^2.0.4", "readable-stream": "^4.2.0" } }, "sha512-jLsPgN/YSvPUg9UX0Kd73CXpm2Psg9FxMeCSXnk3WBO3CMT10JMwijubhGfHCnFu6TPn1ei3b975dxv7K2pWVg=="], "blake3-wasm": ["blake3-wasm@2.1.5", "", {}, "sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g=="], @@ -2196,6 +2388,8 @@ "boolbase": ["boolbase@1.0.0", "", {}, "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="], + "boolean": ["boolean@3.2.0", "", {}, "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw=="], + "bottleneck": ["bottleneck@2.19.5", "", {}, "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw=="], "bowser": ["bowser@2.14.1", "", {}, "sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg=="], @@ -2220,13 +2414,17 @@ "buffers": ["buffers@0.1.1", "", {}, "sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ=="], + "builder-util": ["builder-util@26.8.1", "", { "dependencies": { "7zip-bin": "~5.2.0", "@types/debug": "^4.1.6", "app-builder-bin": "5.0.0-alpha.12", "builder-util-runtime": "9.5.1", "chalk": "^4.1.2", "cross-spawn": "^7.0.6", "debug": "^4.3.4", "fs-extra": "^10.1.0", "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.0", "js-yaml": "^4.1.0", "sanitize-filename": "^1.6.3", "source-map-support": "^0.5.19", "stat-mode": "^1.0.0", "temp-file": "^3.4.0", "tiny-async-pool": "1.3.0" } }, "sha512-pm1lTYbGyc90DHgCDO7eo8Rl4EqKLciayNbZqGziqnH9jrlKe8ZANGdityLZU+pJh16dfzjAx2xQq9McuIPEtw=="], + + "builder-util-runtime": ["builder-util-runtime@9.5.1", "", { "dependencies": { "debug": "^4.3.4", "sax": "^1.2.4" } }, "sha512-qt41tMfgHTllhResqM5DcnHyDIWNgzHvuY2jDcYP9iaGpkWxTUzV6GQjDeLnlR1/DtdlcsWQbA7sByMpmJFTLQ=="], + "bun-ffi-structs": ["bun-ffi-structs@0.1.2", "", { "peerDependencies": { "typescript": "^5" } }, "sha512-Lh1oQAYHDcnesJauieA4UNkWGXY9hYck7OA5IaRwE3Bp6K2F2pJSNYqq+hIy7P3uOvo3km3oxS8304g5gDMl/w=="], "bun-pty": ["bun-pty@0.4.8", "", {}, "sha512-rO70Mrbr13+jxHHHu2YBkk2pNqrJE5cJn29WE++PUr+GFA0hq/VgtQPZANJ8dJo6d7XImvBk37Innt8GM7O28w=="], "bun-types": ["bun-types@1.3.9", "", { "dependencies": { "@types/node": "*" } }, "sha512-+UBWWOakIP4Tswh0Bt0QD0alpTY8cb5hvgiYeWCMet9YukHbzuruIEeXC2D7nMJPB12kbh8C7XJykSexEqGKJg=="], - "bun-webgpu": ["bun-webgpu@0.1.4", "", { "dependencies": { "@webgpu/types": "^0.1.60" }, "optionalDependencies": { "bun-webgpu-darwin-arm64": "^0.1.4", "bun-webgpu-darwin-x64": "^0.1.4", "bun-webgpu-linux-x64": "^0.1.4", "bun-webgpu-win32-x64": "^0.1.4" } }, "sha512-Kw+HoXl1PMWJTh9wvh63SSRofTA8vYBFCw0XEP1V1fFdQEDhI8Sgf73sdndE/oDpN/7CMx0Yv/q8FCvO39ROMQ=="], + "bun-webgpu": ["bun-webgpu@0.1.5", "", { "dependencies": { "@webgpu/types": "^0.1.60" }, "optionalDependencies": { "bun-webgpu-darwin-arm64": "^0.1.5", "bun-webgpu-darwin-x64": "^0.1.5", "bun-webgpu-linux-x64": "^0.1.5", "bun-webgpu-win32-x64": "^0.1.5" } }, "sha512-91/K6S5whZKX7CWAm9AylhyKrLGRz6BUiiPiM/kXadSnD4rffljCD/q9cNFftm5YXhx4MvLqw33yEilxogJvwA=="], "bun-webgpu-darwin-arm64": ["bun-webgpu-darwin-arm64@0.1.5", "", { "os": "darwin", "cpu": "arm64" }, "sha512-qM7W5IaFpWYGPDcNiQ8DOng3noQ97gxpH2MFH1mGsdKwI0T4oy++egSh5Z7s6AQx8WKgc9GzAsTUM4KZkFdacw=="], @@ -2242,6 +2440,14 @@ "c12": ["c12@3.3.3", "", { "dependencies": { "chokidar": "^5.0.0", "confbox": "^0.2.2", "defu": "^6.1.4", "dotenv": "^17.2.3", "exsolve": "^1.0.8", "giget": "^2.0.0", "jiti": "^2.6.1", "ohash": "^2.0.11", "pathe": "^2.0.3", "perfect-debounce": "^2.0.0", "pkg-types": "^2.3.0", "rc9": "^2.1.2" }, "peerDependencies": { "magicast": "*" }, "optionalPeers": ["magicast"] }, "sha512-750hTRvgBy5kcMNPdh95Qo+XUBeGo8C7nsKSmedDmaQI+E0r82DwHeM6vBewDe4rGFbnxoa4V9pw+sPh5+Iz8Q=="], + "cac": ["cac@6.7.14", "", {}, "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ=="], + + "cacache": ["cacache@15.3.0", "", { "dependencies": { "@npmcli/fs": "^1.0.0", "@npmcli/move-file": "^1.0.1", "chownr": "^2.0.0", "fs-minipass": "^2.0.0", "glob": "^7.1.4", "infer-owner": "^1.0.4", "lru-cache": "^6.0.0", "minipass": "^3.1.1", "minipass-collect": "^1.0.2", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.2", "mkdirp": "^1.0.3", "p-map": "^4.0.0", "promise-inflight": "^1.0.1", "rimraf": "^3.0.2", "ssri": "^8.0.1", "tar": "^6.0.2", "unique-filename": "^1.1.1" } }, "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ=="], + + "cacheable-lookup": ["cacheable-lookup@5.0.4", "", {}, "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA=="], + + "cacheable-request": ["cacheable-request@7.0.4", "", { "dependencies": { "clone-response": "^1.0.2", "get-stream": "^5.1.0", "http-cache-semantics": "^4.0.0", "keyv": "^4.0.0", "lowercase-keys": "^2.0.0", "normalize-url": "^6.0.1", "responselike": "^2.0.0" } }, "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg=="], + "call-bind": ["call-bind@1.0.8", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.0", "es-define-property": "^1.0.0", "get-intrinsic": "^1.2.4", "set-function-length": "^1.2.2" } }, "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww=="], "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="], @@ -2258,7 +2464,7 @@ "ccount": ["ccount@2.0.1", "", {}, "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg=="], - "chai": ["chai@6.2.2", "", {}, "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg=="], + "chai": ["chai@5.3.3", "", { "dependencies": { "assertion-error": "^2.0.1", "check-error": "^2.1.1", "deep-eql": "^5.0.1", "loupe": "^3.1.0", "pathval": "^2.0.0" } }, "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw=="], "chainsaw": ["chainsaw@0.1.0", "", { "dependencies": { "traverse": ">=0.3.0 <0.4" } }, "sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ=="], @@ -2274,6 +2480,8 @@ "chart.js": ["chart.js@4.5.1", "", { "dependencies": { "@kurkle/color": "^0.3.0" } }, "sha512-GIjfiT9dbmHRiYi6Nl2yFCq7kkwdkp1W/lp2J99rX0yo9tgJGn3lKQATztIjb5tVtevcBtIdICNWqlq5+E8/Pw=="], + "check-error": ["check-error@2.1.3", "", {}, "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA=="], + "cheerio": ["cheerio@1.0.0-rc.12", "", { "dependencies": { "cheerio-select": "^2.1.0", "dom-serializer": "^2.0.0", "domhandler": "^5.0.3", "domutils": "^3.0.1", "htmlparser2": "^8.0.1", "parse5": "^7.0.0", "parse5-htmlparser2-tree-adapter": "^7.0.0" } }, "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q=="], "cheerio-select": ["cheerio-select@2.1.0", "", { "dependencies": { "boolbase": "^1.0.0", "css-select": "^5.1.0", "css-what": "^6.1.0", "domelementtype": "^2.3.0", "domhandler": "^5.0.3", "domutils": "^3.0.1" } }, "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g=="], @@ -2282,6 +2490,8 @@ "chownr": ["chownr@3.0.0", "", {}, "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g=="], + "chromium-pickle-js": ["chromium-pickle-js@0.2.0", "", {}, "sha512-1R5Fho+jBq0DDydt+/vHWj5KJNJCKdARKOCwZUen84I5BreWoLqRLANH1U87eJy1tiASPtMnGqJJq0ZsLoRPOw=="], + "ci-info": ["ci-info@4.4.0", "", {}, "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg=="], "citty": ["citty@0.1.6", "", { "dependencies": { "consola": "^3.2.3" } }, "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ=="], @@ -2290,16 +2500,24 @@ "clean-css": ["clean-css@5.3.3", "", { "dependencies": { "source-map": "~0.6.0" } }, "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg=="], + "clean-stack": ["clean-stack@2.2.0", "", {}, "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A=="], + "cli-boxes": ["cli-boxes@3.0.0", "", {}, "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g=="], + "cli-cursor": ["cli-cursor@3.1.0", "", { "dependencies": { "restore-cursor": "^3.1.0" } }, "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw=="], + "cli-spinners": ["cli-spinners@3.4.0", "", {}, "sha512-bXfOC4QcT1tKXGorxL3wbJm6XJPDqEnij2gQ2m7ESQuE+/z9YFIWnl/5RpTiKWbMq3EVKR4fRLJGn6DVfu0mpw=="], + "cli-truncate": ["cli-truncate@2.1.0", "", { "dependencies": { "slice-ansi": "^3.0.0", "string-width": "^4.2.0" } }, "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg=="], + "clipboardy": ["clipboardy@4.0.0", "", { "dependencies": { "execa": "^8.0.1", "is-wsl": "^3.1.0", "is64bit": "^2.0.0" } }, "sha512-5mOlNS0mhX0707P2I0aZ2V/cmHUEO/fL7VFLqszkhUsxt7RwnmrInf/eEQKlf5GzvYeHIjT+Ov1HRfNmymlG0w=="], "cliui": ["cliui@9.0.1", "", { "dependencies": { "string-width": "^7.2.0", "strip-ansi": "^7.1.0", "wrap-ansi": "^9.0.0" } }, "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w=="], "clone": ["clone@2.1.2", "", {}, "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w=="], + "clone-response": ["clone-response@1.0.3", "", { "dependencies": { "mimic-response": "^1.0.0" } }, "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA=="], + "cloudflare": ["cloudflare@5.2.0", "", { "dependencies": { "@types/node": "^18.11.18", "@types/node-fetch": "^2.6.4", "abort-controller": "^3.0.0", "agentkeepalive": "^4.2.1", "form-data-encoder": "1.7.2", "formdata-node": "^4.3.2", "node-fetch": "^2.6.7" } }, "sha512-dVzqDpPFYR9ApEC9e+JJshFJZXcw4HzM8W+3DHzO5oy9+8rLC53G7x6fEf9A7/gSuSCxuvndzui5qJKftfIM9A=="], "clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="], @@ -2324,16 +2542,24 @@ "common-ancestor-path": ["common-ancestor-path@1.0.1", "", {}, "sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w=="], + "compare-version": ["compare-version@0.1.2", "", {}, "sha512-pJDh5/4wrEnXX/VWRZvruAGHkzKdr46z11OlTPN+VrATlWWhSKewNCJ1futCO5C7eJB3nPMFZA1LeYtcFboZ2A=="], + "compress-commons": ["compress-commons@6.0.2", "", { "dependencies": { "crc-32": "^1.2.0", "crc32-stream": "^6.0.0", "is-stream": "^2.0.1", "normalize-path": "^3.0.0", "readable-stream": "^4.0.0" } }, "sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg=="], + "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="], + "condense-newlines": ["condense-newlines@0.2.1", "", { "dependencies": { "extend-shallow": "^2.0.1", "is-whitespace": "^0.3.0", "kind-of": "^3.0.2" } }, "sha512-P7X+QL9Hb9B/c8HI5BFFKmjgBu2XpQuF98WZ9XkO+dBGgk5XgwiQz7o1SmpglNWId3581UcS0SFAWfoIhMHPfg=="], + "conf": ["conf@14.0.0", "", { "dependencies": { "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "atomically": "^2.0.3", "debounce-fn": "^6.0.0", "dot-prop": "^9.0.0", "env-paths": "^3.0.0", "json-schema-typed": "^8.0.1", "semver": "^7.7.2", "uint8array-extras": "^1.4.0" } }, "sha512-L6BuueHTRuJHQvQVc6YXYZRtN5vJUtOdCTLn0tRYYV5azfbAFcPghB5zEE40mVrV6w7slMTqUfkDomutIK14fw=="], + "confbox": ["confbox@0.2.4", "", {}, "sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ=="], "config-chain": ["config-chain@1.1.13", "", { "dependencies": { "ini": "^1.3.4", "proto-list": "~1.2.1" } }, "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ=="], "consola": ["consola@3.4.2", "", {}, "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA=="], + "console-control-strings": ["console-control-strings@1.1.0", "", {}, "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ=="], + "content-disposition": ["content-disposition@0.5.4", "", { "dependencies": { "safe-buffer": "5.2.1" } }, "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ=="], "content-type": ["content-type@1.0.5", "", {}, "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="], @@ -2346,14 +2572,18 @@ "cookie-signature": ["cookie-signature@1.0.7", "", {}, "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA=="], - "core-util-is": ["core-util-is@1.0.3", "", {}, "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="], + "core-util-is": ["core-util-is@1.0.2", "", {}, "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ=="], "cors": ["cors@2.8.6", "", { "dependencies": { "object-assign": "^4", "vary": "^1" } }, "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw=="], + "crc": ["crc@3.8.0", "", { "dependencies": { "buffer": "^5.1.0" } }, "sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ=="], + "crc-32": ["crc-32@1.2.2", "", { "bin": { "crc32": "bin/crc32.njs" } }, "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ=="], "crc32-stream": ["crc32-stream@6.0.0", "", { "dependencies": { "crc-32": "^1.2.0", "readable-stream": "^4.0.0" } }, "sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g=="], + "cross-dirname": ["cross-dirname@0.1.0", "", {}, "sha512-+R08/oI0nl3vfPcqftZRpytksBXDzOUveBq/NBVx0sUp1axwzPQrKinNx5yd5sxPu8j1wIy8AfnVQ+5eFdha6Q=="], + "cross-fetch": ["cross-fetch@3.2.0", "", { "dependencies": { "node-fetch": "^2.7.0" } }, "sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q=="], "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], @@ -2368,6 +2598,8 @@ "css-what": ["css-what@6.2.2", "", {}, "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA=="], + "css.escape": ["css.escape@1.5.1", "", {}, "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg=="], + "cssesc": ["cssesc@3.0.0", "", { "bin": { "cssesc": "bin/cssesc" } }, "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="], "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="], @@ -2382,18 +2614,30 @@ "db0": ["db0@0.3.4", "", { "peerDependencies": { "@electric-sql/pglite": "*", "@libsql/client": "*", "better-sqlite3": "*", "drizzle-orm": "*", "mysql2": "*", "sqlite3": "*" }, "optionalPeers": ["@electric-sql/pglite", "@libsql/client", "better-sqlite3", "drizzle-orm", "mysql2", "sqlite3"] }, "sha512-RiXXi4WaNzPTHEOu8UPQKMooIbqOEyqA1t7Z6MsdxSCeb8iUC9ko3LcmsLmeUt2SM5bctfArZKkRQggKZz7JNw=="], + "debounce-fn": ["debounce-fn@6.0.0", "", { "dependencies": { "mimic-function": "^5.0.0" } }, "sha512-rBMW+F2TXryBwB54Q0d8drNEI+TfoS9JpNTAoVpukbWEhjXQq4rySFYLaqXMFXwdv61Zb2OHtj5bviSoimqxRQ=="], + "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], "decimal.js": ["decimal.js@10.5.0", "", {}, "sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw=="], "decode-named-character-reference": ["decode-named-character-reference@1.3.0", "", { "dependencies": { "character-entities": "^2.0.0" } }, "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q=="], + "decompress-response": ["decompress-response@6.0.0", "", { "dependencies": { "mimic-response": "^3.1.0" } }, "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ=="], + + "deep-eql": ["deep-eql@5.0.2", "", {}, "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q=="], + + "deep-extend": ["deep-extend@0.6.0", "", {}, "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="], + "deepmerge": ["deepmerge@4.3.1", "", {}, "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A=="], "default-browser": ["default-browser@5.5.0", "", { "dependencies": { "bundle-name": "^4.1.0", "default-browser-id": "^5.0.0" } }, "sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw=="], "default-browser-id": ["default-browser-id@5.0.1", "", {}, "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q=="], + "defaults": ["defaults@1.0.4", "", { "dependencies": { "clone": "^1.0.2" } }, "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A=="], + + "defer-to-connect": ["defer-to-connect@2.0.1", "", {}, "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg=="], + "define-data-property": ["define-data-property@1.1.4", "", { "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", "gopd": "^1.0.1" } }, "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A=="], "define-lazy-prop": ["define-lazy-prop@3.0.0", "", {}, "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg=="], @@ -2404,6 +2648,8 @@ "delayed-stream": ["delayed-stream@1.0.0", "", {}, "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="], + "delegates": ["delegates@1.0.0", "", {}, "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ=="], + "denque": ["denque@2.1.0", "", {}, "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw=="], "depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="], @@ -2418,6 +2664,8 @@ "detect-libc": ["detect-libc@1.0.3", "", { "bin": { "detect-libc": "./bin/detect-libc.js" } }, "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg=="], + "detect-node": ["detect-node@2.1.0", "", {}, "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g=="], + "detect-node-es": ["detect-node-es@1.1.0", "", {}, "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ=="], "deterministic-object-hash": ["deterministic-object-hash@2.0.2", "", { "dependencies": { "base-64": "^1.0.0" } }, "sha512-KxektNH63SrbfUyDiwXqRb1rLwKt33AmMv+5Nhsw1kqZ13SJBRTgZHtGbE+hH3a1mVW1cz+4pqSWVPAtLVXTzQ=="], @@ -2432,14 +2680,22 @@ "diff": ["diff@8.0.2", "", {}, "sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg=="], + "dir-compare": ["dir-compare@4.2.0", "", { "dependencies": { "minimatch": "^3.0.5", "p-limit": "^3.1.0 " } }, "sha512-2xMCmOoMrdQIPHdsTawECdNPwlVFB9zGcz3kuhmBO6U3oU+UQjsue0i8ayLKpgBcm+hcXPMVSGUN9d+pvJ6+VQ=="], + "dir-glob": ["dir-glob@3.0.1", "", { "dependencies": { "path-type": "^4.0.0" } }, "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA=="], "direction": ["direction@2.0.1", "", { "bin": { "direction": "cli.js" } }, "sha512-9S6m9Sukh1cZNknO1CWAr2QAWsbKLafQiyM5gZ7VgXHeuaoUwffKN4q6NC4A/Mf9iiPlOXQEKW/Mv/mh9/3YFA=="], "dlv": ["dlv@1.1.3", "", {}, "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA=="], + "dmg-builder": ["dmg-builder@26.8.1", "", { "dependencies": { "app-builder-lib": "26.8.1", "builder-util": "26.8.1", "fs-extra": "^10.1.0", "iconv-lite": "^0.6.2", "js-yaml": "^4.1.0" }, "optionalDependencies": { "dmg-license": "^1.0.11" } }, "sha512-glMJgnTreo8CFINujtAhCgN96QAqApDMZ8Vl1r8f0QT8QprvC1UCltV4CcWj20YoIyLZx6IUskaJZ0NV8fokcg=="], + + "dmg-license": ["dmg-license@1.0.11", "", { "dependencies": { "@types/plist": "^3.0.1", "@types/verror": "^1.10.3", "ajv": "^6.10.0", "crc": "^3.8.0", "iconv-corefoundation": "^1.1.7", "plist": "^3.0.4", "smart-buffer": "^4.0.2", "verror": "^1.10.0" }, "os": "darwin", "bin": { "dmg-license": "bin/dmg-license.js" } }, "sha512-ZdzmqwKmECOWJpqefloC5OJy1+WZBBse5+MR88z9g9Zn4VY+WYUkAyojmhzJckH5YbbZGcYIuGAkY5/Ys5OM2Q=="], + "dns-packet": ["dns-packet@5.6.1", "", { "dependencies": { "@leichtgewicht/ip-codec": "^2.0.1" } }, "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw=="], + "dom-accessibility-api": ["dom-accessibility-api@0.6.3", "", {}, "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w=="], + "dom-serializer": ["dom-serializer@2.0.0", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", "entities": "^4.2.0" } }, "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg=="], "domelementtype": ["domelementtype@2.3.0", "", {}, "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw=="], @@ -2454,11 +2710,13 @@ "dot-prop": ["dot-prop@8.0.2", "", { "dependencies": { "type-fest": "^3.8.0" } }, "sha512-xaBe6ZT4DHPkg0k4Ytbvn5xoxgpG0jOS1dYxSOwAHPuNLjP3/OzN0gH55SrLqpx8cBfSaVt91lXYkApjb+nYdQ=="], - "dotenv": ["dotenv@17.3.1", "", {}, "sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA=="], + "dotenv": ["dotenv@16.6.1", "", {}, "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow=="], - "drizzle-kit": ["drizzle-kit@1.0.0-beta.12-a5629fb", "", { "dependencies": { "@drizzle-team/brocli": "^0.11.0", "@js-temporal/polyfill": "^0.5.1", "esbuild": "^0.25.10", "tsx": "^4.20.6" }, "bin": { "drizzle-kit": "bin.cjs" } }, "sha512-l+p4QOMvPGYBYEE9NBlU7diu+NSlxuOUwi0I7i01Uj1PpfU0NxhPzaks/9q1MDw4FAPP8vdD0dOhoqosKtRWWQ=="], + "dotenv-expand": ["dotenv-expand@11.0.7", "", { "dependencies": { "dotenv": "^16.4.5" } }, "sha512-zIHwmZPRshsCdpMDyVsqGmgyP0yT8GAgXUnkdAoJisxvf33k7yO6OuoKmcTGuXPWSsm8Oh88nZicRLA9Y0rUeA=="], - "drizzle-orm": ["drizzle-orm@1.0.0-beta.12-a5629fb", "", { "peerDependencies": { "@aws-sdk/client-rds-data": ">=3", "@cloudflare/workers-types": ">=4", "@effect/sql": "^0.48.5", "@effect/sql-pg": "^0.49.7", "@electric-sql/pglite": ">=0.2.0", "@libsql/client": ">=0.10.0", "@libsql/client-wasm": ">=0.10.0", "@neondatabase/serverless": ">=0.10.0", "@op-engineering/op-sqlite": ">=2", "@opentelemetry/api": "^1.4.1", "@planetscale/database": ">=1.13", "@prisma/client": "*", "@sqlitecloud/drivers": ">=1.0.653", "@tidbcloud/serverless": "*", "@tursodatabase/database": ">=0.2.1", "@tursodatabase/database-common": ">=0.2.1", "@tursodatabase/database-wasm": ">=0.2.1", "@types/better-sqlite3": "*", "@types/mssql": "^9.1.4", "@types/pg": "*", "@types/sql.js": "*", "@upstash/redis": ">=1.34.7", "@vercel/postgres": ">=0.8.0", "@xata.io/client": "*", "better-sqlite3": ">=9.3.0", "bun-types": "*", "expo-sqlite": ">=14.0.0", "gel": ">=2", "mssql": "^11.0.1", "mysql2": ">=2", "pg": ">=8", "postgres": ">=3", "sql.js": ">=1", "sqlite3": ">=5" }, "optionalPeers": ["@aws-sdk/client-rds-data", "@cloudflare/workers-types", "@effect/sql", "@effect/sql-pg", "@electric-sql/pglite", "@libsql/client", "@libsql/client-wasm", "@neondatabase/serverless", "@op-engineering/op-sqlite", "@opentelemetry/api", "@planetscale/database", "@prisma/client", "@sqlitecloud/drivers", "@tidbcloud/serverless", "@tursodatabase/database", "@tursodatabase/database-common", "@tursodatabase/database-wasm", "@types/better-sqlite3", "@types/pg", "@types/sql.js", "@upstash/redis", "@vercel/postgres", "@xata.io/client", "better-sqlite3", "bun-types", "expo-sqlite", "gel", "mysql2", "pg", "postgres", "sql.js", "sqlite3"] }, "sha512-wyOAgr9Cy9oEN6z5S0JGhfipLKbRRJtQKgbDO9SXGR9swMBbGNIlXkeMqPRrqYQ8k70mh+7ZJ/eVmJ2F7zR3Vg=="], + "drizzle-kit": ["drizzle-kit@1.0.0-beta.16-ea816b6", "", { "dependencies": { "@drizzle-team/brocli": "^0.11.0", "@js-temporal/polyfill": "^0.5.1", "esbuild": "^0.25.10", "jiti": "^2.6.1" }, "bin": { "drizzle-kit": "bin.cjs" } }, "sha512-GiJQqCNPZP8Kk+i7/sFa3rtXbq26tLDNi3LbMx9aoLuwF2ofk8CS7cySUGdI+r4J3q0a568quC8FZeaFTCw4IA=="], + + "drizzle-orm": ["drizzle-orm@1.0.0-beta.16-ea816b6", "", { "peerDependencies": { "@aws-sdk/client-rds-data": ">=3", "@cloudflare/workers-types": ">=4", "@effect/sql": "^0.48.5", "@effect/sql-pg": "^0.49.7", "@electric-sql/pglite": ">=0.2.0", "@libsql/client": ">=0.10.0", "@libsql/client-wasm": ">=0.10.0", "@neondatabase/serverless": ">=0.10.0", "@op-engineering/op-sqlite": ">=2", "@opentelemetry/api": "^1.4.1", "@planetscale/database": ">=1.13", "@prisma/client": "*", "@sinclair/typebox": ">=0.34.8", "@sqlitecloud/drivers": ">=1.0.653", "@tidbcloud/serverless": "*", "@tursodatabase/database": ">=0.2.1", "@tursodatabase/database-common": ">=0.2.1", "@tursodatabase/database-wasm": ">=0.2.1", "@types/better-sqlite3": "*", "@types/mssql": "^9.1.4", "@types/pg": "*", "@types/sql.js": "*", "@upstash/redis": ">=1.34.7", "@vercel/postgres": ">=0.8.0", "@xata.io/client": "*", "arktype": ">=2.0.0", "better-sqlite3": ">=9.3.0", "bun-types": "*", "expo-sqlite": ">=14.0.0", "gel": ">=2", "mssql": "^11.0.1", "mysql2": ">=2", "pg": ">=8", "postgres": ">=3", "sql.js": ">=1", "sqlite3": ">=5", "typebox": ">=1.0.0", "valibot": ">=1.0.0-beta.7", "zod": "^3.25.0 || ^4.0.0" }, "optionalPeers": ["@aws-sdk/client-rds-data", "@cloudflare/workers-types", "@effect/sql", "@effect/sql-pg", "@electric-sql/pglite", "@libsql/client", "@libsql/client-wasm", "@neondatabase/serverless", "@op-engineering/op-sqlite", "@opentelemetry/api", "@planetscale/database", "@prisma/client", "@sinclair/typebox", "@sqlitecloud/drivers", "@tidbcloud/serverless", "@tursodatabase/database", "@tursodatabase/database-common", "@tursodatabase/database-wasm", "@types/better-sqlite3", "@types/pg", "@types/sql.js", "@upstash/redis", "@vercel/postgres", "@xata.io/client", "arktype", "better-sqlite3", "bun-types", "expo-sqlite", "gel", "mysql2", "pg", "postgres", "sql.js", "sqlite3", "typebox", "valibot", "zod"] }, "sha512-k9gT4f0O9Qvah5YK/zL+FZonQ8TPyVxcG/ojN4dzO0fHP8hs8tBno8lqmJo53g0JLWv3Q2nsTUoyBRKM2TljFw=="], "dset": ["dset@3.1.4", "", {}, "sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA=="], @@ -2472,8 +2730,30 @@ "ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="], + "ejs": ["ejs@3.1.10", "", { "dependencies": { "jake": "^10.8.5" }, "bin": { "ejs": "bin/cli.js" } }, "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA=="], + + "electron": ["electron@40.4.1", "", { "dependencies": { "@electron/get": "^2.0.0", "@types/node": "^24.9.0", "extract-zip": "^2.0.1" }, "bin": { "electron": "cli.js" } }, "sha512-N1ZXybQZL8kYemO8vAeh9nrk4mSvqlAO8xs0QCHkXIvRnuB/7VGwEehjvQbsU5/f4bmTKpG+2GQERe/zmKpudQ=="], + + "electron-builder": ["electron-builder@26.8.1", "", { "dependencies": { "app-builder-lib": "26.8.1", "builder-util": "26.8.1", "builder-util-runtime": "9.5.1", "chalk": "^4.1.2", "ci-info": "^4.2.0", "dmg-builder": "26.8.1", "fs-extra": "^10.1.0", "lazy-val": "^1.0.5", "simple-update-notifier": "2.0.0", "yargs": "^17.6.2" }, "bin": { "electron-builder": "cli.js", "install-app-deps": "install-app-deps.js" } }, "sha512-uWhx1r74NGpCagG0ULs/P9Nqv2nsoo+7eo4fLUOB8L8MdWltq9odW/uuLXMFCDGnPafknYLZgjNX0ZIFRzOQAw=="], + + "electron-builder-squirrel-windows": ["electron-builder-squirrel-windows@26.8.1", "", { "dependencies": { "app-builder-lib": "26.8.1", "builder-util": "26.8.1", "electron-winstaller": "5.4.0" } }, "sha512-o288fIdgPLHA76eDrFADHPoo7VyGkDCYbLV1GzndaMSAVBoZrGvM9m2IehdcVMzdAZJ2eV9bgyissQXHv5tGzA=="], + + "electron-log": ["electron-log@5.4.3", "", {}, "sha512-sOUsM3LjZdugatazSQ/XTyNcw8dfvH1SYhXWiJyfYodAAKOZdHs0txPiLDXFzOZbhXgAgshQkshH2ccq0feyLQ=="], + + "electron-publish": ["electron-publish@26.8.1", "", { "dependencies": { "@types/fs-extra": "^9.0.11", "builder-util": "26.8.1", "builder-util-runtime": "9.5.1", "chalk": "^4.1.2", "form-data": "^4.0.5", "fs-extra": "^10.1.0", "lazy-val": "^1.0.5", "mime": "^2.5.2" } }, "sha512-q+jrSTIh/Cv4eGZa7oVR+grEJo/FoLMYBAnSL5GCtqwUpr1T+VgKB/dn1pnzxIxqD8S/jP1yilT9VrwCqINR4w=="], + + "electron-store": ["electron-store@10.1.0", "", { "dependencies": { "conf": "^14.0.0", "type-fest": "^4.41.0" } }, "sha512-oL8bRy7pVCLpwhmXy05Rh/L6O93+k9t6dqSw0+MckIc3OmCTZm6Mp04Q4f/J0rtu84Ky6ywkR8ivtGOmrq+16w=="], + "electron-to-chromium": ["electron-to-chromium@1.5.286", "", {}, "sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A=="], + "electron-updater": ["electron-updater@6.8.3", "", { "dependencies": { "builder-util-runtime": "9.5.1", "fs-extra": "^10.1.0", "js-yaml": "^4.1.0", "lazy-val": "^1.0.5", "lodash.escaperegexp": "^4.1.2", "lodash.isequal": "^4.5.0", "semver": "~7.7.3", "tiny-typed-emitter": "^2.1.0" } }, "sha512-Z6sgw3jgbikWKXei1ENdqFOxBP0WlXg3TtKfz0rgw2vIZFJUyI4pD7ZN7jrkm7EoMK+tcm/qTnPUdqfZukBlBQ=="], + + "electron-vite": ["electron-vite@5.0.0", "", { "dependencies": { "@babel/core": "^7.28.4", "@babel/plugin-transform-arrow-functions": "^7.27.1", "cac": "^6.7.14", "esbuild": "^0.25.11", "magic-string": "^0.30.19", "picocolors": "^1.1.1" }, "peerDependencies": { "@swc/core": "^1.0.0", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0" }, "optionalPeers": ["@swc/core"], "bin": { "electron-vite": "bin/electron-vite.js" } }, "sha512-OHp/vjdlubNlhNkPkL/+3JD34ii5ov7M0GpuXEVdQeqdQ3ulvVR7Dg/rNBLfS5XPIFwgoBLDf9sjjrL+CuDyRQ=="], + + "electron-window-state": ["electron-window-state@5.0.3", "", { "dependencies": { "jsonfile": "^4.0.0", "mkdirp": "^0.5.1" } }, "sha512-1mNTwCfkolXl3kMf50yW3vE2lZj0y92P/HYWFBrb+v2S/pCka5mdwN3cagKm458A7NjndSwijynXgcLWRodsVg=="], + + "electron-winstaller": ["electron-winstaller@5.4.0", "", { "dependencies": { "@electron/asar": "^3.2.1", "debug": "^4.1.1", "fs-extra": "^7.0.1", "lodash": "^4.17.21", "temp": "^0.9.0" }, "optionalDependencies": { "@electron/windows-sign": "^1.1.2" } }, "sha512-bO3y10YikuUwUuDUQRM4KfwNkKhnpVO7IPdbsrejwN9/AABJzzTQ4GeHwyzNSrVO+tEH3/Np255a3sVZpZDjvg=="], + "emmet": ["emmet@2.4.11", "", { "dependencies": { "@emmetio/abbreviation": "^2.3.3", "@emmetio/css-abbreviation": "^2.1.8" } }, "sha512-23QPJB3moh/U9sT4rQzGgeyyGIrcM+GH5uVYg2C6wZIxAIJq7Ng3QLT79tl8FUwDXhyq9SusfknOrofAKqvgyQ=="], "emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="], @@ -2482,6 +2762,10 @@ "encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="], + "encoding": ["encoding@0.1.13", "", { "dependencies": { "iconv-lite": "^0.6.2" } }, "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A=="], + + "end-of-stream": ["end-of-stream@1.4.5", "", { "dependencies": { "once": "^1.4.0" } }, "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg=="], + "engine.io-client": ["engine.io-client@6.6.4", "", { "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.4.1", "engine.io-parser": "~5.2.1", "ws": "~8.18.3", "xmlhttprequest-ssl": "~2.1.1" } }, "sha512-+kjUJnZGwzewFDw951CDWcwj35vMNf2fcj7xQWOctq1F2i1jkDdVvdFG9kM/BEChymCH36KgjnW0NsL58JYRxw=="], "engine.io-parser": ["engine.io-parser@5.2.3", "", {}, "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q=="], @@ -2490,6 +2774,10 @@ "entities": ["entities@7.0.1", "", {}, "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA=="], + "env-paths": ["env-paths@2.2.1", "", {}, "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A=="], + + "err-code": ["err-code@2.0.3", "", {}, "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA=="], + "error-stack-parser": ["error-stack-parser@2.1.4", "", { "dependencies": { "stackframe": "^1.3.4" } }, "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ=="], "error-stack-parser-es": ["error-stack-parser-es@1.0.5", "", {}, "sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA=="], @@ -2512,6 +2800,8 @@ "es-to-primitive": ["es-to-primitive@1.3.0", "", { "dependencies": { "is-callable": "^1.2.7", "is-date-object": "^1.0.5", "is-symbol": "^1.0.4" } }, "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g=="], + "es6-error": ["es6-error@4.1.1", "", {}, "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg=="], + "esast-util-from-estree": ["esast-util-from-estree@2.0.0", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "devlop": "^1.0.0", "estree-util-visit": "^2.0.0", "unist-util-position-from-estree": "^2.0.0" } }, "sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ=="], "esast-util-from-js": ["esast-util-from-js@2.0.1", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "acorn": "^8.0.0", "esast-util-from-estree": "^2.0.0", "vfile-message": "^4.0.0" } }, "sha512-8Ja+rNJ0Lt56Pcf3TAmpBZjmx8ZcK5Ts4cAzIOjsjevg9oSXJnl6SUQ2EevU8tv3h6ZLWmoKL5H4fgWvdvfETw=="], @@ -2562,8 +2852,12 @@ "exit-hook": ["exit-hook@2.2.1", "", {}, "sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw=="], + "expand-template": ["expand-template@2.0.3", "", {}, "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg=="], + "expect-type": ["expect-type@1.3.0", "", {}, "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA=="], + "exponential-backoff": ["exponential-backoff@3.1.3", "", {}, "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA=="], + "express": ["express@4.22.1", "", { "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", "body-parser": "~1.20.3", "content-disposition": "~0.5.4", "content-type": "~1.0.4", "cookie": "~0.7.1", "cookie-signature": "~1.0.6", "debug": "2.6.9", "depd": "2.0.0", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", "finalhandler": "~1.3.1", "fresh": "~0.5.2", "http-errors": "~2.0.0", "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "~2.4.1", "parseurl": "~1.3.3", "path-to-regexp": "~0.1.12", "proxy-addr": "~2.0.7", "qs": "~6.14.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", "send": "~0.19.0", "serve-static": "~1.16.2", "setprototypeof": "1.2.0", "statuses": "~2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" } }, "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g=="], "express-rate-limit": ["express-rate-limit@7.5.1", "", { "peerDependencies": { "express": ">= 4.11" } }, "sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw=="], @@ -2576,6 +2870,10 @@ "extend-shallow": ["extend-shallow@2.0.1", "", { "dependencies": { "is-extendable": "^0.1.0" } }, "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug=="], + "extract-zip": ["extract-zip@2.0.1", "", { "dependencies": { "debug": "^4.1.1", "get-stream": "^5.1.0", "yauzl": "^2.10.0" }, "optionalDependencies": { "@types/yauzl": "^2.9.1" }, "bin": { "extract-zip": "cli.js" } }, "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg=="], + + "extsprintf": ["extsprintf@1.4.1", "", {}, "sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA=="], + "fast-content-type-parse": ["fast-content-type-parse@3.0.0", "", {}, "sha512-ZvLdcY8P+N8mGQJahJV5G4U88CSvT1rP8ApL6uETe88MBXrBHAkZlSEySdUlyztF7ccb+Znos3TFqaepHxdhBg=="], "fast-decode-uri-component": ["fast-decode-uri-component@1.0.1", "", {}, "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg=="], @@ -2586,6 +2884,8 @@ "fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="], + "fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="], + "fast-json-stringify": ["fast-json-stringify@6.3.0", "", { "dependencies": { "@fastify/merge-json-schemas": "^0.2.0", "ajv": "^8.12.0", "ajv-formats": "^3.0.1", "fast-uri": "^3.0.0", "json-schema-ref-resolver": "^3.0.0", "rfdc": "^1.2.0" } }, "sha512-oRCntNDY/329HJPlmdNLIdogNtt6Vyjb1WuT01Soss3slIdyUp8kAcDU3saQTOquEK8KFVfwIIF7FebxUAu+yA=="], "fast-querystring": ["fast-querystring@1.1.2", "", { "dependencies": { "fast-decode-uri-component": "^1.0.1" } }, "sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg=="], @@ -2600,12 +2900,18 @@ "fastq": ["fastq@1.20.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw=="], + "fd-slicer": ["fd-slicer@1.1.0", "", { "dependencies": { "pend": "~1.2.0" } }, "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g=="], + "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], "fetch-blob": ["fetch-blob@3.2.0", "", { "dependencies": { "node-domexception": "^1.0.0", "web-streams-polyfill": "^3.0.3" } }, "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ=="], "file-type": ["file-type@16.5.4", "", { "dependencies": { "readable-web-to-node-stream": "^3.0.0", "strtok3": "^6.2.4", "token-types": "^4.1.1" } }, "sha512-/yFHK0aGjFEgDJjEKP0pWCplsPFPhwyfwevf/pVxiN0tmE4L9LmwWxWukdJSHdoCli4VgQLehjJtwQBnqmsKcw=="], + "file-uri-to-path": ["file-uri-to-path@1.0.0", "", {}, "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw=="], + + "filelist": ["filelist@1.0.6", "", { "dependencies": { "minimatch": "^5.0.1" } }, "sha512-5giy2PkLYY1cP39p17Ech+2xlpTRL9HLspOfEgm0L6CwBXBTgsK5ou0JtzYuepxkaQ/tvhCFIJ5uXo0OrM2DxA=="], + "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], "finalhandler": ["finalhandler@1.3.2", "", { "dependencies": { "debug": "2.6.9", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "~2.4.1", "parseurl": "~1.3.3", "statuses": "~2.0.2", "unpipe": "~1.0.0" } }, "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg=="], @@ -2646,8 +2952,12 @@ "fresh": ["fresh@0.5.2", "", {}, "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q=="], + "fs-constants": ["fs-constants@1.0.0", "", {}, "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="], + "fs-extra": ["fs-extra@10.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ=="], + "fs-minipass": ["fs-minipass@2.1.0", "", { "dependencies": { "minipass": "^3.0.0" } }, "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg=="], + "fs.realpath": ["fs.realpath@1.0.0", "", {}, "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="], "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], @@ -2660,6 +2970,8 @@ "fuzzysort": ["fuzzysort@3.1.0", "", {}, "sha512-sR9BNCjBg6LNgwvxlBd0sBABvQitkLzoVY9MYYROQVX/FvfJ4Mai9LsGhDgd8qYdds0bY77VzYd5iuB+v5rwQQ=="], + "gauge": ["gauge@4.0.4", "", { "dependencies": { "aproba": "^1.0.3 || ^2.0.0", "color-support": "^1.1.3", "console-control-strings": "^1.1.0", "has-unicode": "^2.0.1", "signal-exit": "^3.0.7", "string-width": "^4.2.3", "strip-ansi": "^6.0.1", "wide-align": "^1.1.5" } }, "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg=="], + "gaxios": ["gaxios@7.1.3", "", { "dependencies": { "extend": "^3.0.2", "https-proxy-agent": "^7.0.1", "node-fetch": "^3.3.2", "rimraf": "^5.0.1" } }, "sha512-YGGyuEdVIjqxkxVH1pUTMY/XtmmsApXrCVv5EU25iX6inEPbV+VakJfLealkBtJN69AQmh1eGOdCl9Sm1UP6XQ=="], "gcp-metadata": ["gcp-metadata@8.1.2", "", { "dependencies": { "gaxios": "^7.0.0", "google-logging-utils": "^1.0.0", "json-bigint": "^1.0.0" } }, "sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg=="], @@ -2682,18 +2994,20 @@ "get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="], - "get-stream": ["get-stream@8.0.1", "", {}, "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA=="], + "get-stream": ["get-stream@5.2.0", "", { "dependencies": { "pump": "^3.0.0" } }, "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA=="], "get-symbol-description": ["get-symbol-description@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6" } }, "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg=="], "get-tsconfig": ["get-tsconfig@4.13.6", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw=="], - "ghostty-web": ["ghostty-web@0.4.0", "", {}, "sha512-0puDBik2qapbD/QQBW9o5ZHfXnZBqZWx/ctBiVtKZ6ZLds4NYb+wZuw1cRLXZk9zYovIQ908z3rvFhexAvc5Hg=="], + "ghostty-web": ["ghostty-web@github:anomalyco/ghostty-web#4af877d", {}, "anomalyco-ghostty-web-4af877d", "sha512-fbEK8mtr7ar4ySsF+JUGjhaZrane7dKphanN+SxHt5XXI6yLMAh/Hpf6sNCOyyVa2UlGCd7YpXG/T2v2RUAX+A=="], "gifwrap": ["gifwrap@0.10.1", "", { "dependencies": { "image-q": "^4.0.0", "omggif": "^1.0.10" } }, "sha512-2760b1vpJHNmLzZ/ubTtNnEx5WApN/PYWJvXvgS+tL1egTTthayFYIQQNi136FLEDcN/IyEY2EcGpIITD6eYUw=="], "giget": ["giget@2.0.0", "", { "dependencies": { "citty": "^0.1.6", "consola": "^3.4.0", "defu": "^6.1.4", "node-fetch-native": "^1.6.6", "nypm": "^0.6.0", "pathe": "^2.0.3" }, "bin": { "giget": "dist/cli.mjs" } }, "sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA=="], + "github-from-package": ["github-from-package@0.0.0", "", {}, "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw=="], + "github-slugger": ["github-slugger@2.0.0", "", {}, "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw=="], "glob": ["glob@13.0.5", "", { "dependencies": { "minimatch": "^10.2.1", "minipass": "^7.1.2", "path-scurry": "^2.0.0" } }, "sha512-BzXxZg24Ibra1pbQ/zE7Kys4Ua1ks7Bn6pKLkVPZ9FZe4JQS6/Q7ef3LG1H+k7lUf5l4T3PLSyYyYJVYUvfgTw=="], @@ -2702,6 +3016,8 @@ "glob-to-regexp": ["glob-to-regexp@0.4.1", "", {}, "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw=="], + "global-agent": ["global-agent@3.0.0", "", { "dependencies": { "boolean": "^3.0.1", "es6-error": "^4.1.1", "matcher": "^3.0.0", "roarr": "^2.15.3", "semver": "^7.3.2", "serialize-error": "^7.0.1" } }, "sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q=="], + "globalthis": ["globalthis@1.0.4", "", { "dependencies": { "define-properties": "^1.2.1", "gopd": "^1.0.1" } }, "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ=="], "globby": ["globby@11.0.4", "", { "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", "fast-glob": "^3.1.1", "ignore": "^5.1.4", "merge2": "^1.3.0", "slash": "^3.0.0" } }, "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg=="], @@ -2712,6 +3028,8 @@ "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="], + "got": ["got@11.8.6", "", { "dependencies": { "@sindresorhus/is": "^4.0.0", "@szmarczak/http-timer": "^4.0.5", "@types/cacheable-request": "^6.0.1", "@types/responselike": "^1.0.0", "cacheable-lookup": "^5.0.3", "cacheable-request": "^7.0.2", "decompress-response": "^6.0.0", "http2-wrapper": "^1.0.0-beta.5.2", "lowercase-keys": "^2.0.0", "p-cancelable": "^2.0.0", "responselike": "^2.0.0" } }, "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g=="], + "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], "graphql": ["graphql@16.12.0", "", {}, "sha512-DKKrynuQRne0PNpEbzuEdHlYOMksHSUI8Zc9Unei5gTsMNA2/vMpoMz/yKba50pejK56qj98qM0SjYxAKi13gQ=="], @@ -2738,6 +3056,8 @@ "has-tostringtag": ["has-tostringtag@1.0.2", "", { "dependencies": { "has-symbols": "^1.0.3" } }, "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw=="], + "has-unicode": ["has-unicode@2.0.1", "", {}, "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ=="], + "hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="], "hast-util-embedded": ["hast-util-embedded@3.0.0", "", { "dependencies": { "@types/hast": "^3.0.0", "hast-util-is-element": "^3.0.0" } }, "sha512-naH8sld4Pe2ep03qqULEtvYr7EjrLK2QHY8KJR6RJkTUjPGObe1vnx585uzem2hGra+s1q08DZZpfgDVYRbaXA=="], @@ -2790,6 +3110,8 @@ "hono-openapi": ["hono-openapi@1.1.2", "", { "peerDependencies": { "@hono/standard-validator": "^0.2.0", "@standard-community/standard-json": "^0.3.5", "@standard-community/standard-openapi": "^0.2.9", "@types/json-schema": "^7.0.15", "hono": "^4.8.3", "openapi-types": "^12.1.3" }, "optionalPeers": ["@hono/standard-validator", "hono"] }, "sha512-toUcO60MftRBxqcVyxsHNYs2m4vf4xkQaiARAucQx3TiBPDtMNNkoh+C4I1vAretQZiGyaLOZNWn1YxfSyUA5g=="], + "hosted-git-info": ["hosted-git-info@4.1.0", "", { "dependencies": { "lru-cache": "^6.0.0" } }, "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA=="], + "html-entities": ["html-entities@2.3.3", "", {}, "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA=="], "html-escaper": ["html-escaper@3.0.3", "", {}, "sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ=="], @@ -2812,6 +3134,8 @@ "http-proxy-agent": ["http-proxy-agent@7.0.2", "", { "dependencies": { "agent-base": "^7.1.0", "debug": "^4.3.4" } }, "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig=="], + "http2-wrapper": ["http2-wrapper@1.0.3", "", { "dependencies": { "quick-lru": "^5.1.1", "resolve-alpn": "^1.0.0" } }, "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg=="], + "https-proxy-agent": ["https-proxy-agent@7.0.6", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "4" } }, "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw=="], "human-signals": ["human-signals@5.0.0", "", {}, "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ=="], @@ -2822,6 +3146,8 @@ "i18next": ["i18next@23.16.8", "", { "dependencies": { "@babel/runtime": "^7.23.2" } }, "sha512-06r/TitrM88Mg5FdUXAKL96dJMzgqLE5dv3ryBAra4KCwD9mJ4ndOTS95ZuymIGoE+2hzfdaMak2X11/es7ZWg=="], + "iconv-corefoundation": ["iconv-corefoundation@1.1.7", "", { "dependencies": { "cli-truncate": "^2.1.0", "node-addon-api": "^1.6.3" }, "os": "darwin" }, "sha512-T10qvkw0zz4wnm560lOEg0PovVqUXuOFhhHAkixw8/sycy7TJt7v/RrkEKEQnAw2viPSJu6iAkErxnzR0g8PpQ=="], + "iconv-lite": ["iconv-lite@0.7.2", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw=="], "ieee754": ["ieee754@1.1.13", "", {}, "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg=="], @@ -2834,6 +3160,14 @@ "import-meta-resolve": ["import-meta-resolve@4.2.0", "", {}, "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg=="], + "imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="], + + "indent-string": ["indent-string@4.0.0", "", {}, "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg=="], + + "infer-owner": ["infer-owner@1.0.4", "", {}, "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A=="], + + "inflight": ["inflight@1.0.6", "", { "dependencies": { "once": "^1.3.0", "wrappy": "1" } }, "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA=="], + "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], "ini": ["ini@1.3.8", "", {}, "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="], @@ -2842,6 +3176,8 @@ "internal-slot": ["internal-slot@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "hasown": "^2.0.2", "side-channel": "^1.1.0" } }, "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw=="], + "ip-address": ["ip-address@10.1.0", "", {}, "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q=="], + "ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="], "iron-webcrypto": ["iron-webcrypto@1.2.1", "", {}, "sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg=="], @@ -2898,6 +3234,10 @@ "is-inside-container": ["is-inside-container@1.0.0", "", { "dependencies": { "is-docker": "^3.0.0" }, "bin": { "is-inside-container": "cli.js" } }, "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA=="], + "is-interactive": ["is-interactive@1.0.0", "", {}, "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w=="], + + "is-lambda": ["is-lambda@1.0.1", "", {}, "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ=="], + "is-map": ["is-map@2.0.3", "", {}, "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw=="], "is-negative-zero": ["is-negative-zero@2.0.3", "", {}, "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw=="], @@ -2926,6 +3266,8 @@ "is-typed-array": ["is-typed-array@1.1.15", "", { "dependencies": { "which-typed-array": "^1.1.16" } }, "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ=="], + "is-unicode-supported": ["is-unicode-supported@0.1.0", "", {}, "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw=="], + "is-weakmap": ["is-weakmap@2.0.2", "", {}, "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w=="], "is-weakref": ["is-weakref@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3" } }, "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew=="], @@ -2942,7 +3284,9 @@ "isarray": ["isarray@1.0.0", "", {}, "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="], - "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], + "isbinaryfile": ["isbinaryfile@5.0.7", "", {}, "sha512-gnWD14Jh3FzS3CPhF0AxNOJ8CxqeblPTADzI38r0wt8ZyQl5edpy75myt08EG2oKvpyiqSqsx+Wkz9vtkbTqYQ=="], + + "isexe": ["isexe@4.0.0", "", {}, "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw=="], "isomorphic-ws": ["isomorphic-ws@5.0.0", "", { "peerDependencies": { "ws": "*" } }, "sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw=="], @@ -2952,6 +3296,8 @@ "jackspeak": ["jackspeak@4.2.3", "", { "dependencies": { "@isaacs/cliui": "^9.0.0" } }, "sha512-ykkVRwrYvFm1nb2AJfKKYPr0emF6IiXDYUaFx4Zn9ZuIH7MrzEZ3sD5RlqGXNRpHtvUHJyOnCEFxOlNDtGo7wg=="], + "jake": ["jake@10.9.4", "", { "dependencies": { "async": "^3.2.6", "filelist": "^1.0.4", "picocolors": "^1.1.1" }, "bin": { "jake": "bin/cli.js" } }, "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA=="], + "jimp": ["jimp@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/diff": "1.6.0", "@jimp/js-bmp": "1.6.0", "@jimp/js-gif": "1.6.0", "@jimp/js-jpeg": "1.6.0", "@jimp/js-png": "1.6.0", "@jimp/js-tiff": "1.6.0", "@jimp/plugin-blit": "1.6.0", "@jimp/plugin-blur": "1.6.0", "@jimp/plugin-circle": "1.6.0", "@jimp/plugin-color": "1.6.0", "@jimp/plugin-contain": "1.6.0", "@jimp/plugin-cover": "1.6.0", "@jimp/plugin-crop": "1.6.0", "@jimp/plugin-displace": "1.6.0", "@jimp/plugin-dither": "1.6.0", "@jimp/plugin-fisheye": "1.6.0", "@jimp/plugin-flip": "1.6.0", "@jimp/plugin-hash": "1.6.0", "@jimp/plugin-mask": "1.6.0", "@jimp/plugin-print": "1.6.0", "@jimp/plugin-quantize": "1.6.0", "@jimp/plugin-resize": "1.6.0", "@jimp/plugin-rotate": "1.6.0", "@jimp/plugin-threshold": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0" } }, "sha512-YcwCHw1kiqEeI5xRpDlPPBGL2EOpBKLwO4yIBJcXWHPj5PnA5urGq0jbyhM5KoNpypQ6VboSoxc9D8HyfvngSg=="], "jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="], @@ -2980,6 +3326,8 @@ "json-bigint": ["json-bigint@1.0.0", "", { "dependencies": { "bignumber.js": "^9.0.0" } }, "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ=="], + "json-buffer": ["json-buffer@3.0.1", "", {}, "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="], + "json-schema": ["json-schema@0.4.0", "", {}, "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA=="], "json-schema-ref-resolver": ["json-schema-ref-resolver@3.0.0", "", { "dependencies": { "dequal": "^2.0.3" } }, "sha512-hOrZIVL5jyYFjzk7+y7n5JDzGlU8rfWDuYyHwGa2WA8/pcmMHezp2xsVwxrebD/Q9t8Nc5DboieySDpCp4WG4A=="], @@ -2990,11 +3338,13 @@ "json-schema-typed": ["json-schema-typed@8.0.2", "", {}, "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA=="], + "json-stringify-safe": ["json-stringify-safe@5.0.1", "", {}, "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA=="], + "json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="], "jsonc-parser": ["jsonc-parser@3.3.1", "", {}, "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ=="], - "jsonfile": ["jsonfile@6.2.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="], + "jsonfile": ["jsonfile@4.0.0", "", { "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg=="], "jsonwebtoken": ["jsonwebtoken@9.0.3", "", { "dependencies": { "jws": "^4.0.1", "lodash.includes": "^4.3.0", "lodash.isboolean": "^3.0.3", "lodash.isinteger": "^4.0.4", "lodash.isnumber": "^3.0.3", "lodash.isplainobject": "^4.0.6", "lodash.isstring": "^4.0.1", "lodash.once": "^4.0.0", "ms": "^2.1.1", "semver": "^7.5.4" } }, "sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g=="], @@ -3006,6 +3356,8 @@ "katex": ["katex@0.16.27", "", { "dependencies": { "commander": "^8.3.0" }, "bin": { "katex": "cli.js" } }, "sha512-aeQoDkuRWSqQN6nSvVCEFvfXdqo1OQiCmmW1kc9xSdjutPv7BGO7pqY9sQRJpMOGrEdfDgF2TfRXe5eUAD2Waw=="], + "keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="], + "kind-of": ["kind-of@6.0.3", "", {}, "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw=="], "kleur": ["kleur@4.1.5", "", {}, "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ=="], @@ -3016,6 +3368,8 @@ "language-map": ["language-map@1.5.0", "", {}, "sha512-n7gFZpe+DwEAX9cXVTw43i3wiudWDDtSn28RmdnS/HCPr284dQI/SztsamWanRr75oSlKSaGbV2nmWCTzGCoVg=="], + "lazy-val": ["lazy-val@1.0.5", "", {}, "sha512-0/BnGCCfyUMkBpeDgWihanIAF9JmZhHBgUhEqzvf+adhNGLoP6TaiI5oF8oyb3I45P+PcnrqihSf01M0l0G5+Q=="], + "lazystream": ["lazystream@1.0.1", "", { "dependencies": { "readable-stream": "^2.0.5" } }, "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw=="], "leac": ["leac@0.6.0", "", {}, "sha512-y+SqErxb8h7nE/fiEX07jsbuhrpO9lL8eca7/Y1nuWV2moNlXhyd59iDGcRf6moVyDMbmTNzL40SUyrFU/yDpg=="], @@ -3052,10 +3406,14 @@ "lodash": ["lodash@4.17.23", "", {}, "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w=="], + "lodash.escaperegexp": ["lodash.escaperegexp@4.1.2", "", {}, "sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw=="], + "lodash.includes": ["lodash.includes@4.3.0", "", {}, "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w=="], "lodash.isboolean": ["lodash.isboolean@3.0.3", "", {}, "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg=="], + "lodash.isequal": ["lodash.isequal@4.5.0", "", {}, "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ=="], + "lodash.isinteger": ["lodash.isinteger@4.0.4", "", {}, "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA=="], "lodash.isnumber": ["lodash.isnumber@3.0.3", "", {}, "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw=="], @@ -3066,6 +3424,8 @@ "lodash.once": ["lodash.once@4.1.1", "", {}, "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg=="], + "log-symbols": ["log-symbols@4.1.0", "", { "dependencies": { "chalk": "^4.1.0", "is-unicode-supported": "^0.1.0" } }, "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg=="], + "loglevelnext": ["loglevelnext@6.0.0", "", {}, "sha512-FDl1AI2sJGjHHG3XKJd6sG3/6ncgiGCQ0YkW46nxe7SfqQq6hujd9CvFXIXtkGBUN83KPZ2KSOJK8q5P0bSSRQ=="], "long": ["long@5.3.2", "", {}, "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA=="], @@ -3074,8 +3434,12 @@ "loose-envify": ["loose-envify@1.4.0", "", { "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, "bin": { "loose-envify": "cli.js" } }, "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="], + "loupe": ["loupe@3.2.1", "", {}, "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ=="], + "lower-case": ["lower-case@2.0.2", "", { "dependencies": { "tslib": "^2.0.3" } }, "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg=="], + "lowercase-keys": ["lowercase-keys@2.0.0", "", {}, "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA=="], + "lru-cache": ["lru-cache@11.2.6", "", {}, "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ=="], "lru.min": ["lru.min@1.1.4", "", {}, "sha512-DqC6n3QQ77zdFpCMASA1a3Jlb64Hv2N2DciFGkO/4L9+q/IpIAuRlKOvCXabtRW6cQf8usbmM6BE/TOPysCdIA=="], @@ -3084,10 +3448,14 @@ "luxon": ["luxon@3.6.1", "", {}, "sha512-tJLxrKJhO2ukZ5z0gyjY1zPh3Rh88Ej9P7jNrZiHMUXHae1yvI2imgOZtL1TO8TW6biMMKfTtAOoEJANgtWBMQ=="], + "lz-string": ["lz-string@1.5.0", "", { "bin": { "lz-string": "bin/bin.js" } }, "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ=="], + "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="], "magicast": ["magicast@0.3.5", "", { "dependencies": { "@babel/parser": "^7.25.4", "@babel/types": "^7.25.4", "source-map-js": "^1.2.0" } }, "sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ=="], + "make-fetch-happen": ["make-fetch-happen@9.1.0", "", { "dependencies": { "agentkeepalive": "^4.1.3", "cacache": "^15.2.0", "http-cache-semantics": "^4.1.0", "http-proxy-agent": "^4.0.1", "https-proxy-agent": "^5.0.0", "is-lambda": "^1.0.1", "lru-cache": "^6.0.0", "minipass": "^3.1.3", "minipass-collect": "^1.0.2", "minipass-fetch": "^1.3.2", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "negotiator": "^0.6.2", "promise-retry": "^2.0.1", "socks-proxy-agent": "^6.0.0", "ssri": "^8.0.0" } }, "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg=="], + "markdown-extensions": ["markdown-extensions@2.0.0", "", {}, "sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q=="], "markdown-table": ["markdown-table@3.0.4", "", {}, "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw=="], @@ -3098,6 +3466,8 @@ "marked-shiki": ["marked-shiki@1.2.1", "", { "peerDependencies": { "marked": ">=7.0.0", "shiki": ">=1.0.0" } }, "sha512-yHxYQhPY5oYaIRnROn98foKhuClark7M373/VpLxiy5TrDu9Jd/LsMwo8w+U91Up4oDb9IXFrP0N1MFRz8W/DQ=="], + "matcher": ["matcher@3.0.0", "", { "dependencies": { "escape-string-regexp": "^4.0.0" } }, "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng=="], + "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], "md-to-react-email": ["md-to-react-email@5.0.0", "", { "dependencies": { "marked": "7.0.4" }, "peerDependencies": { "react": "18.x" } }, "sha512-GdBrBUbAAJHypnuyofYGfVos8oUslxHx69hs3CW9P0L8mS1sT6GnJuMBTlz/Fw+2widiwdavcu9UwyLF/BzZ4w=="], @@ -3234,6 +3604,12 @@ "mimic-fn": ["mimic-fn@4.0.0", "", {}, "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw=="], + "mimic-function": ["mimic-function@5.0.1", "", {}, "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA=="], + + "mimic-response": ["mimic-response@3.1.0", "", {}, "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ=="], + + "min-indent": ["min-indent@1.0.1", "", {}, "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg=="], + "miniflare": ["miniflare@4.20251118.1", "", { "dependencies": { "@cspotcode/source-map-support": "0.8.1", "acorn": "8.14.0", "acorn-walk": "8.3.2", "exit-hook": "2.2.1", "glob-to-regexp": "0.4.1", "sharp": "^0.33.5", "stoppable": "1.1.0", "undici": "7.14.0", "workerd": "1.20251118.0", "ws": "8.18.0", "youch": "4.1.0-beta.10", "zod": "3.22.3" }, "bin": { "miniflare": "bootstrap.js" } }, "sha512-uLSAE/DvOm392fiaig4LOaatxLjM7xzIniFRG5Y3yF9IduOYLLK/pkCPQNCgKQH3ou0YJRHnTN+09LPfqYNTQQ=="], "minimatch": ["minimatch@10.0.3", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.0" } }, "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw=="], @@ -3242,12 +3618,30 @@ "minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="], + "minipass-collect": ["minipass-collect@1.0.2", "", { "dependencies": { "minipass": "^3.0.0" } }, "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA=="], + + "minipass-fetch": ["minipass-fetch@1.4.1", "", { "dependencies": { "minipass": "^3.1.0", "minipass-sized": "^1.0.3", "minizlib": "^2.0.0" }, "optionalDependencies": { "encoding": "^0.1.12" } }, "sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw=="], + + "minipass-flush": ["minipass-flush@1.0.5", "", { "dependencies": { "minipass": "^3.0.0" } }, "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw=="], + + "minipass-pipeline": ["minipass-pipeline@1.2.4", "", { "dependencies": { "minipass": "^3.0.0" } }, "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A=="], + + "minipass-sized": ["minipass-sized@1.0.3", "", { "dependencies": { "minipass": "^3.0.0" } }, "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g=="], + "minizlib": ["minizlib@3.1.0", "", { "dependencies": { "minipass": "^7.1.2" } }, "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw=="], "mkdirp": ["mkdirp@0.5.6", "", { "dependencies": { "minimist": "^1.2.6" }, "bin": { "mkdirp": "bin/cmd.js" } }, "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw=="], + "mkdirp-classic": ["mkdirp-classic@0.5.3", "", {}, "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A=="], + "morphdom": ["morphdom@2.7.8", "", {}, "sha512-D/fR4xgGUyVRbdMGU6Nejea1RFzYxYtyurG4Fbv2Fi/daKlWKuXGLOdXtl+3eIwL110cI2hz1ZojGICjjFLgTg=="], + "motion": ["motion@12.34.5", "", { "dependencies": { "framer-motion": "^12.34.5", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-N06NLJ9IeBHeielRqIvYvjPfXuRdyTxa+9++BgpGa+hY2D7TcMkI6QzV3jaRuv0aZRXgMa7cPy9YcBUBisPzAQ=="], + + "motion-dom": ["motion-dom@12.34.3", "", { "dependencies": { "motion-utils": "^12.29.2" } }, "sha512-sYgFe+pR9aIM7o4fhs2aXtOI+oqlUd33N9Yoxcgo1Fv7M20sRkHtCmzE/VRNIcq7uNJ+qio+Xubt1FXH3pQ+eQ=="], + + "motion-utils": ["motion-utils@12.29.2", "", {}, "sha512-G3kc34H2cX2gI63RqU+cZq+zWRRPSsNIOjpdl9TN4AQwC4sgwYPl/Q/Obf/d53nOm569T0fYK+tcoSV50BWx8A=="], + "mrmime": ["mrmime@2.0.1", "", {}, "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ=="], "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], @@ -3270,6 +3664,8 @@ "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], + "napi-build-utils": ["napi-build-utils@2.0.0", "", {}, "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA=="], + "native-duplexpair": ["native-duplexpair@1.0.0", "", {}, "sha512-E7QQoM+3jvNtlmyfqRZ0/U75VFgCls+fSkbml2MpgWkWyz3ox8Y58gNhfuziuQYGNNQAbFZJQck55LHCnCK6CA=="], "negotiator": ["negotiator@0.6.3", "", {}, "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="], @@ -3284,14 +3680,20 @@ "no-case": ["no-case@3.0.4", "", { "dependencies": { "lower-case": "^2.0.2", "tslib": "^2.0.3" } }, "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg=="], + "node-abi": ["node-abi@3.87.0", "", { "dependencies": { "semver": "^7.3.5" } }, "sha512-+CGM1L1CgmtheLcBuleyYOn7NWPVu0s0EJH2C4puxgEZb9h8QpR9G2dBfZJOAUhi7VQxuBPMd0hiISWcTyiYyQ=="], + "node-addon-api": ["node-addon-api@7.1.1", "", {}, "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ=="], + "node-api-version": ["node-api-version@0.2.1", "", { "dependencies": { "semver": "^7.3.5" } }, "sha512-2xP/IGGMmmSQpI1+O/k72jF/ykvZ89JeuKX3TLJAYPDVLUalrshrLHkeVcCCZqG/eEa635cr8IBYzgnDvM2O8Q=="], + "node-domexception": ["node-domexception@1.0.0", "", {}, "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ=="], "node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="], "node-fetch-native": ["node-fetch-native@1.6.7", "", {}, "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q=="], + "node-gyp": ["node-gyp@8.4.1", "", { "dependencies": { "env-paths": "^2.2.0", "glob": "^7.1.4", "graceful-fs": "^4.2.6", "make-fetch-happen": "^9.1.0", "nopt": "^5.0.0", "npmlog": "^6.0.0", "rimraf": "^3.0.2", "semver": "^7.3.5", "tar": "^6.1.2", "which": "^2.0.2" }, "bin": { "node-gyp": "bin/node-gyp.js" } }, "sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w=="], + "node-gyp-build": ["node-gyp-build@4.8.4", "", { "bin": { "node-gyp-build": "bin.js", "node-gyp-build-optional": "optional.js", "node-gyp-build-test": "build-test.js" } }, "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ=="], "node-html-parser": ["node-html-parser@7.0.2", "", { "dependencies": { "css-select": "^5.1.0", "he": "1.2.0" } }, "sha512-DxodLVh7a6JMkYzWyc8nBX9MaF4M0lLFYkJHlWOiu7+9/I6mwNK9u5TbAMC7qfqDJEPX9OIoWA2A9t4C2l1mUQ=="], @@ -3304,8 +3706,12 @@ "normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="], + "normalize-url": ["normalize-url@6.1.0", "", {}, "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A=="], + "npm-run-path": ["npm-run-path@5.3.0", "", { "dependencies": { "path-key": "^4.0.0" } }, "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ=="], + "npmlog": ["npmlog@6.0.2", "", { "dependencies": { "are-we-there-yet": "^3.0.0", "console-control-strings": "^1.1.0", "gauge": "^4.0.3", "set-blocking": "^2.0.0" } }, "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg=="], + "nth-check": ["nth-check@2.1.1", "", { "dependencies": { "boolbase": "^1.0.0" } }, "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w=="], "nypm": ["nypm@0.6.5", "", { "dependencies": { "citty": "^0.2.0", "pathe": "^2.0.3", "tinyexec": "^1.0.2" }, "bin": { "nypm": "dist/cli.mjs" } }, "sha512-K6AJy1GMVyfyMXRVB88700BJqNUkByijGJM8kEHpLdcAt+vSQAVfkWWHYzuRXHSY6xA2sNc5RjTj0p9rE2izVQ=="], @@ -3356,12 +3762,16 @@ "opentui-spinner": ["opentui-spinner@0.0.6", "", { "dependencies": { "cli-spinners": "^3.3.0" }, "peerDependencies": { "@opentui/core": "^0.1.49", "@opentui/react": "^0.1.49", "@opentui/solid": "^0.1.49", "typescript": "^5" }, "optionalPeers": ["@opentui/react", "@opentui/solid"] }, "sha512-xupLOeVQEAXEvVJCvHkfX6fChDWmJIPHe5jyUrVb8+n4XVTX8mBNhitFfB9v2ZbkC1H2UwPab/ElePHoW37NcA=="], + "ora": ["ora@5.4.1", "", { "dependencies": { "bl": "^4.1.0", "chalk": "^4.1.0", "cli-cursor": "^3.1.0", "cli-spinners": "^2.5.0", "is-interactive": "^1.0.0", "is-unicode-supported": "^0.1.0", "log-symbols": "^4.1.0", "strip-ansi": "^6.0.0", "wcwidth": "^1.0.1" } }, "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ=="], + "own-keys": ["own-keys@1.0.1", "", { "dependencies": { "get-intrinsic": "^1.2.6", "object-keys": "^1.1.1", "safe-push-apply": "^1.0.0" } }, "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg=="], "oxc-minify": ["oxc-minify@0.96.0", "", { "optionalDependencies": { "@oxc-minify/binding-android-arm64": "0.96.0", "@oxc-minify/binding-darwin-arm64": "0.96.0", "@oxc-minify/binding-darwin-x64": "0.96.0", "@oxc-minify/binding-freebsd-x64": "0.96.0", "@oxc-minify/binding-linux-arm-gnueabihf": "0.96.0", "@oxc-minify/binding-linux-arm-musleabihf": "0.96.0", "@oxc-minify/binding-linux-arm64-gnu": "0.96.0", "@oxc-minify/binding-linux-arm64-musl": "0.96.0", "@oxc-minify/binding-linux-riscv64-gnu": "0.96.0", "@oxc-minify/binding-linux-s390x-gnu": "0.96.0", "@oxc-minify/binding-linux-x64-gnu": "0.96.0", "@oxc-minify/binding-linux-x64-musl": "0.96.0", "@oxc-minify/binding-wasm32-wasi": "0.96.0", "@oxc-minify/binding-win32-arm64-msvc": "0.96.0", "@oxc-minify/binding-win32-x64-msvc": "0.96.0" } }, "sha512-dXeeGrfPJJ4rMdw+NrqiCRtbzVX2ogq//R0Xns08zql2HjV3Zi2SBJ65saqfDaJzd2bcHqvGWH+M44EQCHPAcA=="], "oxc-transform": ["oxc-transform@0.96.0", "", { "optionalDependencies": { "@oxc-transform/binding-android-arm64": "0.96.0", "@oxc-transform/binding-darwin-arm64": "0.96.0", "@oxc-transform/binding-darwin-x64": "0.96.0", "@oxc-transform/binding-freebsd-x64": "0.96.0", "@oxc-transform/binding-linux-arm-gnueabihf": "0.96.0", "@oxc-transform/binding-linux-arm-musleabihf": "0.96.0", "@oxc-transform/binding-linux-arm64-gnu": "0.96.0", "@oxc-transform/binding-linux-arm64-musl": "0.96.0", "@oxc-transform/binding-linux-riscv64-gnu": "0.96.0", "@oxc-transform/binding-linux-s390x-gnu": "0.96.0", "@oxc-transform/binding-linux-x64-gnu": "0.96.0", "@oxc-transform/binding-linux-x64-musl": "0.96.0", "@oxc-transform/binding-wasm32-wasi": "0.96.0", "@oxc-transform/binding-win32-arm64-msvc": "0.96.0", "@oxc-transform/binding-win32-x64-msvc": "0.96.0" } }, "sha512-dQPNIF+gHpSkmC0+Vg9IktNyhcn28Y8R3eTLyzn52UNymkasLicl3sFAtz7oEVuFmCpgGjaUTKkwk+jW2cHpDQ=="], + "p-cancelable": ["p-cancelable@2.1.1", "", {}, "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg=="], + "p-defer": ["p-defer@3.0.0", "", {}, "sha512-ugZxsxmtTln604yeYd29EGrNhazN2lywetzpKhfmQjW/VJmhpDmWbiX+h0zL8V91R0UXkhb3KtPmyq9PZw3aYw=="], "p-finally": ["p-finally@1.0.0", "", {}, "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow=="], @@ -3370,6 +3780,8 @@ "p-locate": ["p-locate@4.1.0", "", { "dependencies": { "p-limit": "^2.2.0" } }, "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A=="], + "p-map": ["p-map@4.0.0", "", { "dependencies": { "aggregate-error": "^3.0.0" } }, "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ=="], + "p-queue": ["p-queue@8.1.1", "", { "dependencies": { "eventemitter3": "^5.0.1", "p-timeout": "^6.1.2" } }, "sha512-aNZ+VfjobsWryoiPnEApGGmf5WmNsCo9xu8dfaYamG5qaLP7ClhLN6NgsFe6SwJ2UbLEBK5dv9x8Mn5+RVhMWQ=="], "p-retry": ["p-retry@4.6.2", "", { "dependencies": { "@types/retry": "0.12.0", "retry": "^0.13.1" } }, "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ=="], @@ -3414,6 +3826,8 @@ "path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="], + "path-is-absolute": ["path-is-absolute@1.0.1", "", {}, "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg=="], + "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], "path-parse": ["path-parse@1.0.7", "", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="], @@ -3426,10 +3840,16 @@ "pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], + "pathval": ["pathval@2.0.1", "", {}, "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ=="], + + "pe-library": ["pe-library@0.4.1", "", {}, "sha512-eRWB5LBz7PpDu4PUlwT0PhnQfTQJlDDdPa35urV4Osrm0t0AqQFGn+UIkU3klZvwJ8KPO3VbBFsXquA6p6kqZw=="], + "peberminta": ["peberminta@0.9.0", "", {}, "sha512-XIxfHpEuSJbITd1H3EeQwpcZbTLHc+VVr8ANI9t5sit565tsI4/xK3KWTUFE2e6QiangUkh3B0jihzmGnNrRsQ=="], "peek-readable": ["peek-readable@4.1.0", "", {}, "sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg=="], + "pend": ["pend@1.2.0", "", {}, "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg=="], + "perfect-debounce": ["perfect-debounce@2.1.0", "", {}, "sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g=="], "piccolore": ["piccolore@0.1.3", "", {}, "sha512-o8bTeDWjE086iwKrROaDf31K0qC/BENdm15/uH9usSC/uZjJOKb2YGiVHfLY4GhwsERiPI1jmwI2XrA7ACOxVw=="], @@ -3464,6 +3884,8 @@ "playwright-core": ["playwright-core@1.57.0", "", { "bin": { "playwright-core": "cli.js" } }, "sha512-agTcKlMw/mjBWOnD6kFZttAAGHgi/Nw0CZ2o6JqWSbMlI219lAFLZZCyqByTsvVAJq5XA5H8cA6PrvBRpBWEuQ=="], + "plist": ["plist@3.1.0", "", { "dependencies": { "@xmldom/xmldom": "^0.8.8", "base64-js": "^1.5.1", "xmlbuilder": "^15.1.1" } }, "sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ=="], + "pngjs": ["pngjs@7.0.0", "", {}, "sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow=="], "possible-typed-array-names": ["possible-typed-array-names@1.1.0", "", {}, "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg=="], @@ -3486,24 +3908,40 @@ "postgres": ["postgres@3.4.7", "", {}, "sha512-Jtc2612XINuBjIl/QTWsV5UvE8UHuNblcO3vVADSrKsrc6RqGX6lOW1cEo3CM2v0XG4Nat8nI+YM7/f26VxXLw=="], + "postject": ["postject@1.0.0-alpha.6", "", { "dependencies": { "commander": "^9.4.0" }, "bin": { "postject": "dist/cli.js" } }, "sha512-b9Eb8h2eVqNE8edvKdwqkrY6O7kAwmI8kcnBv1NScolYJbo59XUF0noFq+lxbC1yN20bmC0WBEbDC5H/7ASb0A=="], + "powershell-utils": ["powershell-utils@0.1.0", "", {}, "sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A=="], + "prebuild-install": ["prebuild-install@7.1.3", "", { "dependencies": { "detect-libc": "^2.0.0", "expand-template": "^2.0.3", "github-from-package": "0.0.0", "minimist": "^1.2.3", "mkdirp-classic": "^0.5.3", "napi-build-utils": "^2.0.0", "node-abi": "^3.3.0", "pump": "^3.0.0", "rc": "^1.2.7", "simple-get": "^4.0.0", "tar-fs": "^2.0.0", "tunnel-agent": "^0.6.0" }, "bin": { "prebuild-install": "bin.js" } }, "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug=="], + "prettier": ["prettier@3.6.2", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ=="], "pretty": ["pretty@2.0.0", "", { "dependencies": { "condense-newlines": "^0.2.1", "extend-shallow": "^2.0.1", "js-beautify": "^1.6.12" } }, "sha512-G9xUchgTEiNpormdYBl+Pha50gOUovT18IvAe7EYMZ1/f9W/WWMPRn+xI68yXNMUk3QXHDwo/1wV/4NejVNe1w=="], + "pretty-format": ["pretty-format@27.5.1", "", { "dependencies": { "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", "react-is": "^17.0.1" } }, "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ=="], + "prismjs": ["prismjs@1.30.0", "", {}, "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw=="], + "proc-log": ["proc-log@5.0.0", "", {}, "sha512-Azwzvl90HaF0aCz1JrDdXQykFakSSNPaPoiZ9fm5qJIMHioDZEi7OAdRwSm6rSoPtY3Qutnm3L7ogmg3dc+wbQ=="], + "process": ["process@0.11.10", "", {}, "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A=="], "process-nextick-args": ["process-nextick-args@2.0.1", "", {}, "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="], "process-warning": ["process-warning@5.0.0", "", {}, "sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA=="], + "progress": ["progress@2.0.3", "", {}, "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA=="], + + "promise-inflight": ["promise-inflight@1.0.1", "", {}, "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g=="], + + "promise-retry": ["promise-retry@2.0.1", "", { "dependencies": { "err-code": "^2.0.2", "retry": "^0.12.0" } }, "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g=="], + "promise.allsettled": ["promise.allsettled@1.0.7", "", { "dependencies": { "array.prototype.map": "^1.0.5", "call-bind": "^1.0.2", "define-properties": "^1.2.0", "es-abstract": "^1.22.1", "get-intrinsic": "^1.2.1", "iterate-value": "^1.0.2" } }, "sha512-hezvKvQQmsFkOdrZfYxUxkyxl8mgFQeT259Ajj9PXdbg9VzBCWrItOev72JyWxkCD5VSSqAeHmlN3tWx4DlmsA=="], "prompts": ["prompts@2.4.2", "", { "dependencies": { "kleur": "^3.0.3", "sisteransi": "^1.0.5" } }, "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q=="], + "proper-lockfile": ["proper-lockfile@4.1.2", "", { "dependencies": { "graceful-fs": "^4.2.4", "retry": "^0.12.0", "signal-exit": "^3.0.2" } }, "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA=="], + "property-information": ["property-information@7.1.0", "", {}, "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ=="], "proto-list": ["proto-list@1.2.4", "", {}, "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA=="], @@ -3512,6 +3950,8 @@ "proxy-from-env": ["proxy-from-env@1.1.0", "", {}, "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="], + "pump": ["pump@3.0.4", "", { "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" } }, "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA=="], + "punycode": ["punycode@1.3.2", "", {}, "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw=="], "qs": ["qs@6.15.0", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ=="], @@ -3524,18 +3964,26 @@ "quick-format-unescaped": ["quick-format-unescaped@4.0.4", "", {}, "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg=="], + "quick-lru": ["quick-lru@5.1.1", "", {}, "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA=="], + "radix3": ["radix3@1.1.2", "", {}, "sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA=="], "range-parser": ["range-parser@1.2.1", "", {}, "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="], "raw-body": ["raw-body@2.5.3", "", { "dependencies": { "bytes": "~3.1.2", "http-errors": "~2.0.1", "iconv-lite": "~0.4.24", "unpipe": "~1.0.0" } }, "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA=="], + "rc": ["rc@1.2.8", "", { "dependencies": { "deep-extend": "^0.6.0", "ini": "~1.3.0", "minimist": "^1.2.0", "strip-json-comments": "~2.0.1" }, "bin": { "rc": "./cli.js" } }, "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw=="], + "rc9": ["rc9@2.1.2", "", { "dependencies": { "defu": "^6.1.4", "destr": "^2.0.3" } }, "sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg=="], "react": ["react@18.2.0", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ=="], + "react-docgen-typescript": ["react-docgen-typescript@2.4.0", "", { "peerDependencies": { "typescript": ">= 4.3.x" } }, "sha512-ZtAp5XTO5HRzQctjPU0ybY0RRCQO19X/8fxn3w7y2VVTUbGHDKULPTL4ky3vB05euSgG5NpALhEhDPvQ56wvXg=="], + "react-dom": ["react-dom@18.2.0", "", { "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.0" }, "peerDependencies": { "react": "^18.2.0" } }, "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g=="], + "react-is": ["react-is@17.0.2", "", {}, "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="], + "react-refresh": ["react-refresh@0.17.0", "", {}, "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ=="], "react-remove-scroll": ["react-remove-scroll@2.5.5", "", { "dependencies": { "react-remove-scroll-bar": "^2.3.3", "react-style-singleton": "^2.2.1", "tslib": "^2.1.0", "use-callback-ref": "^1.3.0", "use-sidecar": "^1.1.2" }, "peerDependencies": { "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", "react": "^16.8.0 || ^17.0.0 || ^18.0.0" }, "optionalPeers": ["@types/react"] }, "sha512-ImKhrzJJsyXJfBZ4bzu8Bwpka14c/fQt0k+cyFp/PBhTfyDnU5hjOtM4AG/0AMyy8oKzOTR0lDgJIM7pYXI0kw=="], @@ -3548,6 +3996,8 @@ "react-style-singleton": ["react-style-singleton@2.2.3", "", { "dependencies": { "get-nonce": "^1.0.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ=="], + "read-binary-file-arch": ["read-binary-file-arch@1.0.6", "", { "dependencies": { "debug": "^4.3.4" }, "bin": { "read-binary-file-arch": "cli.js" } }, "sha512-BNg9EN3DD3GsDXX7Aa8O4p92sryjkmzYYgmgTAc6CA4uGLEDzFfxOxugu21akOxpcXHiEgsYkC6nPsQvLLLmEg=="], + "read-cache": ["read-cache@1.0.0", "", { "dependencies": { "pify": "^2.3.0" } }, "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA=="], "readable-stream": ["readable-stream@4.7.0", "", { "dependencies": { "abort-controller": "^3.0.0", "buffer": "^6.0.3", "events": "^3.3.0", "process": "^0.11.10", "string_decoder": "^1.3.0" } }, "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg=="], @@ -3560,6 +4010,8 @@ "real-require": ["real-require@0.2.0", "", {}, "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg=="], + "recast": ["recast@0.23.11", "", { "dependencies": { "ast-types": "^0.16.1", "esprima": "~4.0.0", "source-map": "~0.6.1", "tiny-invariant": "^1.3.3", "tslib": "^2.0.1" } }, "sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA=="], + "recma-build-jsx": ["recma-build-jsx@1.0.0", "", { "dependencies": { "@types/estree": "^1.0.0", "estree-util-build-jsx": "^3.0.0", "vfile": "^6.0.0" } }, "sha512-8GtdyqaBcDfva+GUKDr3nev3VpKAhup1+RvkMvUxURHpW7QyIvk9F5wz7Vzo06CEMSilw6uArgRqhpiUcWp8ew=="], "recma-jsx": ["recma-jsx@1.0.1", "", { "dependencies": { "acorn-jsx": "^5.0.0", "estree-util-to-js": "^2.0.0", "recma-parse": "^1.0.0", "recma-stringify": "^1.0.0", "unified": "^11.0.0" }, "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-huSIy7VU2Z5OLv6oFLosQGGDqPqdO1iq6bWNAdhzMxSJP7RAso4fCZ1cKu8j9YHCZf3TPrq4dw3okhrylgcd7w=="], @@ -3568,6 +4020,8 @@ "recma-stringify": ["recma-stringify@1.0.0", "", { "dependencies": { "@types/estree": "^1.0.0", "estree-util-to-js": "^2.0.0", "unified": "^11.0.0", "vfile": "^6.0.0" } }, "sha512-cjwII1MdIIVloKvC9ErQ+OgAtwHBmcZ0Bg4ciz78FtbT8In39aAYbaA7zvxQ61xVMSPE8WxhLwLbhif4Js2C+g=="], + "redent": ["redent@3.0.0", "", { "dependencies": { "indent-string": "^4.0.0", "strip-indent": "^3.0.0" } }, "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg=="], + "reflect.getprototypeof": ["reflect.getprototypeof@1.0.10", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.9", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.7", "get-proto": "^1.0.1", "which-builtin-type": "^1.2.1" } }, "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw=="], "regex": ["regex@6.1.0", "", { "dependencies": { "regex-utilities": "^2.3.0" } }, "sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg=="], @@ -3618,16 +4072,24 @@ "require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="], + "resedit": ["resedit@1.7.2", "", { "dependencies": { "pe-library": "^0.4.1" } }, "sha512-vHjcY2MlAITJhC0eRD/Vv8Vlgmu9Sd3LX9zZvtGzU5ZImdTN3+d6e/4mnTyV8vEbyf1sgNIrWxhWlrys52OkEA=="], + "reselect": ["reselect@4.1.8", "", {}, "sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ=="], "resolve": ["resolve@1.22.11", "", { "dependencies": { "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ=="], + "resolve-alpn": ["resolve-alpn@1.2.1", "", {}, "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g=="], + "resolve-cwd": ["resolve-cwd@3.0.0", "", { "dependencies": { "resolve-from": "^5.0.0" } }, "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg=="], "resolve-from": ["resolve-from@5.0.0", "", {}, "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="], "resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="], + "responselike": ["responselike@2.0.1", "", { "dependencies": { "lowercase-keys": "^2.0.0" } }, "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw=="], + + "restore-cursor": ["restore-cursor@3.1.0", "", { "dependencies": { "onetime": "^5.1.0", "signal-exit": "^3.0.2" } }, "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA=="], + "restructure": ["restructure@3.0.2", "", {}, "sha512-gSfoiOEA0VPE6Tukkrr7I0RBdE0s7H1eFCDBk05l1KIQT1UIKNc5JZy6jdyW6eYH3aR3g5b3PuL77rq0hvwtAw=="], "ret": ["ret@0.5.0", "", {}, "sha512-I1XxrZSQ+oErkRR4jYbAyEEu2I0avBvvMM5JN+6EBprOGRCs63ENqZ3vjavq8fBw2+62G5LF5XelKwuJpcvcxw=="], @@ -3640,7 +4102,7 @@ "retext-stringify": ["retext-stringify@4.0.0", "", { "dependencies": { "@types/nlcst": "^2.0.0", "nlcst-to-string": "^4.0.0", "unified": "^11.0.0" } }, "sha512-rtfN/0o8kL1e+78+uxPTqu1Klt0yPzKuQ2BfWwwfgIUSayyzxpM1PJzkKt4V8803uB9qSy32MvI7Xep9khTpiA=="], - "retry": ["retry@0.13.1", "", {}, "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg=="], + "retry": ["retry@0.12.0", "", {}, "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow=="], "reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="], @@ -3648,6 +4110,8 @@ "rimraf": ["rimraf@5.0.10", "", { "dependencies": { "glob": "^10.3.7" }, "bin": { "rimraf": "dist/esm/bin.mjs" } }, "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ=="], + "roarr": ["roarr@2.15.4", "", { "dependencies": { "boolean": "^3.0.1", "detect-node": "^2.0.4", "globalthis": "^1.0.1", "json-stringify-safe": "^5.0.1", "semver-compare": "^1.0.0", "sprintf-js": "^1.1.2" } }, "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A=="], + "rollup": ["rollup@4.57.1", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.57.1", "@rollup/rollup-android-arm64": "4.57.1", "@rollup/rollup-darwin-arm64": "4.57.1", "@rollup/rollup-darwin-x64": "4.57.1", "@rollup/rollup-freebsd-arm64": "4.57.1", "@rollup/rollup-freebsd-x64": "4.57.1", "@rollup/rollup-linux-arm-gnueabihf": "4.57.1", "@rollup/rollup-linux-arm-musleabihf": "4.57.1", "@rollup/rollup-linux-arm64-gnu": "4.57.1", "@rollup/rollup-linux-arm64-musl": "4.57.1", "@rollup/rollup-linux-loong64-gnu": "4.57.1", "@rollup/rollup-linux-loong64-musl": "4.57.1", "@rollup/rollup-linux-ppc64-gnu": "4.57.1", "@rollup/rollup-linux-ppc64-musl": "4.57.1", "@rollup/rollup-linux-riscv64-gnu": "4.57.1", "@rollup/rollup-linux-riscv64-musl": "4.57.1", "@rollup/rollup-linux-s390x-gnu": "4.57.1", "@rollup/rollup-linux-x64-gnu": "4.57.1", "@rollup/rollup-linux-x64-musl": "4.57.1", "@rollup/rollup-openbsd-x64": "4.57.1", "@rollup/rollup-openharmony-arm64": "4.57.1", "@rollup/rollup-win32-arm64-msvc": "4.57.1", "@rollup/rollup-win32-ia32-msvc": "4.57.1", "@rollup/rollup-win32-x64-gnu": "4.57.1", "@rollup/rollup-win32-x64-msvc": "4.57.1", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A=="], "rou3": ["rou3@0.7.12", "", {}, "sha512-iFE4hLDuloSWcD7mjdCDhx2bKcIsYbtOTpfH5MHHLSKMOUyjqQXTeZVa289uuwEGEKFoE/BAPbhaU4B774nceg=="], @@ -3674,6 +4138,8 @@ "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], + "sanitize-filename": ["sanitize-filename@1.6.3", "", { "dependencies": { "truncate-utf8-bytes": "^1.0.0" } }, "sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg=="], + "sax": ["sax@1.2.1", "", {}, "sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA=="], "scheduler": ["scheduler@0.23.2", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ=="], @@ -3686,16 +4152,22 @@ "semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="], + "semver-compare": ["semver-compare@1.0.0", "", {}, "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow=="], + "send": ["send@0.19.2", "", { "dependencies": { "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "~0.5.2", "http-errors": "~2.0.1", "mime": "1.6.0", "ms": "2.1.3", "on-finished": "~2.4.1", "range-parser": "~1.2.1", "statuses": "~2.0.2" } }, "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg=="], "seq-queue": ["seq-queue@0.0.5", "", {}, "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q=="], + "serialize-error": ["serialize-error@7.0.1", "", { "dependencies": { "type-fest": "^0.13.1" } }, "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw=="], + "seroval": ["seroval@1.3.2", "", {}, "sha512-RbcPH1n5cfwKrru7v7+zrZvjLurgHhGyso3HTyGtRivGWgYjbOmGuivCQaORNELjNONoK35nj28EoWul9sb1zQ=="], "seroval-plugins": ["seroval-plugins@1.3.3", "", { "peerDependencies": { "seroval": "^1.0" } }, "sha512-16OL3NnUBw8JG1jBLUoZJsLnQq0n5Ua6aHalhJK4fMQkz1lqR7Osz1sA30trBtd9VUDc2NgkuRCn8+/pBwqZ+w=="], "serve-static": ["serve-static@1.16.3", "", { "dependencies": { "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", "send": "~0.19.1" } }, "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA=="], + "set-blocking": ["set-blocking@2.0.0", "", {}, "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw=="], + "set-cookie-parser": ["set-cookie-parser@2.7.2", "", {}, "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw=="], "set-function-length": ["set-function-length@1.2.2", "", { "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", "gopd": "^1.0.1", "has-property-descriptors": "^1.0.2" } }, "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg=="], @@ -3728,8 +4200,14 @@ "signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], + "simple-concat": ["simple-concat@1.0.1", "", {}, "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q=="], + + "simple-get": ["simple-get@4.0.1", "", { "dependencies": { "decompress-response": "^6.0.0", "once": "^1.3.1", "simple-concat": "^1.0.0" } }, "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA=="], + "simple-swizzle": ["simple-swizzle@0.2.4", "", { "dependencies": { "is-arrayish": "^0.3.1" } }, "sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw=="], + "simple-update-notifier": ["simple-update-notifier@2.0.0", "", { "dependencies": { "semver": "^7.5.3" } }, "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w=="], + "simple-xml-to-json": ["simple-xml-to-json@1.2.3", "", {}, "sha512-kWJDCr9EWtZ+/EYYM5MareWj2cRnZGF93YDNpH4jQiHB+hBIZnfPFSQiVMzZOdk+zXWqTZ/9fTeQNu2DqeiudA=="], "sisteransi": ["sisteransi@1.0.5", "", {}, "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg=="], @@ -3738,12 +4216,20 @@ "slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="], + "slice-ansi": ["slice-ansi@3.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "astral-regex": "^2.0.0", "is-fullwidth-code-point": "^3.0.0" } }, "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ=="], + + "smart-buffer": ["smart-buffer@4.2.0", "", {}, "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg=="], + "smol-toml": ["smol-toml@1.6.0", "", {}, "sha512-4zemZi0HvTnYwLfrpk/CF9LOd9Lt87kAt50GnqhMpyF9U3poDAP2+iukq2bZsO/ufegbYehBkqINbsWxj4l4cw=="], "socket.io-client": ["socket.io-client@4.8.3", "", { "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.4.1", "engine.io-client": "~6.6.1", "socket.io-parser": "~4.2.4" } }, "sha512-uP0bpjWrjQmUt5DTHq9RuoCBdFJF10cdX9X+a368j/Ft0wmaVgxlrjvK3kjvgCODOMMOz9lcaRzxmso0bTWZ/g=="], "socket.io-parser": ["socket.io-parser@4.2.5", "", { "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.4.1" } }, "sha512-bPMmpy/5WWKHea5Y/jYAP6k74A+hvmRCQaJuJB6I/ML5JZq/KfNieUVo/3Mh7SAqn7TyFdIo6wqYHInG1MU1bQ=="], + "socks": ["socks@2.8.7", "", { "dependencies": { "ip-address": "^10.0.1", "smart-buffer": "^4.2.0" } }, "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A=="], + + "socks-proxy-agent": ["socks-proxy-agent@6.2.1", "", { "dependencies": { "agent-base": "^6.0.2", "debug": "^4.3.3", "socks": "^2.6.2" } }, "sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ=="], + "solid-js": ["solid-js@1.9.10", "", { "dependencies": { "csstype": "^3.1.0", "seroval": "~1.3.0", "seroval-plugins": "~1.3.0" } }, "sha512-Coz956cos/EPDlhs6+jsdTxKuJDPT7B5SVIWgABwROyxjY7Xbr8wkzD68Et+NxnV7DLJ3nJdAC2r9InuV/4Jew=="], "solid-list": ["solid-list@0.3.0", "", { "dependencies": { "@corvu/utils": "~0.4.0" }, "peerDependencies": { "solid-js": "^1.8" } }, "sha512-t4hx/F/l8Vmq+ib9HtZYl7Z9F1eKxq3eKJTXlvcm7P7yI4Z8O7QSOOEVHb/K6DD7M0RxzVRobK/BS5aSfLRwKg=="], @@ -3760,7 +4246,7 @@ "sonic-boom": ["sonic-boom@4.2.1", "", { "dependencies": { "atomic-sleep": "^1.0.0" } }, "sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q=="], - "source-map": ["source-map@0.7.6", "", {}, "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ=="], + "source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], @@ -3772,10 +4258,14 @@ "sprintf-js": ["sprintf-js@1.1.3", "", {}, "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA=="], + "sqlite3": ["sqlite3@5.1.7", "", { "dependencies": { "bindings": "^1.5.0", "node-addon-api": "^7.0.0", "prebuild-install": "^7.1.1", "tar": "^6.1.11" }, "optionalDependencies": { "node-gyp": "8.x" } }, "sha512-GGIyOiFaG+TUra3JIfkI/zGP8yZYLPQ0pl1bH+ODjiX57sPhrLU5sQJn1y9bDKZUFYkX1crlrPfSYt0BKKdkog=="], + "sqlstring": ["sqlstring@2.3.3", "", {}, "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg=="], "srvx": ["srvx@0.9.8", "", { "bin": { "srvx": "bin/srvx.mjs" } }, "sha512-RZaxTKJEE/14HYn8COLuUOJAt0U55N9l1Xf6jj+T0GoA01EUH1Xz5JtSUOI+EHn+AEgPCVn7gk6jHJffrr06fQ=="], + "ssri": ["ssri@8.0.1", "", { "dependencies": { "minipass": "^3.1.1" } }, "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ=="], + "sst": ["sst@3.18.10", "", { "dependencies": { "aws-sdk": "2.1692.0", "aws4fetch": "1.0.18", "jose": "5.2.3", "opencontrol": "0.0.6", "openid-client": "5.6.4" }, "optionalDependencies": { "sst-darwin-arm64": "3.18.10", "sst-darwin-x64": "3.18.10", "sst-linux-arm64": "3.18.10", "sst-linux-x64": "3.18.10", "sst-linux-x86": "3.18.10", "sst-win32-arm64": "3.18.10", "sst-win32-x64": "3.18.10", "sst-win32-x86": "3.18.10" }, "bin": { "sst": "bin/sst.mjs" } }, "sha512-SY+ldeJ9K5E9q+DhjXA3e2W3BEOzBwkE3IyLSD71uA3/5nRhUAST31iOWEpW36LbIvSQ9uOVDFcebztoLJ8s7w=="], "sst-darwin-arm64": ["sst-darwin-arm64@3.18.10", "", { "os": "darwin", "cpu": "arm64" }, "sha512-N3MwIpMZhhdZKDqLp9ZQNlwkWix5+q+N0PWstuTomYwgZOxCCe6u9IIsoIszSk+GAJJN/jvGZyLiXKeV4iiQvw=="], @@ -3800,6 +4290,8 @@ "stage-js": ["stage-js@1.0.1", "", {}, "sha512-cz14aPp/wY0s3bkb/B93BPP5ZAEhgBbRmAT3CCDqert8eCAqIpQ0RB2zpK8Ksxf+Pisl5oTzvPHtL4CVzzeHcw=="], + "stat-mode": ["stat-mode@1.0.0", "", {}, "sha512-jH9EhtKIjuXZ2cWxmXS8ZP80XyC3iasQxMDV8jzhNJpfDb7VbQLVW4Wvsxz9QZvzV+G4YoSfBUVKDOyxLzi/sg=="], + "statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="], "std-env": ["std-env@3.10.0", "", {}, "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg=="], @@ -3808,6 +4300,10 @@ "stoppable": ["stoppable@1.1.0", "", {}, "sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw=="], + "storybook": ["storybook@10.2.13", "", { "dependencies": { "@storybook/global": "^5.0.0", "@storybook/icons": "^2.0.1", "@testing-library/jest-dom": "^6.6.3", "@testing-library/user-event": "^14.6.1", "@vitest/expect": "3.2.4", "@vitest/spy": "3.2.4", "esbuild": "^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0 || ^0.25.0 || ^0.26.0 || ^0.27.0", "open": "^10.2.0", "recast": "^0.23.5", "semver": "^7.7.3", "use-sync-external-store": "^1.5.0", "ws": "^8.18.0" }, "peerDependencies": { "prettier": "^2 || ^3" }, "optionalPeers": ["prettier"], "bin": "./dist/bin/dispatcher.js" }, "sha512-heMfJjOfbHvL+wlCAwFZlSxcakyJ5yQDam6e9k2RRArB1veJhRnsjO6lO1hOXjJYrqxfHA/ldIugbBVlCDqfvQ=="], + + "storybook-solidjs-vite": ["storybook-solidjs-vite@10.0.9", "", { "dependencies": { "@joshwooding/vite-plugin-react-docgen-typescript": "^0.6.1", "@storybook/builder-vite": "^10.0.0", "@storybook/global": "^5.0.0", "vite-plugin-solid": "^2.11.8" }, "peerDependencies": { "solid-js": "^1.9.0", "storybook": "^0.0.0-0 || ^10.0.0", "typescript": ">= 4.9.x", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0" }, "optionalPeers": ["typescript"] }, "sha512-n6MwWCL9mK/qIaUutE9vhGB0X1I1hVnKin2NL+iVC5oXfAiuaABVZlr/1oEeEypsgCdyDOcbEbhJmDWmaqGpPw=="], + "stream-replace-string": ["stream-replace-string@2.0.0", "", {}, "sha512-TlnjJ1C0QrmxRNrON00JvaFFlNh5TTG00APw23j74ET7gkQpTASi6/L2fuiav8pzK715HXtUeClpBTw2NPSn6w=="], "streamx": ["streamx@2.23.0", "", { "dependencies": { "events-universal": "^1.0.0", "fast-fifo": "^1.3.2", "text-decoder": "^1.1.0" } }, "sha512-kn+e44esVfn2Fa/O0CPFcex27fjIL6MkVae0Mm6q+E6f0hWv578YCERbv+4m02cjxvDsPKLnmxral/rR6lBMAg=="], @@ -3834,18 +4330,28 @@ "strip-final-newline": ["strip-final-newline@3.0.0", "", {}, "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw=="], + "strip-indent": ["strip-indent@3.0.0", "", { "dependencies": { "min-indent": "^1.0.0" } }, "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ=="], + + "strip-json-comments": ["strip-json-comments@2.0.1", "", {}, "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ=="], + "stripe": ["stripe@18.0.0", "", { "dependencies": { "@types/node": ">=8.1.0", "qs": "^6.11.0" } }, "sha512-3Fs33IzKUby//9kCkCa1uRpinAoTvj6rJgQ2jrBEysoxEvfsclvXdna1amyEYbA2EKkjynuB4+L/kleCCaWTpA=="], "strnum": ["strnum@1.1.2", "", {}, "sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA=="], "strtok3": ["strtok3@6.3.0", "", { "dependencies": { "@tokenizer/token": "^0.3.0", "peek-readable": "^4.1.0" } }, "sha512-fZtbhtvI9I48xDSywd/somNqgUHl2L2cstmXCCif0itOf96jeW18MBSyrLuNicYQVkvpOxkZtkzujiTJ9LW5Jw=="], + "stubborn-fs": ["stubborn-fs@2.0.0", "", { "dependencies": { "stubborn-utils": "^1.0.1" } }, "sha512-Y0AvSwDw8y+nlSNFXMm2g6L51rBGdAQT20J3YSOqxC53Lo3bjWRtr2BKcfYoAf352WYpsZSTURrA0tqhfgudPA=="], + + "stubborn-utils": ["stubborn-utils@1.0.2", "", {}, "sha512-zOh9jPYI+xrNOyisSelgym4tolKTJCQd5GBhK0+0xJvcYDcwlOoxF/rnFKQ2KRZknXSG9jWAp66fwP6AxN9STg=="], + "style-to-js": ["style-to-js@1.1.21", "", { "dependencies": { "style-to-object": "1.0.14" } }, "sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ=="], "style-to-object": ["style-to-object@1.0.14", "", { "dependencies": { "inline-style-parser": "0.2.7" } }, "sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw=="], "sucrase": ["sucrase@3.35.1", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", "commander": "^4.0.0", "lines-and-columns": "^1.1.6", "mz": "^2.7.0", "pirates": "^4.0.1", "tinyglobby": "^0.2.11", "ts-interface-checker": "^0.1.9" }, "bin": { "sucrase": "bin/sucrase", "sucrase-node": "bin/sucrase-node" } }, "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw=="], + "sumchecker": ["sumchecker@3.0.1", "", { "dependencies": { "debug": "^4.1.0" } }, "sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg=="], + "superstruct": ["superstruct@1.0.4", "", {}, "sha512-7JpaAoX2NGyoFlI9NBh66BQXGONc+uE+MRS5i2iOBKuS4e+ccgMDjATgZldkah+33DakBxDHiss9kvUcGAO8UQ=="], "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], @@ -3860,12 +4366,18 @@ "tar": ["tar@7.5.9", "", { "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", "minizlib": "^3.1.0", "yallist": "^5.0.0" } }, "sha512-BTLcK0xsDh2+PUe9F6c2TlRp4zOOBMTkoQHQIWSIzI0R7KG46uEwq4OPk2W7bZcprBMsuaeFsqwYr7pjh6CuHg=="], + "tar-fs": ["tar-fs@2.1.4", "", { "dependencies": { "chownr": "^1.1.1", "mkdirp-classic": "^0.5.2", "pump": "^3.0.0", "tar-stream": "^2.1.4" } }, "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ=="], + "tar-stream": ["tar-stream@3.1.7", "", { "dependencies": { "b4a": "^1.6.4", "fast-fifo": "^1.2.0", "streamx": "^2.15.0" } }, "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ=="], "tarn": ["tarn@3.0.2", "", {}, "sha512-51LAVKUSZSVfI05vjPESNc5vwqqZpbXCsU+/+wxlOrUjk2SnFTt97v9ZgQrD4YmxYW1Px6w2KjaDitCfkvgxMQ=="], "tedious": ["tedious@18.6.2", "", { "dependencies": { "@azure/core-auth": "^1.7.2", "@azure/identity": "^4.2.1", "@azure/keyvault-keys": "^4.4.0", "@js-joda/core": "^5.6.1", "@types/node": ">=18", "bl": "^6.0.11", "iconv-lite": "^0.6.3", "js-md4": "^0.3.2", "native-duplexpair": "^1.0.0", "sprintf-js": "^1.1.3" } }, "sha512-g7jC56o3MzLkE3lHkaFe2ZdOVFBahq5bsB60/M4NYUbocw/MCrS89IOEQUFr+ba6pb8ZHczZ/VqCyYeYq0xBAg=="], + "temp": ["temp@0.9.4", "", { "dependencies": { "mkdirp": "^0.5.1", "rimraf": "~2.6.2" } }, "sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA=="], + + "temp-file": ["temp-file@3.4.0", "", { "dependencies": { "async-exit-hook": "^2.0.1", "fs-extra": "^10.0.0" } }, "sha512-C5tjlC/HCtVUOi3KWVokd4vHVViOmGjtLwIh4MuzPo/nMYTV/p1urt3RnMz2IWXDdKEGJH3k5+KPxtqRsUYGtg=="], + "terracotta": ["terracotta@1.1.0", "", { "dependencies": { "solid-use": "^0.9.1" }, "peerDependencies": { "solid-js": "^1.8" } }, "sha512-kfQciWUBUBgYkXu7gh3CK3FAJng/iqZslAaY08C+k1Hdx17aVEpcFFb/WPaysxAfcupNH3y53s/pc53xxZauww=="], "terser": ["terser@5.46.0", "", { "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.15.0", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, "bin": { "terser": "bin/terser" } }, "sha512-jTwoImyr/QbOWFFso3YoU3ik0jBBDJ6JTOQiy/J2YxVJdZCc+5u7skhNwiOR3FQIygFqVUPHl7qbbxtjW2K3Qg=="], @@ -3882,10 +4394,14 @@ "thunky": ["thunky@1.1.0", "", {}, "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA=="], + "tiny-async-pool": ["tiny-async-pool@1.3.0", "", { "dependencies": { "semver": "^5.5.0" } }, "sha512-01EAw5EDrcVrdgyCLgoSPvqznC0sVxDSVeiOz09FUpjh71G79VCqneOr+xvt7T1r76CF6ZZfPjHorN2+d+3mqA=="], + "tiny-inflate": ["tiny-inflate@1.0.3", "", {}, "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw=="], "tiny-invariant": ["tiny-invariant@1.3.3", "", {}, "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg=="], + "tiny-typed-emitter": ["tiny-typed-emitter@2.1.0", "", {}, "sha512-qVtvMxeXbVej0cQWKqVSSAHmKZEHAvxdF8HEUBFWts8h+xEo5m/lEiPakuyZ3BnCBjOD8i24kzNOiOLLgsSxhA=="], + "tinybench": ["tinybench@2.9.0", "", {}, "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg=="], "tinycolor2": ["tinycolor2@1.6.0", "", {}, "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw=="], @@ -3896,8 +4412,14 @@ "tinyrainbow": ["tinyrainbow@3.0.3", "", {}, "sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q=="], + "tinyspy": ["tinyspy@4.0.4", "", {}, "sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q=="], + "titleize": ["titleize@4.0.0", "", {}, "sha512-ZgUJ1K83rhdu7uh7EHAC2BgY5DzoX8V5rTvoWI4vFysggi6YjLe5gUXABPWAU7VkvGP7P/0YiWq+dcPeYDsf1g=="], + "tmp": ["tmp@0.2.5", "", {}, "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow=="], + + "tmp-promise": ["tmp-promise@3.0.3", "", { "dependencies": { "tmp": "^0.2.0" } }, "sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ=="], + "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], "toad-cache": ["toad-cache@3.7.0", "", {}, "sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw=="], @@ -3912,14 +4434,20 @@ "traverse": ["traverse@0.3.9", "", {}, "sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ=="], + "tree-kill": ["tree-kill@1.2.2", "", { "bin": { "tree-kill": "cli.js" } }, "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A=="], + "tree-sitter-bash": ["tree-sitter-bash@0.25.0", "", { "dependencies": { "node-addon-api": "^8.2.1", "node-gyp-build": "^4.8.2" }, "peerDependencies": { "tree-sitter": "^0.25.0" }, "optionalPeers": ["tree-sitter"] }, "sha512-gZtlj9+qFS81qKxpLfD6H0UssQ3QBc/F0nKkPsiFDyfQF2YBqYvglFJUzchrPpVhZe9kLZTrJ9n2J6lmka69Vg=="], "trim-lines": ["trim-lines@3.0.1", "", {}, "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg=="], "trough": ["trough@2.2.0", "", {}, "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw=="], + "truncate-utf8-bytes": ["truncate-utf8-bytes@1.0.2", "", { "dependencies": { "utf8-byte-length": "^1.0.1" } }, "sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ=="], + "ts-algebra": ["ts-algebra@2.0.0", "", {}, "sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw=="], + "ts-dedent": ["ts-dedent@2.2.0", "", {}, "sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ=="], + "ts-interface-checker": ["ts-interface-checker@0.1.13", "", {}, "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA=="], "tsconfck": ["tsconfck@3.1.6", "", { "peerDependencies": { "typescript": "^5.0.0" }, "optionalPeers": ["typescript"], "bin": { "tsconfck": "bin/tsconfck.js" } }, "sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w=="], @@ -3932,19 +4460,21 @@ "tunnel": ["tunnel@0.0.6", "", {}, "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg=="], - "turbo": ["turbo@2.5.6", "", { "optionalDependencies": { "turbo-darwin-64": "2.5.6", "turbo-darwin-arm64": "2.5.6", "turbo-linux-64": "2.5.6", "turbo-linux-arm64": "2.5.6", "turbo-windows-64": "2.5.6", "turbo-windows-arm64": "2.5.6" }, "bin": { "turbo": "bin/turbo" } }, "sha512-gxToHmi9oTBNB05UjUsrWf0OyN5ZXtD0apOarC1KIx232Vp3WimRNy3810QzeNSgyD5rsaIDXlxlbnOzlouo+w=="], + "tunnel-agent": ["tunnel-agent@0.6.0", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w=="], - "turbo-darwin-64": ["turbo-darwin-64@2.5.6", "", { "os": "darwin", "cpu": "x64" }, "sha512-3C1xEdo4aFwMJAPvtlPqz1Sw/+cddWIOmsalHFMrsqqydcptwBfu26WW2cDm3u93bUzMbBJ8k3zNKFqxJ9ei2A=="], + "turbo": ["turbo@2.8.13", "", { "optionalDependencies": { "turbo-darwin-64": "2.8.13", "turbo-darwin-arm64": "2.8.13", "turbo-linux-64": "2.8.13", "turbo-linux-arm64": "2.8.13", "turbo-windows-64": "2.8.13", "turbo-windows-arm64": "2.8.13" }, "bin": { "turbo": "bin/turbo" } }, "sha512-nyM99hwFB9/DHaFyKEqatdayGjsMNYsQ/XBNO6MITc7roncZetKb97MpHxWf3uiU+LB9c9HUlU3Jp2Ixei2k1A=="], - "turbo-darwin-arm64": ["turbo-darwin-arm64@2.5.6", "", { "os": "darwin", "cpu": "arm64" }, "sha512-LyiG+rD7JhMfYwLqB6k3LZQtYn8CQQUePbpA8mF/hMLPAekXdJo1g0bUPw8RZLwQXUIU/3BU7tXENvhSGz5DPA=="], + "turbo-darwin-64": ["turbo-darwin-64@2.8.13", "", { "os": "darwin", "cpu": "x64" }, "sha512-PmOvodQNiOj77+Zwoqku70vwVjKzL34RTNxxoARjp5RU5FOj/CGiC6vcDQhNtFPUOWSAaogHF5qIka9TBhX4XA=="], - "turbo-linux-64": ["turbo-linux-64@2.5.6", "", { "os": "linux", "cpu": "x64" }, "sha512-GOcUTT0xiT/pSnHL4YD6Yr3HreUhU8pUcGqcI2ksIF9b2/r/kRHwGFcsHgpG3+vtZF/kwsP0MV8FTlTObxsYIA=="], + "turbo-darwin-arm64": ["turbo-darwin-arm64@2.8.13", "", { "os": "darwin", "cpu": "arm64" }, "sha512-kI+anKcLIM4L8h+NsM7mtAUpElkCOxv5LgiQVQR8BASyDFfc8Efj5kCk3cqxuxOvIqx0sLfCX7atrHQ2kwuNJQ=="], - "turbo-linux-arm64": ["turbo-linux-arm64@2.5.6", "", { "os": "linux", "cpu": "arm64" }, "sha512-10Tm15bruJEA3m0V7iZcnQBpObGBcOgUcO+sY7/2vk1bweW34LMhkWi8svjV9iDF68+KJDThnYDlYE/bc7/zzQ=="], + "turbo-linux-64": ["turbo-linux-64@2.8.13", "", { "os": "linux", "cpu": "x64" }, "sha512-j29KnQhHyzdzgCykBFeBqUPS4Wj7lWMnZ8CHqytlYDap4Jy70l4RNG46pOL9+lGu6DepK2s1rE86zQfo0IOdPw=="], - "turbo-windows-64": ["turbo-windows-64@2.5.6", "", { "os": "win32", "cpu": "x64" }, "sha512-FyRsVpgaj76It0ludwZsNN40ytHN+17E4PFJyeliBEbxrGTc5BexlXVpufB7XlAaoaZVxbS6KT8RofLfDRyEPg=="], + "turbo-linux-arm64": ["turbo-linux-arm64@2.8.13", "", { "os": "linux", "cpu": "arm64" }, "sha512-OEl1YocXGZDRDh28doOUn49QwNe82kXljO1HXApjU0LapkDiGpfl3jkAlPKxEkGDSYWc8MH5Ll8S16Rf5tEBYg=="], - "turbo-windows-arm64": ["turbo-windows-arm64@2.5.6", "", { "os": "win32", "cpu": "arm64" }, "sha512-j/tWu8cMeQ7HPpKri6jvKtyXg9K1gRyhdK4tKrrchH8GNHscPX/F71zax58yYtLRWTiK04zNzPcUJuoS0+v/+Q=="], + "turbo-windows-64": ["turbo-windows-64@2.8.13", "", { "os": "win32", "cpu": "x64" }, "sha512-717bVk1+Pn2Jody7OmWludhEirEe0okoj1NpRbSm5kVZz/yNN/jfjbxWC6ilimXMz7xoMT3IDfQFJsFR3PMANA=="], + + "turbo-windows-arm64": ["turbo-windows-arm64@2.8.13", "", { "os": "win32", "cpu": "arm64" }, "sha512-R819HShLIT0Wj6zWVnIsYvSNtRNj1q9VIyaUz0P24SMcLCbQZIm1sV09F4SDbg+KCCumqD2lcaR2UViQ8SnUJA=="], "turndown": ["turndown@7.2.0", "", { "dependencies": { "@mixmark-io/domino": "^2.2.0" } }, "sha512-eCZGBN4nNNqM9Owkv9HAtWRYfLA4h909E/WGAWWBpmB275ehNhZyk87/Tpvjbp0jjNl9XwCsbe6bm6CqFsgD+A=="], @@ -3970,6 +4500,8 @@ "ufo": ["ufo@1.6.3", "", {}, "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q=="], + "uint8array-extras": ["uint8array-extras@1.5.0", "", {}, "sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A=="], + "ulid": ["ulid@3.0.1", "", { "bin": { "ulid": "dist/cli.js" } }, "sha512-dPJyqPzx8preQhqq24bBG1YNkvigm87K8kVEHCD+ruZg24t6IFEFv00xMWfxcC4djmFtiTLdFuADn4+DOz6R7Q=="], "ultrahtml": ["ultrahtml@1.6.0", "", {}, "sha512-R9fBn90VTJrqqLDwyMph+HGne8eqY1iPfYhPzZrvKpIfwkWZbcYlfpsb8B9dTvBfpy1/hqAD7Wi8EKfP9e8zdw=="], @@ -3992,6 +4524,10 @@ "unifont": ["unifont@0.5.2", "", { "dependencies": { "css-tree": "^3.0.0", "ofetch": "^1.4.1", "ohash": "^2.0.0" } }, "sha512-LzR4WUqzH9ILFvjLAUU7dK3Lnou/qd5kD+IakBtBK4S15/+x2y9VX+DcWQv6s551R6W+vzwgVS6tFg3XggGBgg=="], + "unique-filename": ["unique-filename@1.1.1", "", { "dependencies": { "unique-slug": "^2.0.0" } }, "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ=="], + + "unique-slug": ["unique-slug@2.0.2", "", { "dependencies": { "imurmurhash": "^0.1.4" } }, "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w=="], + "unist-util-find-after": ["unist-util-find-after@5.0.0", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0" } }, "sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ=="], "unist-util-is": ["unist-util-is@6.0.1", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g=="], @@ -4020,18 +4556,26 @@ "unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="], + "unplugin": ["unplugin@2.3.11", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "acorn": "^8.15.0", "picomatch": "^4.0.3", "webpack-virtual-modules": "^0.6.2" } }, "sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww=="], + "unstorage": ["unstorage@2.0.0-alpha.5", "", { "peerDependencies": { "@azure/app-configuration": "^1.9.0", "@azure/cosmos": "^4.7.0", "@azure/data-tables": "^13.3.1", "@azure/identity": "^4.13.0", "@azure/keyvault-secrets": "^4.10.0", "@azure/storage-blob": "^12.29.1", "@capacitor/preferences": "^6.0.3 || ^7.0.0", "@deno/kv": ">=0.12.0", "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0", "@planetscale/database": "^1.19.0", "@upstash/redis": "^1.35.6", "@vercel/blob": ">=0.27.3", "@vercel/functions": "^2.2.12 || ^3.0.0", "@vercel/kv": "^1.0.1", "aws4fetch": "^1.0.20", "chokidar": "^4 || ^5", "db0": ">=0.3.4", "idb-keyval": "^6.2.2", "ioredis": "^5.8.2", "lru-cache": "^11.2.2", "mongodb": "^6 || ^7", "ofetch": "*", "uploadthing": "^7.7.4" }, "optionalPeers": ["@azure/app-configuration", "@azure/cosmos", "@azure/data-tables", "@azure/identity", "@azure/keyvault-secrets", "@azure/storage-blob", "@capacitor/preferences", "@deno/kv", "@netlify/blobs", "@planetscale/database", "@upstash/redis", "@vercel/blob", "@vercel/functions", "@vercel/kv", "aws4fetch", "chokidar", "db0", "idb-keyval", "ioredis", "lru-cache", "mongodb", "ofetch", "uploadthing"] }, "sha512-Sj8btci21Twnd6M+N+MHhjg3fVn6lAPElPmvFTe0Y/wR0WImErUdA1PzlAaUavHylJ7uDiFwlZDQKm0elG4b7g=="], "unzip-stream": ["unzip-stream@0.3.4", "", { "dependencies": { "binary": "^0.3.0", "mkdirp": "^0.5.1" } }, "sha512-PyofABPVv+d7fL7GOpusx7eRT9YETY2X04PhwbSipdj6bMxVCFJrr+nm0Mxqbf9hUiTin/UsnuFWBXlDZFy0Cw=="], "update-browserslist-db": ["update-browserslist-db@1.2.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w=="], + "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="], + "url": ["url@0.10.3", "", { "dependencies": { "punycode": "1.3.2", "querystring": "0.2.0" } }, "sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ=="], "use-callback-ref": ["use-callback-ref@1.3.3", "", { "dependencies": { "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg=="], "use-sidecar": ["use-sidecar@1.1.3", "", { "dependencies": { "detect-node-es": "^1.1.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ=="], + "use-sync-external-store": ["use-sync-external-store@1.6.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w=="], + + "utf8-byte-length": ["utf8-byte-length@1.0.5", "", {}, "sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA=="], + "utif2": ["utif2@4.1.0", "", { "dependencies": { "pako": "^1.0.11" } }, "sha512-+oknB9FHrJ7oW7A2WZYajOcv4FcDR4CfoGB0dPNfxbi4GO05RRnFmt5oa23+9w32EanrYcSJWspUiJkLMs+37w=="], "util": ["util@0.12.5", "", { "dependencies": { "inherits": "^2.0.3", "is-arguments": "^1.0.4", "is-generator-function": "^1.0.7", "is-typed-array": "^1.1.3", "which-typed-array": "^1.1.2" } }, "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA=="], @@ -4044,6 +4588,8 @@ "vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="], + "verror": ["verror@1.10.1", "", { "dependencies": { "assert-plus": "^1.0.0", "core-util-is": "1.0.2", "extsprintf": "^1.2.0" } }, "sha512-veufcmxri4e3XSrT0xwfUR7kguIkaxBeosDg00yDWhk49wdwkSUrvvsm7nc75e1PUyvIeZj6nS8VQRYz2/S4Xg=="], + "vfile": ["vfile@6.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "vfile-message": "^4.0.0" } }, "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q=="], "vfile-location": ["vfile-location@5.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "vfile": "^6.0.0" } }, "sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg=="], @@ -4098,6 +4644,8 @@ "vscode-uri": ["vscode-uri@3.1.0", "", {}, "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ=="], + "wcwidth": ["wcwidth@1.0.1", "", { "dependencies": { "defaults": "^1.0.3" } }, "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg=="], + "web-namespaces": ["web-namespaces@2.0.1", "", {}, "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ=="], "web-streams-polyfill": ["web-streams-polyfill@4.0.0-beta.3", "", {}, "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug=="], @@ -4106,11 +4654,15 @@ "webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="], + "webpack-virtual-modules": ["webpack-virtual-modules@0.6.2", "", {}, "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ=="], + "whatwg-mimetype": ["whatwg-mimetype@3.0.0", "", {}, "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q=="], "whatwg-url": ["whatwg-url@5.0.0", "", { "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="], - "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], + "when-exit": ["when-exit@2.1.5", "", {}, "sha512-VGkKJ564kzt6Ms1dbgPP/yuIoQCrsFAnRbptpC5wOEsDaNsbCB2bnfnaA8i/vRs5tjUSEOtIuvl9/MyVsvQZCg=="], + + "which": ["which@6.0.1", "", { "dependencies": { "isexe": "^4.0.0" }, "bin": { "node-which": "bin/which.js" } }, "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg=="], "which-boxed-primitive": ["which-boxed-primitive@1.1.1", "", { "dependencies": { "is-bigint": "^1.1.0", "is-boolean-object": "^1.2.1", "is-number-object": "^1.1.1", "is-string": "^1.1.1", "is-symbol": "^1.1.1" } }, "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA=="], @@ -4124,6 +4676,8 @@ "why-is-node-running": ["why-is-node-running@3.2.2", "", { "bin": { "why-is-node-running": "cli.js" } }, "sha512-NKUzAelcoCXhXL4dJzKIwXeR8iEVqsA0Lq6Vnd0UXvgaKbzVo4ZTHROF2Jidrv+SgxOQ03fMinnNhzZATxOD3A=="], + "wide-align": ["wide-align@1.1.5", "", { "dependencies": { "string-width": "^1.0.2 || 2 || 3 || 4" } }, "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg=="], + "widest-line": ["widest-line@5.0.0", "", { "dependencies": { "string-width": "^7.0.0" } }, "sha512-c9bZp7b5YtRj2wOe6dlj32MK+Bx/M/d+9VB2SHM1OtsUHR0aV0tdP6DWh/iMt0kWi1t5g1Iudu6hQRNd1A4PVA=="], "workerd": ["workerd@1.20251118.0", "", { "optionalDependencies": { "@cloudflare/workerd-darwin-64": "1.20251118.0", "@cloudflare/workerd-darwin-arm64": "1.20251118.0", "@cloudflare/workerd-linux-64": "1.20251118.0", "@cloudflare/workerd-linux-arm64": "1.20251118.0", "@cloudflare/workerd-windows-64": "1.20251118.0" }, "bin": { "workerd": "bin/workerd" } }, "sha512-Om5ns0Lyx/LKtYI04IV0bjIrkBgoFNg0p6urzr2asekJlfP18RqFzyqMFZKf0i9Gnjtz/JfAS/Ol6tjCe5JJsQ=="], @@ -4164,6 +4718,8 @@ "yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="], + "yauzl": ["yauzl@2.10.0", "", { "dependencies": { "buffer-crc32": "~0.2.3", "fd-slicer": "~1.1.0" } }, "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g=="], + "yocto-queue": ["yocto-queue@1.2.2", "", {}, "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ=="], "yocto-spinner": ["yocto-spinner@0.2.3", "", { "dependencies": { "yoctocolors": "^2.1.1" } }, "sha512-sqBChb33loEnkoXte1bLg45bEBsOP9N1kzQh5JZNKj/0rik4zAPTNSAVPj3uQAdc6slYJ0Ksc403G2XgxsJQFQ=="], @@ -4260,6 +4816,8 @@ "@astrojs/mdx/@astrojs/markdown-remark": ["@astrojs/markdown-remark@6.3.10", "", { "dependencies": { "@astrojs/internal-helpers": "0.7.5", "@astrojs/prism": "3.3.0", "github-slugger": "^2.0.0", "hast-util-from-html": "^2.0.3", "hast-util-to-text": "^4.0.2", "import-meta-resolve": "^4.2.0", "js-yaml": "^4.1.1", "mdast-util-definitions": "^6.0.0", "rehype-raw": "^7.0.0", "rehype-stringify": "^10.0.1", "remark-gfm": "^4.0.1", "remark-parse": "^11.0.0", "remark-rehype": "^11.1.2", "remark-smartypants": "^3.0.2", "shiki": "^3.19.0", "smol-toml": "^1.5.2", "unified": "^11.0.5", "unist-util-remove-position": "^5.0.0", "unist-util-visit": "^5.0.0", "unist-util-visit-parents": "^6.0.2", "vfile": "^6.0.3" } }, "sha512-kk4HeYR6AcnzC4QV8iSlOfh+N8TZ3MEStxPyenyCtemqn8IpEATBFMTJcfrNW32dgpt6MY3oCkMM/Tv3/I4G3A=="], + "@astrojs/mdx/source-map": ["source-map@0.7.6", "", {}, "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ=="], + "@astrojs/sitemap/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], "@astrojs/solid-js/vite": ["vite@6.4.1", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", "picomatch": "^4.0.2", "postcss": "^8.5.3", "rollup": "^4.34.9", "tinyglobby": "^0.2.13" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g=="], @@ -4432,8 +4990,42 @@ "@cspotcode/source-map-support/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.9", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" } }, "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ=="], + "@develar/schema-utils/ajv": ["ajv@6.14.0", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw=="], + "@dot/log/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], + "@electron/asar/commander": ["commander@5.1.0", "", {}, "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg=="], + + "@electron/asar/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], + + "@electron/asar/minimatch": ["minimatch@3.1.5", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w=="], + + "@electron/fuses/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], + + "@electron/fuses/fs-extra": ["fs-extra@9.1.0", "", { "dependencies": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ=="], + + "@electron/get/fs-extra": ["fs-extra@8.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^4.0.0", "universalify": "^0.1.0" } }, "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g=="], + + "@electron/get/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + + "@electron/notarize/fs-extra": ["fs-extra@9.1.0", "", { "dependencies": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ=="], + + "@electron/osx-sign/isbinaryfile": ["isbinaryfile@4.0.10", "", {}, "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw=="], + + "@electron/rebuild/detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], + + "@electron/rebuild/node-abi": ["node-abi@4.26.0", "", { "dependencies": { "semver": "^7.6.3" } }, "sha512-8QwIZqikRvDIkXS2S93LjzhsSPJuIbfaMETWH+Bx8oOT9Sa9UsUtBFQlc3gBNd1+QINjaTloitXr1W3dQLi9Iw=="], + + "@electron/rebuild/node-gyp": ["node-gyp@11.5.0", "", { "dependencies": { "env-paths": "^2.2.0", "exponential-backoff": "^3.1.1", "graceful-fs": "^4.2.6", "make-fetch-happen": "^14.0.3", "nopt": "^8.0.0", "proc-log": "^5.0.0", "semver": "^7.3.5", "tar": "^7.4.3", "tinyglobby": "^0.2.12", "which": "^5.0.0" }, "bin": { "node-gyp": "bin/node-gyp.js" } }, "sha512-ra7Kvlhxn5V9Slyus0ygMa2h+UqExPqUIkfk7Pc8QTLT956JLSy51uWFwHtIYy0vI8cB4BDhc/S03+880My/LQ=="], + + "@electron/rebuild/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/universal/fs-extra": ["fs-extra@11.3.3", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-VWSRii4t0AFm6ixFFmLLx1t7wS1gh+ckoa84aOeapGum0h+EZd1EhEumSB+ZdDLnEPuucsVB9oB7cxJHap6Afg=="], + + "@electron/universal/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], + + "@electron/windows-sign/fs-extra": ["fs-extra@11.3.3", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-VWSRii4t0AFm6ixFFmLLx1t7wS1gh+ckoa84aOeapGum0h+EZd1EhEumSB+ZdDLnEPuucsVB9oB7cxJHap6Afg=="], + "@fastify/proxy-addr/ipaddr.js": ["ipaddr.js@2.3.0", "", {}, "sha512-Zv/pA+ciVFbCSBBjGfaKUya/CcGmUHzTydLMaTwrUUEM2DIEO3iZvueGxmacvmN50fGpGVKeTXpb2LcYQxeVdg=="], "@gitlab/gitlab-ai-provider/openai": ["openai@6.22.0", "", { "peerDependencies": { "ws": "^8.18.0", "zod": "^3.25 || ^4.0" }, "optionalPeers": ["ws", "zod"], "bin": { "openai": "bin/cli" } }, "sha512-7Yvy17F33Bi9RutWbsaYt5hJEEJ/krRPOrwan+f9aCPuMat1WVsb2VNSII5W1EksKT6fF69TG/xj4XzodK3JZw=="], @@ -4488,6 +5080,10 @@ "@jsx-email/doiuse-email/htmlparser2": ["htmlparser2@9.1.0", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.3", "domutils": "^3.1.0", "entities": "^4.5.0" } }, "sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ=="], + "@malept/flatpak-bundler/fs-extra": ["fs-extra@9.1.0", "", { "dependencies": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ=="], + + "@mdx-js/mdx/source-map": ["source-map@0.7.6", "", {}, "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ=="], + "@modelcontextprotocol/sdk/express": ["express@5.2.1", "", { "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.1", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", "depd": "^2.0.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "finalhandler": "^2.1.0", "fresh": "^2.0.0", "http-errors": "^2.0.0", "merge-descriptors": "^2.0.0", "mime-types": "^3.0.0", "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", "proxy-addr": "^2.0.7", "qs": "^6.14.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", "type-is": "^2.0.1", "vary": "^1.1.2" } }, "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw=="], "@modelcontextprotocol/sdk/jose": ["jose@6.1.3", "", {}, "sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ=="], @@ -4496,6 +5092,14 @@ "@modelcontextprotocol/sdk/zod-to-json-schema": ["zod-to-json-schema@3.25.1", "", { "peerDependencies": { "zod": "^3.25 || ^4" } }, "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA=="], + "@npmcli/agent/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], + + "@npmcli/agent/socks-proxy-agent": ["socks-proxy-agent@8.0.5", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "^4.3.4", "socks": "^2.8.3" } }, "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw=="], + + "@npmcli/move-file/mkdirp": ["mkdirp@1.0.4", "", { "bin": { "mkdirp": "bin/cmd.js" } }, "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="], + + "@npmcli/move-file/rimraf": ["rimraf@3.0.2", "", { "dependencies": { "glob": "^7.1.3" }, "bin": { "rimraf": "bin.js" } }, "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA=="], + "@octokit/auth-app/@octokit/request": ["@octokit/request@10.0.7", "", { "dependencies": { "@octokit/endpoint": "^11.0.2", "@octokit/request-error": "^7.0.2", "@octokit/types": "^16.0.0", "fast-content-type-parse": "^3.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-v93h0i1yu4idj8qFPZwjehoJx4j3Ntn+JhXsdJrG9pYaX6j/XRz2RmasMUHtNgQD39nrv/VwTWSqK0RNXR8upA=="], "@octokit/auth-app/@octokit/request-error": ["@octokit/request-error@7.1.0", "", { "dependencies": { "@octokit/types": "^16.0.0" } }, "sha512-KMQIfq5sOPpkQYajXHwnhjCC0slzCNScLHs9JafXc4RAJI+9f+jNDlBNaIMTvazOPLgb4BnlhGJOTbnN0wIjPw=="], @@ -4560,6 +5164,12 @@ "@opencode-ai/desktop/typescript": ["typescript@5.6.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw=="], + "@opencode-ai/desktop-electron/@actions/artifact": ["@actions/artifact@4.0.0", "", { "dependencies": { "@actions/core": "^1.10.0", "@actions/github": "^6.0.1", "@actions/http-client": "^2.1.0", "@azure/core-http": "^3.0.5", "@azure/storage-blob": "^12.15.0", "@octokit/core": "^5.2.1", "@octokit/plugin-request-log": "^1.0.4", "@octokit/plugin-retry": "^3.0.9", "@octokit/request": "^8.4.1", "@octokit/request-error": "^5.1.1", "@protobuf-ts/plugin": "^2.2.3-alpha.1", "archiver": "^7.0.1", "jwt-decode": "^3.1.2", "unzip-stream": "^0.3.1" } }, "sha512-HCc2jMJRAfviGFAh0FsOR/jNfWhirxl7W6z8zDtttt0GltwxBLdEIjLiweOPFl9WbyJRW1VWnPUSAixJqcWUMQ=="], + + "@opencode-ai/desktop-electron/marked": ["marked@15.0.12", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA=="], + + "@opencode-ai/desktop-electron/typescript": ["typescript@5.6.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw=="], + "@opencode-ai/web/@shikijs/transformers": ["@shikijs/transformers@3.20.0", "", { "dependencies": { "@shikijs/core": "3.20.0", "@shikijs/types": "3.20.0" } }, "sha512-PrHHMRr3Q5W1qB/42kJW6laqFyWdhrPF2hNR9qjOm1xcSiAO3hAHo7HaVyHE6pMyevmy3i51O8kuGGXC78uK3g=="], "@opentui/solid/@babel/core": ["@babel/core@7.28.0", "", { "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.0", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.27.3", "@babel/helpers": "^7.27.6", "@babel/parser": "^7.28.0", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.0", "@babel/types": "^7.28.0", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ=="], @@ -4572,6 +5182,8 @@ "@pierre/diffs/diff": ["diff@8.0.3", "", {}, "sha512-qejHi7bcSD4hQAZE0tNAawRK1ZtafHDmMTMkrrIGgSLl7hTnQHmKCeB45xAcbfTqK2zowkM3j3bHt/4b/ARbYQ=="], + "@poppinss/dumper/@sindresorhus/is": ["@sindresorhus/is@7.2.0", "", {}, "sha512-P1Cz1dWaFfR4IR+U13mqqiGsLFf1KbayybWwdd2vfctdV6hDpUkgCY0nKOLLTMSoRd/jJNjtbqzf13K8DCCXQw=="], + "@poppinss/dumper/supports-color": ["supports-color@10.2.2", "", {}, "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g=="], "@protobuf-ts/plugin/typescript": ["typescript@3.9.10", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q=="], @@ -4612,6 +5224,8 @@ "@solidjs/start/vite": ["vite@7.1.10", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-CmuvUBzVJ/e3HGxhg6cYk88NGgTnBoOo7ogtfJJ0fefUWAxN/WDSUa50o+oVBxuIhO8FoEZW0j2eW7sfjs5EtA=="], + "@storybook/builder-vite/@storybook/csf-plugin": ["@storybook/csf-plugin@10.2.10", "", { "dependencies": { "unplugin": "^2.3.5" }, "peerDependencies": { "esbuild": "*", "rollup": "*", "storybook": "^10.2.10", "vite": "*", "webpack": "*" }, "optionalPeers": ["esbuild", "rollup", "vite", "webpack"] }, "sha512-aFvgaNDAnKMjuyhPK5ialT22pPqMN0XfPBNPeeNVPYztngkdKBa8WFqF/umDd47HxAjebq+vn6uId1xHyOHH3g=="], + "@tailwindcss/oxide/detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.8.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg=="], @@ -4632,8 +5246,20 @@ "@tanstack/server-functions-plugin/@babel/code-frame": ["@babel/code-frame@7.27.1", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg=="], + "@testing-library/dom/aria-query": ["aria-query@5.3.0", "", { "dependencies": { "dequal": "^2.0.3" } }, "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A=="], + + "@testing-library/dom/dom-accessibility-api": ["dom-accessibility-api@0.5.16", "", {}, "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg=="], + + "@types/plist/xmlbuilder": ["xmlbuilder@15.1.1", "", {}, "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg=="], + "@types/serve-static/@types/send": ["@types/send@0.17.6", "", { "dependencies": { "@types/mime": "^1", "@types/node": "*" } }, "sha512-Uqt8rPBE8SY0RK8JB1EzVOIZ32uqy8HwdxCnoCOsYrvnswqmFZ/k+9Ikidlk/ImhsdvBsloHbAlewb2IEBV/Og=="], + "@vitest/expect/@vitest/utils": ["@vitest/utils@3.2.4", "", { "dependencies": { "@vitest/pretty-format": "3.2.4", "loupe": "^3.1.4", "tinyrainbow": "^2.0.0" } }, "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA=="], + + "@vitest/expect/tinyrainbow": ["tinyrainbow@2.0.0", "", {}, "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw=="], + + "@vitest/mocker/@vitest/spy": ["@vitest/spy@4.0.18", "", {}, "sha512-cbQt3PTSD7P2OARdVW3qWER5EGq7PHlvE+QfzSC0lbwO+xnt7+XH06ZzFjFRgzUX//JmpxrCu92VdwvEPlWSNw=="], + "@vscode/emmet-helper/jsonc-parser": ["jsonc-parser@2.3.1", "", {}, "sha512-H8jvkz1O50L3dMZCsLqiuB2tA7muqbSg1AtGEkN0leAqGjsUzDJir3Zwr02BhqdcITPg3ei3mZ+HjMocAknhhg=="], "accepts/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], @@ -4652,14 +5278,26 @@ "ai-gateway-provider/@ai-sdk/openai-compatible": ["@ai-sdk/openai-compatible@1.0.33", "", { "dependencies": { "@ai-sdk/provider": "2.0.1", "@ai-sdk/provider-utils": "3.0.21" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-2KMcR2xAul3u5dGZD7gONgbIki3Hg7Ey+sFu7gsiJ4U2iRU0GDV3ccNq79dTuAEXPDFcOWCUpW8A8jXc0kxJxQ=="], + "ajv-keywords/ajv": ["ajv@6.14.0", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw=="], + "ansi-align/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=="], "anymatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + "app-builder-lib/@electron/get": ["@electron/get@3.1.0", "", { "dependencies": { "debug": "^4.1.1", "env-paths": "^2.2.0", "fs-extra": "^8.1.0", "got": "^11.8.5", "progress": "^2.0.3", "semver": "^6.2.0", "sumchecker": "^3.0.1" }, "optionalDependencies": { "global-agent": "^3.0.0" } }, "sha512-F+nKc0xW+kVbBRhFzaMgPy3KwmuNTYX1fx6+FxxoSnNgwYX6LD7AKBTWkU0MQ6IBoe7dz069CNkR673sPAgkCQ=="], + + "app-builder-lib/ci-info": ["ci-info@4.3.1", "", {}, "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA=="], + + "app-builder-lib/minimatch": ["minimatch@10.2.1", "", { "dependencies": { "brace-expansion": "^5.0.2" } }, "sha512-MClCe8IL5nRRmawL6ib/eT4oLyeKMGCghibcDWK+J0hh0Q8kqSdia6BvbRMVk6mPa6WqUa5uR2oxt6C5jd533A=="], + + "app-builder-lib/which": ["which@5.0.0", "", { "dependencies": { "isexe": "^3.1.1" }, "bin": { "node-which": "bin/which.js" } }, "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ=="], + "archiver-utils/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="], "archiver-utils/is-stream": ["is-stream@2.0.1", "", {}, "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="], + "are-we-there-yet/readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="], + "astro/@astrojs/internal-helpers": ["@astrojs/internal-helpers@0.6.1", "", {}, "sha512-l5Pqf6uZu31aG+3Lv8nl/3s4DbUzdlxTWDof4pEpto6GUJNhhCbelVi9dEyurOVyqaelwmS9oSyOWOENSfgo9A=="], "astro/diff": ["diff@5.2.2", "", {}, "sha512-vtcDfH3TOjP8UekytvnHH1o1P4FcUdt4eQ1Y+Abap1tk/OB2MWQvcwS2ClCd1zuIhc3JKOx6p3kod8Vfys3E+A=="], @@ -4688,16 +5326,58 @@ "buffer/ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], + "builder-util/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], + + "builder-util-runtime/sax": ["sax@1.4.4", "", {}, "sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw=="], + "bun-webgpu/@webgpu/types": ["@webgpu/types@0.1.69", "", {}, "sha512-RPmm6kgRbI8e98zSD3RVACvnuktIja5+yLgDAkTmxLr90BEwdTXRQWNLF3ETTTyH/8mKhznZuN5AveXYFEsMGQ=="], "c12/chokidar": ["chokidar@5.0.0", "", { "dependencies": { "readdirp": "^5.0.0" } }, "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw=="], - "clean-css/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], + "c12/dotenv": ["dotenv@17.3.1", "", {}, "sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA=="], + + "cacache/chownr": ["chownr@2.0.0", "", {}, "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ=="], + + "cacache/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], + + "cacache/lru-cache": ["lru-cache@6.0.0", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA=="], + + "cacache/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], + + "cacache/mkdirp": ["mkdirp@1.0.4", "", { "bin": { "mkdirp": "bin/cmd.js" } }, "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="], + + "cacache/rimraf": ["rimraf@3.0.2", "", { "dependencies": { "glob": "^7.1.3" }, "bin": { "rimraf": "bin.js" } }, "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA=="], + + "cacache/tar": ["tar@6.2.1", "", { "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", "minipass": "^5.0.0", "minizlib": "^2.1.1", "mkdirp": "^1.0.3", "yallist": "^4.0.0" } }, "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A=="], + + "cli-truncate/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=="], + + "clone-response/mimic-response": ["mimic-response@1.0.1", "", {}, "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ=="], "compress-commons/is-stream": ["is-stream@2.0.1", "", {}, "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="], "condense-newlines/kind-of": ["kind-of@3.2.2", "", { "dependencies": { "is-buffer": "^1.1.5" } }, "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ=="], + "conf/dot-prop": ["dot-prop@9.0.0", "", { "dependencies": { "type-fest": "^4.18.2" } }, "sha512-1gxPBJpI/pcjQhKgIU91II6Wkay+dLcN3M6rf2uwP8hRur3HtQXjVrdAK3sjC0piaEuxzMwjXChcETiJl47lAQ=="], + + "conf/env-paths": ["env-paths@3.0.0", "", {}, "sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A=="], + + "crc/buffer": ["buffer@5.7.1", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" } }, "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ=="], + + "cross-spawn/which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], + + "db0/drizzle-orm": ["drizzle-orm@1.0.0-beta.12-a5629fb", "", { "peerDependencies": { "@aws-sdk/client-rds-data": ">=3", "@cloudflare/workers-types": ">=4", "@effect/sql": "^0.48.5", "@effect/sql-pg": "^0.49.7", "@electric-sql/pglite": ">=0.2.0", "@libsql/client": ">=0.10.0", "@libsql/client-wasm": ">=0.10.0", "@neondatabase/serverless": ">=0.10.0", "@op-engineering/op-sqlite": ">=2", "@opentelemetry/api": "^1.4.1", "@planetscale/database": ">=1.13", "@prisma/client": "*", "@sqlitecloud/drivers": ">=1.0.653", "@tidbcloud/serverless": "*", "@tursodatabase/database": ">=0.2.1", "@tursodatabase/database-common": ">=0.2.1", "@tursodatabase/database-wasm": ">=0.2.1", "@types/better-sqlite3": "*", "@types/mssql": "^9.1.4", "@types/pg": "*", "@types/sql.js": "*", "@upstash/redis": ">=1.34.7", "@vercel/postgres": ">=0.8.0", "@xata.io/client": "*", "better-sqlite3": ">=9.3.0", "bun-types": "*", "expo-sqlite": ">=14.0.0", "gel": ">=2", "mssql": "^11.0.1", "mysql2": ">=2", "pg": ">=8", "postgres": ">=3", "sql.js": ">=1", "sqlite3": ">=5" }, "optionalPeers": ["@aws-sdk/client-rds-data", "@cloudflare/workers-types", "@effect/sql", "@effect/sql-pg", "@electric-sql/pglite", "@libsql/client", "@libsql/client-wasm", "@neondatabase/serverless", "@op-engineering/op-sqlite", "@opentelemetry/api", "@planetscale/database", "@prisma/client", "@sqlitecloud/drivers", "@tidbcloud/serverless", "@tursodatabase/database", "@tursodatabase/database-common", "@tursodatabase/database-wasm", "@types/better-sqlite3", "@types/pg", "@types/sql.js", "@upstash/redis", "@vercel/postgres", "@xata.io/client", "better-sqlite3", "bun-types", "expo-sqlite", "gel", "mysql2", "pg", "postgres", "sql.js", "sqlite3"] }, "sha512-wyOAgr9Cy9oEN6z5S0JGhfipLKbRRJtQKgbDO9SXGR9swMBbGNIlXkeMqPRrqYQ8k70mh+7ZJ/eVmJ2F7zR3Vg=="], + + "defaults/clone": ["clone@1.0.4", "", {}, "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg=="], + + "dir-compare/minimatch": ["minimatch@3.1.5", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w=="], + + "dir-compare/p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="], + + "dmg-builder/iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="], + + "dmg-license/ajv": ["ajv@6.14.0", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw=="], + "dom-serializer/entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="], "dot-prop/type-fest": ["type-fest@3.13.1", "", {}, "sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g=="], @@ -4706,6 +5386,18 @@ "editorconfig/minimatch": ["minimatch@9.0.1", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w=="], + "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-publish/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], + + "electron-publish/mime": ["mime@2.6.0", "", { "bin": { "mime": "cli.js" } }, "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg=="], + + "electron-winstaller/fs-extra": ["fs-extra@7.0.1", "", { "dependencies": { "graceful-fs": "^4.1.2", "jsonfile": "^4.0.0", "universalify": "^0.1.0" } }, "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw=="], + + "encoding/iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="], + "engine.io-client/ws": ["ws@8.18.3", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg=="], "es-get-iterator/isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="], @@ -4714,6 +5406,10 @@ "esbuild-plugin-copy/chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="], + "estree-util-to-js/source-map": ["source-map@0.7.6", "", {}, "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ=="], + + "execa/get-stream": ["get-stream@8.0.1", "", {}, "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA=="], + "execa/is-stream": ["is-stream@3.0.0", "", {}, "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA=="], "express/cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="], @@ -4726,10 +5422,22 @@ "fetch-blob/web-streams-polyfill": ["web-streams-polyfill@3.3.3", "", {}, "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw=="], + "filelist/minimatch": ["minimatch@5.1.6", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g=="], + "finalhandler/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], "form-data/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], + "fs-extra/jsonfile": ["jsonfile@6.2.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="], + + "fs-minipass/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], + + "gauge/signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="], + + "gauge/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=="], + + "gauge/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + "gaxios/node-fetch": ["node-fetch@3.3.2", "", { "dependencies": { "data-uri-to-buffer": "^4.0.0", "fetch-blob": "^3.1.4", "formdata-polyfill": "^4.0.10" } }, "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA=="], "glob/minimatch": ["minimatch@10.2.1", "", { "dependencies": { "brace-expansion": "^5.0.2" } }, "sha512-MClCe8IL5nRRmawL6ib/eT4oLyeKMGCghibcDWK+J0hh0Q8kqSdia6BvbRMVk6mPa6WqUa5uR2oxt6C5jd533A=="], @@ -4740,12 +5448,16 @@ "happy-dom/ws": ["ws@8.19.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg=="], + "hosted-git-info/lru-cache": ["lru-cache@6.0.0", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA=="], + "html-minifier-terser/commander": ["commander@10.0.1", "", {}, "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug=="], "html-minifier-terser/entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="], "htmlparser2/entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="], + "iconv-corefoundation/node-addon-api": ["node-addon-api@1.7.2", "", {}, "sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg=="], + "js-beautify/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="], "katex/commander": ["commander@8.3.0", "", {}, "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww=="], @@ -4756,6 +5468,18 @@ "lightningcss/detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], + "log-symbols/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], + + "make-fetch-happen/http-proxy-agent": ["http-proxy-agent@4.0.1", "", { "dependencies": { "@tootallnate/once": "1", "agent-base": "6", "debug": "4" } }, "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg=="], + + "make-fetch-happen/https-proxy-agent": ["https-proxy-agent@5.0.1", "", { "dependencies": { "agent-base": "6", "debug": "4" } }, "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA=="], + + "make-fetch-happen/lru-cache": ["lru-cache@6.0.0", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA=="], + + "make-fetch-happen/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], + + "matcher/escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="], + "md-to-react-email/marked": ["marked@7.0.4", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-t8eP0dXRJMtMvBojtkcsA7n48BkauktUKzfkPSCq85ZMTJ0v76Rke4DYz01omYpPTUh4p/f7HePgRo3ebG8+QQ=="], "mdast-util-find-and-replace/escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="], @@ -4768,10 +5492,34 @@ "miniflare/zod": ["zod@3.22.3", "", {}, "sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug=="], + "minipass-collect/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], + + "minipass-fetch/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], + + "minipass-fetch/minizlib": ["minizlib@2.1.2", "", { "dependencies": { "minipass": "^3.0.0", "yallist": "^4.0.0" } }, "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg=="], + + "minipass-flush/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], + + "minipass-pipeline/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], + + "minipass-sized/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], + + "motion/framer-motion": ["framer-motion@12.34.5", "", { "dependencies": { "motion-dom": "^12.34.5", "motion-utils": "^12.29.2", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-Z2dQ+o7BsfpJI3+u0SQUNCrN+ajCKJen1blC4rCHx1Ta2EOHs+xKJegLT2aaD9iSMbU3OoX+WabQXkloUbZmJQ=="], + "mssql/commander": ["commander@11.1.0", "", {}, "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ=="], "nitro/h3": ["h3@2.0.1-rc.5", "", { "dependencies": { "rou3": "^0.7.9", "srvx": "^0.9.1" }, "peerDependencies": { "crossws": "^0.4.1" }, "optionalPeers": ["crossws"] }, "sha512-qkohAzCab0nLzXNm78tBjZDvtKMTmtygS8BJLT3VPczAQofdqlFXDPkXdLMJN4r05+xqneG8snZJ0HgkERCZTg=="], + "node-gyp/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], + + "node-gyp/nopt": ["nopt@5.0.0", "", { "dependencies": { "abbrev": "1" }, "bin": { "nopt": "bin/nopt.js" } }, "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ=="], + + "node-gyp/rimraf": ["rimraf@3.0.2", "", { "dependencies": { "glob": "^7.1.3" }, "bin": { "rimraf": "bin.js" } }, "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA=="], + + "node-gyp/tar": ["tar@6.2.1", "", { "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", "minipass": "^5.0.0", "minizlib": "^2.1.1", "mkdirp": "^1.0.3", "yallist": "^4.0.0" } }, "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A=="], + + "node-gyp/which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], + "npm-run-path/path-key": ["path-key@4.0.0", "", {}, "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ=="], "nypm/citty": ["citty@0.2.1", "", {}, "sha512-kEV95lFBhQgtogAPlQfJJ0WGVSokvLr/UEoFPiKKOXF7pl98HfUVUD0ejsuTCld/9xH9vogSywZ5KqHzXrZpqg=="], @@ -4798,8 +5546,18 @@ "openid-client/lru-cache": ["lru-cache@6.0.0", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA=="], + "ora/bl": ["bl@4.1.0", "", { "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", "readable-stream": "^3.4.0" } }, "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w=="], + + "ora/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], + + "ora/cli-spinners": ["cli-spinners@2.9.2", "", {}, "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg=="], + + "ora/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + "p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="], + "p-retry/retry": ["retry@0.13.1", "", {}, "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg=="], + "parse-entities/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="], "parse5/entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="], @@ -4810,18 +5568,34 @@ "playwright/fsevents": ["fsevents@2.3.2", "", { "os": "darwin" }, "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA=="], + "plist/xmlbuilder": ["xmlbuilder@15.1.1", "", {}, "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg=="], + "postcss-css-variables/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], "postcss-load-config/lilconfig": ["lilconfig@3.1.3", "", {}, "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw=="], + "postject/commander": ["commander@9.5.0", "", {}, "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ=="], + + "prebuild-install/detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], + + "pretty-format/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "pretty-format/ansi-styles": ["ansi-styles@5.2.0", "", {}, "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="], + "prompts/kleur": ["kleur@3.0.3", "", {}, "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w=="], + "proper-lockfile/signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="], + "raw-body/iconv-lite": ["iconv-lite@0.4.24", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3" } }, "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA=="], "readable-stream/buffer": ["buffer@6.0.3", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" } }, "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA=="], "readdir-glob/minimatch": ["minimatch@5.1.6", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g=="], + "restore-cursor/onetime": ["onetime@5.1.2", "", { "dependencies": { "mimic-fn": "^2.1.0" } }, "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg=="], + + "restore-cursor/signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="], + "rimraf/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="], "router/path-to-regexp": ["path-to-regexp@8.3.0", "", {}, "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA=="], @@ -4834,6 +5608,8 @@ "send/mime": ["mime@1.6.0", "", { "bin": { "mime": "cli.js" } }, "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="], + "serialize-error/type-fest": ["type-fest@0.13.1", "", {}, "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg=="], + "sharp/detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], "shiki/@shikijs/core": ["@shikijs/core@3.20.0", "", { "dependencies": { "@shikijs/types": "3.20.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-f2ED7HYV4JEk827mtMDwe/yQ25pRiXZmtHjWF8uzZKuKiEsJR7Ce1nuQ+HhV9FzDcbIo4ObBCD9GPTzNuy9S1g=="], @@ -4842,12 +5618,22 @@ "sitemap/sax": ["sax@1.4.4", "", {}, "sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw=="], - "source-map-support/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], + "socks-proxy-agent/agent-base": ["agent-base@6.0.2", "", { "dependencies": { "debug": "4" } }, "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ=="], + + "sqlite3/tar": ["tar@6.2.1", "", { "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", "minipass": "^5.0.0", "minizlib": "^2.1.1", "mkdirp": "^1.0.3", "yallist": "^4.0.0" } }, "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A=="], + + "ssri/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], "sst/aws4fetch": ["aws4fetch@1.0.18", "", {}, "sha512-3Cf+YaUl07p24MoQ46rFwulAmiyCwH2+1zw1ZyPAX5OtJ34Hh185DwB8y/qRLb6cYYYtSFJ9pthyLc0MD4e8sQ=="], "sst/jose": ["jose@5.2.3", "", {}, "sha512-KUXdbctm1uHVL8BYhnyHkgp3zDX5KW8ZhAKVFEfUbU2P8Alpzjb+48hHvjOdQIyPshoblhzsuqOwEEAbtHVirA=="], + "storybook/esbuild": ["esbuild@0.27.3", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.3", "@esbuild/android-arm": "0.27.3", "@esbuild/android-arm64": "0.27.3", "@esbuild/android-x64": "0.27.3", "@esbuild/darwin-arm64": "0.27.3", "@esbuild/darwin-x64": "0.27.3", "@esbuild/freebsd-arm64": "0.27.3", "@esbuild/freebsd-x64": "0.27.3", "@esbuild/linux-arm": "0.27.3", "@esbuild/linux-arm64": "0.27.3", "@esbuild/linux-ia32": "0.27.3", "@esbuild/linux-loong64": "0.27.3", "@esbuild/linux-mips64el": "0.27.3", "@esbuild/linux-ppc64": "0.27.3", "@esbuild/linux-riscv64": "0.27.3", "@esbuild/linux-s390x": "0.27.3", "@esbuild/linux-x64": "0.27.3", "@esbuild/netbsd-arm64": "0.27.3", "@esbuild/netbsd-x64": "0.27.3", "@esbuild/openbsd-arm64": "0.27.3", "@esbuild/openbsd-x64": "0.27.3", "@esbuild/openharmony-arm64": "0.27.3", "@esbuild/sunos-x64": "0.27.3", "@esbuild/win32-arm64": "0.27.3", "@esbuild/win32-ia32": "0.27.3", "@esbuild/win32-x64": "0.27.3" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg=="], + + "storybook/open": ["open@10.2.0", "", { "dependencies": { "default-browser": "^5.2.1", "define-lazy-prop": "^3.0.0", "is-inside-container": "^1.0.0", "wsl-utils": "^0.1.0" } }, "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA=="], + + "storybook/ws": ["ws@8.19.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg=="], + "string-width-cjs/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], "string-width-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], @@ -4858,10 +5644,18 @@ "tar/yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="], + "tar-fs/chownr": ["chownr@1.1.4", "", {}, "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="], + + "tar-fs/tar-stream": ["tar-stream@2.2.0", "", { "dependencies": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", "fs-constants": "^1.0.0", "inherits": "^2.0.3", "readable-stream": "^3.1.1" } }, "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ=="], + "tedious/iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="], + "temp/rimraf": ["rimraf@2.6.3", "", { "dependencies": { "glob": "^7.1.3" }, "bin": { "rimraf": "./bin.js" } }, "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA=="], + "terser/commander": ["commander@2.20.3", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="], + "tiny-async-pool/semver": ["semver@5.7.2", "", { "bin": { "semver": "bin/semver" } }, "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g=="], + "token-types/ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], "tree-sitter-bash/node-addon-api": ["node-addon-api@8.5.0", "", {}, "sha512-/bRZty2mXUIFY/xU5HLvveNHlswNJej+RnxBjOMkidWfwZzgTbPG1E3K5TOxRLOR+5hX7bSofy8yf1hZevMS8A=="], @@ -4876,10 +5670,16 @@ "unifont/ofetch": ["ofetch@1.5.1", "", { "dependencies": { "destr": "^2.0.5", "node-fetch-native": "^1.6.7", "ufo": "^1.6.1" } }, "sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA=="], + "uri-js/punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], + "utif2/pako": ["pako@1.0.11", "", {}, "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="], "vite-plugin-icons-spritesheet/glob": ["glob@11.1.0", "", { "dependencies": { "foreground-child": "^3.3.1", "jackspeak": "^4.1.1", "minimatch": "^10.1.1", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^2.0.0" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw=="], + "vitest/@vitest/expect": ["@vitest/expect@4.0.18", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "@types/chai": "^5.2.2", "@vitest/spy": "4.0.18", "@vitest/utils": "4.0.18", "chai": "^6.2.1", "tinyrainbow": "^3.0.3" } }, "sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ=="], + + "vitest/@vitest/spy": ["@vitest/spy@4.0.18", "", {}, "sha512-cbQt3PTSD7P2OARdVW3qWER5EGq7PHlvE+QfzSC0lbwO+xnt7+XH06ZzFjFRgzUX//JmpxrCu92VdwvEPlWSNw=="], + "vitest/tinyexec": ["tinyexec@1.0.2", "", {}, "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg=="], "vitest/vite": ["vite@7.1.10", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-CmuvUBzVJ/e3HGxhg6cYk88NGgTnBoOo7ogtfJJ0fefUWAxN/WDSUa50o+oVBxuIhO8FoEZW0j2eW7sfjs5EtA=="], @@ -4890,6 +5690,8 @@ "which-builtin-type/isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="], + "wide-align/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=="], + "wrangler/esbuild": ["esbuild@0.25.4", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.4", "@esbuild/android-arm": "0.25.4", "@esbuild/android-arm64": "0.25.4", "@esbuild/android-x64": "0.25.4", "@esbuild/darwin-arm64": "0.25.4", "@esbuild/darwin-x64": "0.25.4", "@esbuild/freebsd-arm64": "0.25.4", "@esbuild/freebsd-x64": "0.25.4", "@esbuild/linux-arm": "0.25.4", "@esbuild/linux-arm64": "0.25.4", "@esbuild/linux-ia32": "0.25.4", "@esbuild/linux-loong64": "0.25.4", "@esbuild/linux-mips64el": "0.25.4", "@esbuild/linux-ppc64": "0.25.4", "@esbuild/linux-riscv64": "0.25.4", "@esbuild/linux-s390x": "0.25.4", "@esbuild/linux-x64": "0.25.4", "@esbuild/netbsd-arm64": "0.25.4", "@esbuild/netbsd-x64": "0.25.4", "@esbuild/openbsd-arm64": "0.25.4", "@esbuild/openbsd-x64": "0.25.4", "@esbuild/sunos-x64": "0.25.4", "@esbuild/win32-arm64": "0.25.4", "@esbuild/win32-ia32": "0.25.4", "@esbuild/win32-x64": "0.25.4" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q=="], "wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], @@ -4908,6 +5710,8 @@ "yargs/yargs-parser": ["yargs-parser@22.0.0", "", {}, "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw=="], + "yauzl/buffer-crc32": ["buffer-crc32@0.2.13", "", {}, "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ=="], + "zod-to-json-schema/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], "zod-to-ts/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], @@ -5010,6 +5814,32 @@ "@babel/helper-compilation-targets/lru-cache/yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], + "@develar/schema-utils/ajv/json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="], + + "@electron/asar/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="], + + "@electron/fuses/fs-extra/jsonfile": ["jsonfile@6.2.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="], + + "@electron/get/fs-extra/universalify": ["universalify@0.1.2", "", {}, "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="], + + "@electron/notarize/fs-extra/jsonfile": ["jsonfile@6.2.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="], + + "@electron/rebuild/node-gyp/make-fetch-happen": ["make-fetch-happen@14.0.3", "", { "dependencies": { "@npmcli/agent": "^3.0.0", "cacache": "^19.0.1", "http-cache-semantics": "^4.1.1", "minipass": "^7.0.2", "minipass-fetch": "^4.0.0", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "negotiator": "^1.0.0", "proc-log": "^5.0.0", "promise-retry": "^2.0.1", "ssri": "^12.0.0" } }, "sha512-QMjGbFTP0blj97EeidG5hk/QhKQ3T4ICckQGLgz38QF7Vgbk6e6FTARN8KhKxyBbWn8R0HU+bnw8aSoFPD4qtQ=="], + + "@electron/rebuild/node-gyp/nopt": ["nopt@8.1.0", "", { "dependencies": { "abbrev": "^3.0.0" }, "bin": { "nopt": "bin/nopt.js" } }, "sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A=="], + + "@electron/rebuild/node-gyp/which": ["which@5.0.0", "", { "dependencies": { "isexe": "^3.1.1" }, "bin": { "node-which": "bin/which.js" } }, "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ=="], + + "@electron/rebuild/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=="], + + "@electron/rebuild/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=="], + + "@electron/universal/fs-extra/jsonfile": ["jsonfile@6.2.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="], + + "@electron/universal/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], + + "@electron/windows-sign/fs-extra/jsonfile": ["jsonfile@6.2.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="], + "@jsx-email/cli/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.19.12", "", { "os": "aix", "cpu": "ppc64" }, "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA=="], "@jsx-email/cli/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.19.12", "", { "os": "android", "cpu": "arm" }, "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w=="], @@ -5070,6 +5900,8 @@ "@jsx-email/doiuse-email/htmlparser2/entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="], + "@malept/flatpak-bundler/fs-extra/jsonfile": ["jsonfile@6.2.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="], + "@modelcontextprotocol/sdk/express/accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="], "@modelcontextprotocol/sdk/express/body-parser": ["body-parser@2.2.2", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.3", "http-errors": "^2.0.0", "iconv-lite": "^0.7.0", "on-finished": "^2.4.1", "qs": "^6.14.1", "raw-body": "^3.0.1", "type-is": "^2.0.1" } }, "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA=="], @@ -5092,6 +5924,8 @@ "@modelcontextprotocol/sdk/express/type-is": ["type-is@2.0.1", "", { "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw=="], + "@npmcli/move-file/rimraf/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], + "@octokit/auth-app/@octokit/request/@octokit/endpoint": ["@octokit/endpoint@11.0.2", "", { "dependencies": { "@octokit/types": "^16.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-4zCpzP1fWc7QlqunZ5bSEjxc6yLAlRTnDwKtgXfcI/FxxGoqedDG8V2+xJ60bV2kODqcGB+nATdtap/XYq2NZQ=="], "@octokit/auth-app/@octokit/request/@octokit/types": ["@octokit/types@16.0.0", "", { "dependencies": { "@octokit/openapi-types": "^27.0.0" } }, "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg=="], @@ -5178,6 +6012,8 @@ "@octokit/rest/@octokit/core/before-after-hook": ["before-after-hook@4.0.0", "", {}, "sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ=="], + "@opencode-ai/desktop-electron/@actions/artifact/@actions/http-client": ["@actions/http-client@2.2.3", "", { "dependencies": { "tunnel": "^0.0.6", "undici": "^5.25.4" } }, "sha512-mx8hyJi/hjFvbPokCg4uRd4ZX78t+YyRPtnKWwIl+RzNaVuFpQHfmlGVfsKEJN8LwTCvL+DfVgAM04XaHkm6bA=="], + "@opencode-ai/desktop/@actions/artifact/@actions/http-client": ["@actions/http-client@2.2.3", "", { "dependencies": { "tunnel": "^0.0.6", "undici": "^5.25.4" } }, "sha512-mx8hyJi/hjFvbPokCg4uRd4ZX78t+YyRPtnKWwIl+RzNaVuFpQHfmlGVfsKEJN8LwTCvL+DfVgAM04XaHkm6bA=="], "@opencode-ai/web/@shikijs/transformers/@shikijs/core": ["@shikijs/core@3.20.0", "", { "dependencies": { "@shikijs/types": "3.20.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-f2ED7HYV4JEk827mtMDwe/yQ25pRiXZmtHjWF8uzZKuKiEsJR7Ce1nuQ+HhV9FzDcbIo4ObBCD9GPTzNuy9S1g=="], @@ -5210,6 +6046,8 @@ "@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime/@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="], + "@vitest/expect/@vitest/utils/@vitest/pretty-format": ["@vitest/pretty-format@3.2.4", "", { "dependencies": { "tinyrainbow": "^2.0.0" } }, "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA=="], + "accepts/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], "ai-gateway-provider/@ai-sdk/amazon-bedrock/@ai-sdk/anthropic": ["@ai-sdk/anthropic@2.0.62", "", { "dependencies": { "@ai-sdk/provider": "2.0.1", "@ai-sdk/provider-utils": "3.0.21" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-I3RhaOEMnWlWnrvjNBOYvUb19Dwf2nw01IruZrVJRDi688886e11wnd5DxrBZLd2V29Gizo3vpOPnnExsA+wTA=="], @@ -5224,10 +6062,18 @@ "ai-gateway-provider/@ai-sdk/openai/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@3.0.20", "", { "dependencies": { "@ai-sdk/provider": "2.0.1", "@standard-schema/spec": "^1.0.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-iXHVe0apM2zUEzauqJwqmpC37A5rihrStAih5Ks+JE32iTe4LZ58y17UGBjpQQTCRw9YxMeo2UFLxLpBluyvLQ=="], + "ajv-keywords/ajv/json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="], + "ansi-align/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], "ansi-align/string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + "app-builder-lib/@electron/get/fs-extra": ["fs-extra@8.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^4.0.0", "universalify": "^0.1.0" } }, "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g=="], + + "app-builder-lib/@electron/get/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + + "app-builder-lib/which/isexe": ["isexe@3.1.5", "", {}, "sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w=="], + "archiver-utils/glob/jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="], "archiver-utils/glob/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], @@ -5254,16 +6100,48 @@ "c12/chokidar/readdirp": ["readdirp@5.0.0", "", {}, "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ=="], + "cacache/glob/minimatch": ["minimatch@3.1.5", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w=="], + + "cacache/tar/minipass": ["minipass@5.0.0", "", {}, "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ=="], + + "cacache/tar/minizlib": ["minizlib@2.1.2", "", { "dependencies": { "minipass": "^3.0.0", "yallist": "^4.0.0" } }, "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg=="], + + "cli-truncate/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + + "cli-truncate/string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "crc/buffer/ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], + + "cross-spawn/which/isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], + + "dir-compare/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="], + + "dir-compare/p-limit/yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="], + + "dmg-license/ajv/json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="], + "editorconfig/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], + "electron-builder/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=="], + + "electron-builder/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=="], + + "electron-winstaller/fs-extra/universalify": ["universalify@0.1.2", "", {}, "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="], + "esbuild-plugin-copy/chokidar/readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="], "express/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], + "filelist/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], + "finalhandler/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], "form-data/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], + "gauge/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + + "gauge/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + "gray-matter/js-yaml/argparse": ["argparse@1.0.10", "", { "dependencies": { "sprintf-js": "~1.0.2" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="], "js-beautify/glob/jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="], @@ -5272,10 +6150,32 @@ "js-beautify/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="], + "lazystream/readable-stream/core-util-is": ["core-util-is@1.0.3", "", {}, "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="], + "lazystream/readable-stream/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="], "lazystream/readable-stream/string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="], + "make-fetch-happen/http-proxy-agent/agent-base": ["agent-base@6.0.2", "", { "dependencies": { "debug": "4" } }, "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ=="], + + "make-fetch-happen/https-proxy-agent/agent-base": ["agent-base@6.0.2", "", { "dependencies": { "debug": "4" } }, "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ=="], + + "motion/framer-motion/motion-dom": ["motion-dom@12.34.5", "", { "dependencies": { "motion-utils": "^12.29.2" } }, "sha512-k33CsnxO2K3gBRMUZT+vPmc4Utlb5menKdG0RyVNLtlqRaaJPRWlE9fXl8NTtfZ5z3G8TDvqSu0MENLqSTaHZA=="], + + "node-gyp/glob/minimatch": ["minimatch@3.1.5", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w=="], + + "node-gyp/nopt/abbrev": ["abbrev@1.1.1", "", {}, "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="], + + "node-gyp/tar/chownr": ["chownr@2.0.0", "", {}, "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ=="], + + "node-gyp/tar/minipass": ["minipass@5.0.0", "", {}, "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ=="], + + "node-gyp/tar/minizlib": ["minizlib@2.1.2", "", { "dependencies": { "minipass": "^3.0.0", "yallist": "^4.0.0" } }, "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg=="], + + "node-gyp/tar/mkdirp": ["mkdirp@1.0.4", "", { "bin": { "mkdirp": "bin/cmd.js" } }, "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="], + + "node-gyp/which/isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], + "opencode/@ai-sdk/openai/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@3.0.20", "", { "dependencies": { "@ai-sdk/provider": "2.0.1", "@standard-schema/spec": "^1.0.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-iXHVe0apM2zUEzauqJwqmpC37A5rihrStAih5Ks+JE32iTe4LZ58y17UGBjpQQTCRw9YxMeo2UFLxLpBluyvLQ=="], "opencode/@ai-sdk/openai-compatible/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@3.0.20", "", { "dependencies": { "@ai-sdk/provider": "2.0.1", "@standard-schema/spec": "^1.0.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-iXHVe0apM2zUEzauqJwqmpC37A5rihrStAih5Ks+JE32iTe4LZ58y17UGBjpQQTCRw9YxMeo2UFLxLpBluyvLQ=="], @@ -5290,12 +6190,20 @@ "opencontrol/@modelcontextprotocol/sdk/zod-to-json-schema": ["zod-to-json-schema@3.25.1", "", { "peerDependencies": { "zod": "^3.25 || ^4" } }, "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA=="], + "ora/bl/buffer": ["buffer@5.7.1", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" } }, "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ=="], + + "ora/bl/readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="], + + "ora/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + "pkg-up/find-up/locate-path": ["locate-path@3.0.0", "", { "dependencies": { "p-locate": "^3.0.0", "path-exists": "^3.0.0" } }, "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A=="], "readable-stream/buffer/ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], "readdir-glob/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], + "restore-cursor/onetime/mimic-fn": ["mimic-fn@2.1.0", "", {}, "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="], + "rimraf/glob/jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="], "rimraf/glob/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], @@ -5304,8 +6212,76 @@ "send/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], + "sqlite3/tar/chownr": ["chownr@2.0.0", "", {}, "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ=="], + + "sqlite3/tar/minipass": ["minipass@5.0.0", "", {}, "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ=="], + + "sqlite3/tar/minizlib": ["minizlib@2.1.2", "", { "dependencies": { "minipass": "^3.0.0", "yallist": "^4.0.0" } }, "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg=="], + + "sqlite3/tar/mkdirp": ["mkdirp@1.0.4", "", { "bin": { "mkdirp": "bin/cmd.js" } }, "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="], + + "storybook/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.3", "", { "os": "aix", "cpu": "ppc64" }, "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg=="], + + "storybook/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.27.3", "", { "os": "android", "cpu": "arm" }, "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA=="], + + "storybook/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.27.3", "", { "os": "android", "cpu": "arm64" }, "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg=="], + + "storybook/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.27.3", "", { "os": "android", "cpu": "x64" }, "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ=="], + + "storybook/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.27.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg=="], + + "storybook/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.27.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg=="], + + "storybook/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.27.3", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w=="], + + "storybook/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.27.3", "", { "os": "freebsd", "cpu": "x64" }, "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA=="], + + "storybook/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.27.3", "", { "os": "linux", "cpu": "arm" }, "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw=="], + + "storybook/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.27.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg=="], + + "storybook/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.27.3", "", { "os": "linux", "cpu": "ia32" }, "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg=="], + + "storybook/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.27.3", "", { "os": "linux", "cpu": "none" }, "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA=="], + + "storybook/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.27.3", "", { "os": "linux", "cpu": "none" }, "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw=="], + + "storybook/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.27.3", "", { "os": "linux", "cpu": "ppc64" }, "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA=="], + + "storybook/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.27.3", "", { "os": "linux", "cpu": "none" }, "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ=="], + + "storybook/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.27.3", "", { "os": "linux", "cpu": "s390x" }, "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw=="], + + "storybook/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.27.3", "", { "os": "linux", "cpu": "x64" }, "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA=="], + + "storybook/esbuild/@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.27.3", "", { "os": "none", "cpu": "arm64" }, "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA=="], + + "storybook/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.27.3", "", { "os": "none", "cpu": "x64" }, "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA=="], + + "storybook/esbuild/@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.27.3", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw=="], + + "storybook/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.27.3", "", { "os": "openbsd", "cpu": "x64" }, "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ=="], + + "storybook/esbuild/@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.27.3", "", { "os": "none", "cpu": "arm64" }, "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g=="], + + "storybook/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.27.3", "", { "os": "sunos", "cpu": "x64" }, "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA=="], + + "storybook/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.27.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA=="], + + "storybook/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.27.3", "", { "os": "win32", "cpu": "ia32" }, "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q=="], + + "storybook/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.3", "", { "os": "win32", "cpu": "x64" }, "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA=="], + + "storybook/open/wsl-utils": ["wsl-utils@0.1.0", "", { "dependencies": { "is-wsl": "^3.1.0" } }, "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw=="], + "string-width-cjs/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + "tar-fs/tar-stream/bl": ["bl@4.1.0", "", { "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", "readable-stream": "^3.4.0" } }, "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w=="], + + "tar-fs/tar-stream/readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="], + + "temp/rimraf/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], + "tsx/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.3", "", { "os": "aix", "cpu": "ppc64" }, "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg=="], "tsx/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.27.3", "", { "os": "android", "cpu": "arm" }, "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA=="], @@ -5372,6 +6348,12 @@ "vite-plugin-icons-spritesheet/glob/minimatch": ["minimatch@10.2.1", "", { "dependencies": { "brace-expansion": "^5.0.2" } }, "sha512-MClCe8IL5nRRmawL6ib/eT4oLyeKMGCghibcDWK+J0hh0Q8kqSdia6BvbRMVk6mPa6WqUa5uR2oxt6C5jd533A=="], + "vitest/@vitest/expect/chai": ["chai@6.2.2", "", {}, "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg=="], + + "wide-align/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + + "wide-align/string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + "wrangler/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.4", "", { "os": "aix", "cpu": "ppc64" }, "sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q=="], "wrangler/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.25.4", "", { "os": "android", "cpu": "arm" }, "sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ=="], @@ -5484,6 +6466,30 @@ "@aws-sdk/token-providers/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.3.6", "", { "dependencies": { "strnum": "^2.1.2" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-QNI3sAvSvaOiaMl8FYU4trnEzCwiRr8XMWgAHzlrWpTSj+QaCSvOf1h82OEP1s4hiAXhnbXSyFWCf4ldZzZRVA=="], + "@electron/asar/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + + "@electron/rebuild/node-gyp/make-fetch-happen/cacache": ["cacache@19.0.1", "", { "dependencies": { "@npmcli/fs": "^4.0.0", "fs-minipass": "^3.0.0", "glob": "^10.2.2", "lru-cache": "^10.0.1", "minipass": "^7.0.3", "minipass-collect": "^2.0.1", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "p-map": "^7.0.2", "ssri": "^12.0.0", "tar": "^7.4.3", "unique-filename": "^4.0.0" } }, "sha512-hdsUxulXCi5STId78vRVYEtDAjq99ICAUktLTeTYsLoTE6Z8dS0c8pWNCxwdrk9YfJeobDZc2Y186hD/5ZQgFQ=="], + + "@electron/rebuild/node-gyp/make-fetch-happen/minipass-fetch": ["minipass-fetch@4.0.1", "", { "dependencies": { "minipass": "^7.0.3", "minipass-sized": "^1.0.3", "minizlib": "^3.0.1" }, "optionalDependencies": { "encoding": "^0.1.13" } }, "sha512-j7U11C5HXigVuutxebFadoYBbd7VSdZWggSe64NVdvWNBqGAiXPL2QVCehjmw7lY1oF9gOllYbORh+hiNgfPgQ=="], + + "@electron/rebuild/node-gyp/make-fetch-happen/negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="], + + "@electron/rebuild/node-gyp/make-fetch-happen/ssri": ["ssri@12.0.0", "", { "dependencies": { "minipass": "^7.0.3" } }, "sha512-S7iGNosepx9RadX82oimUkvr0Ct7IjJbEbs4mJcTxst8um95J3sDYU1RBEOvdu6oL1Wek2ODI5i4MAw+dZ6cAQ=="], + + "@electron/rebuild/node-gyp/nopt/abbrev": ["abbrev@3.0.1", "", {}, "sha512-AO2ac6pjRB3SJmGJo+v5/aK6Omggp6fsLrs6wN9bd35ulu4cCwaAU9+7ZhXjeqHVkaHThLuzH0nZr0YpCDhygg=="], + + "@electron/rebuild/node-gyp/which/isexe": ["isexe@3.1.5", "", {}, "sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w=="], + + "@electron/rebuild/yargs/cliui/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "@electron/rebuild/yargs/cliui/wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], + + "@electron/rebuild/yargs/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + + "@electron/rebuild/yargs/string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "@electron/universal/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + "@jsx-email/cli/tailwindcss/chokidar/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], "@jsx-email/cli/tailwindcss/chokidar/readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="], @@ -5536,6 +6542,8 @@ "@modelcontextprotocol/sdk/express/type-is/media-typer": ["media-typer@1.1.0", "", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="], + "@npmcli/move-file/rimraf/glob/minimatch": ["minimatch@3.1.5", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w=="], + "@octokit/auth-app/@octokit/request-error/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@27.0.0", "", {}, "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA=="], "@octokit/auth-app/@octokit/request/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@27.0.0", "", {}, "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA=="], @@ -5554,6 +6562,8 @@ "@octokit/rest/@octokit/core/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@27.0.0", "", {}, "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA=="], + "@opencode-ai/desktop-electron/@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=="], "@slack/web-api/form-data/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], @@ -5562,6 +6572,8 @@ "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=="], + "archiver-utils/glob/jackspeak/@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="], "archiver-utils/glob/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], @@ -5580,10 +6592,28 @@ "babel-plugin-module-resolver/glob/path-scurry/minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="], + "cacache/glob/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="], + + "cacache/tar/minizlib/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], + + "cli-truncate/string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "dir-compare/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + "editorconfig/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + "electron-builder/yargs/cliui/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "electron-builder/yargs/cliui/wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], + + "electron-builder/yargs/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + + "electron-builder/yargs/string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + "esbuild-plugin-copy/chokidar/readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + "filelist/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + "gray-matter/js-yaml/argparse/sprintf-js": ["sprintf-js@1.0.3", "", {}, "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="], "js-beautify/glob/jackspeak/@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="], @@ -5592,6 +6622,10 @@ "js-beautify/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], + "node-gyp/glob/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="], + + "node-gyp/tar/minizlib/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], + "opencontrol/@modelcontextprotocol/sdk/express/accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="], "opencontrol/@modelcontextprotocol/sdk/express/body-parser": ["body-parser@2.2.2", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.3", "http-errors": "^2.0.0", "iconv-lite": "^0.7.0", "on-finished": "^2.4.1", "qs": "^6.14.1", "raw-body": "^3.0.1", "type-is": "^2.0.1" } }, "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA=="], @@ -5614,6 +6648,8 @@ "opencontrol/@modelcontextprotocol/sdk/express/type-is": ["type-is@2.0.1", "", { "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw=="], + "ora/bl/buffer/ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], + "pkg-up/find-up/locate-path/p-locate": ["p-locate@3.0.0", "", { "dependencies": { "p-limit": "^2.0.0" } }, "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ=="], "pkg-up/find-up/locate-path/path-exists": ["path-exists@3.0.0", "", {}, "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ=="], @@ -5626,10 +6662,18 @@ "rimraf/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], + "sqlite3/tar/minizlib/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], + + "tar-fs/tar-stream/bl/buffer": ["buffer@5.7.1", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" } }, "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ=="], + + "temp/rimraf/glob/minimatch": ["minimatch@3.1.5", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w=="], + "tw-to-css/tailwindcss/chokidar/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], "tw-to-css/tailwindcss/chokidar/readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="], + "wide-align/string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + "@astrojs/check/yargs/cliui/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], "@astrojs/check/yargs/string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], @@ -5662,8 +6706,28 @@ "@aws-sdk/token-providers/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.1.2", "", {}, "sha512-l63NF9y/cLROq/yqKXSLtcMeeyOfnSQlfMSlzFt/K73oIaD8DGaQWd7Z34X9GPiKqP5rbSh84Hl4bOlLcjiSrQ=="], + "@electron/rebuild/node-gyp/make-fetch-happen/cacache/@npmcli/fs": ["@npmcli/fs@4.0.0", "", { "dependencies": { "semver": "^7.3.5" } }, "sha512-/xGlezI6xfGO9NwuJlnwz/K14qD1kCSAGtacBHnGzeAIuJGazcp45KP5NuyARXoKb7cwulAGWVsbeSxdG/cb0Q=="], + + "@electron/rebuild/node-gyp/make-fetch-happen/cacache/fs-minipass": ["fs-minipass@3.0.3", "", { "dependencies": { "minipass": "^7.0.3" } }, "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw=="], + + "@electron/rebuild/node-gyp/make-fetch-happen/cacache/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="], + + "@electron/rebuild/node-gyp/make-fetch-happen/cacache/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], + + "@electron/rebuild/node-gyp/make-fetch-happen/cacache/minipass-collect": ["minipass-collect@2.0.1", "", { "dependencies": { "minipass": "^7.0.3" } }, "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw=="], + + "@electron/rebuild/node-gyp/make-fetch-happen/cacache/p-map": ["p-map@7.0.4", "", {}, "sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ=="], + + "@electron/rebuild/node-gyp/make-fetch-happen/cacache/unique-filename": ["unique-filename@4.0.0", "", { "dependencies": { "unique-slug": "^5.0.0" } }, "sha512-XSnEewXmQ+veP7xX2dS5Q4yZAvO40cBN2MWkJ7D/6sW4Dg6wYBNwM1Vrnz1FhH5AdeLIlUXRI9e28z1YZi71NQ=="], + + "@electron/rebuild/yargs/cliui/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "@electron/rebuild/yargs/string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + "@jsx-email/cli/tailwindcss/chokidar/readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + "@npmcli/move-file/rimraf/glob/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="], + "@solidjs/start/shiki/@shikijs/engine-javascript/oniguruma-to-es/regex": ["regex@5.1.1", "", { "dependencies": { "regex-utilities": "^2.3.0" } }, "sha512-dN5I359AVGPnwzJm2jN1k0W9LPZ+ePvoOeVMMfqIMFz53sSwXkxaJoxr50ptnsC771lK95BnTrVSZxq0b9yCGw=="], "@solidjs/start/shiki/@shikijs/engine-javascript/oniguruma-to-es/regex-recursion": ["regex-recursion@5.1.1", "", { "dependencies": { "regex": "^5.1.1", "regex-utilities": "^2.3.0" } }, "sha512-ae7SBCbzVNrIjgSbh7wMznPcQel1DNlDtzensnFxpiNpXt1U2ju/bHugH422r+4LAVS1FpW1YCwilmnNsjum9w=="], @@ -5676,12 +6740,20 @@ "babel-plugin-module-resolver/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + "cacache/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + + "electron-builder/yargs/cliui/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "electron-builder/yargs/string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + "js-beautify/glob/jackspeak/@isaacs/cliui/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="], "js-beautify/glob/jackspeak/@isaacs/cliui/wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="], "js-beautify/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + "node-gyp/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + "opencontrol/@modelcontextprotocol/sdk/express/accepts/negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="], "opencontrol/@modelcontextprotocol/sdk/express/type-is/media-typer": ["media-typer@1.1.0", "", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="], @@ -5694,10 +6766,24 @@ "rimraf/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + "tar-fs/tar-stream/bl/buffer/ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], + + "temp/rimraf/glob/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="], + "tw-to-css/tailwindcss/chokidar/readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], "@aws-sdk/credential-provider-cognito-identity/@aws-sdk/client-cognito-identity/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.1.2", "", {}, "sha512-l63NF9y/cLROq/yqKXSLtcMeeyOfnSQlfMSlzFt/K73oIaD8DGaQWd7Z34X9GPiKqP5rbSh84Hl4bOlLcjiSrQ=="], + "@electron/rebuild/node-gyp/make-fetch-happen/cacache/glob/jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="], + + "@electron/rebuild/node-gyp/make-fetch-happen/cacache/glob/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], + + "@electron/rebuild/node-gyp/make-fetch-happen/cacache/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="], + + "@electron/rebuild/node-gyp/make-fetch-happen/cacache/unique-filename/unique-slug": ["unique-slug@5.0.0", "", { "dependencies": { "imurmurhash": "^0.1.4" } }, "sha512-9OdaqO5kwqR+1kVgHAhsp5vPNU0hnxRa26rBFNfNgM7M6pNtgzeBn3s/xbyCQL3dcjzOatcef6UUHpB/6MaETg=="], + + "@npmcli/move-file/rimraf/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + "archiver-utils/glob/jackspeak/@isaacs/cliui/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], "archiver-utils/glob/jackspeak/@isaacs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], @@ -5709,5 +6795,21 @@ "rimraf/glob/jackspeak/@isaacs/cliui/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], "rimraf/glob/jackspeak/@isaacs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], + + "temp/rimraf/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + + "@electron/rebuild/node-gyp/make-fetch-happen/cacache/glob/jackspeak/@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="], + + "@electron/rebuild/node-gyp/make-fetch-happen/cacache/glob/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], + + "@electron/rebuild/node-gyp/make-fetch-happen/cacache/glob/jackspeak/@isaacs/cliui/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="], + + "@electron/rebuild/node-gyp/make-fetch-happen/cacache/glob/jackspeak/@isaacs/cliui/wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="], + + "@electron/rebuild/node-gyp/make-fetch-happen/cacache/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + + "@electron/rebuild/node-gyp/make-fetch-happen/cacache/glob/jackspeak/@isaacs/cliui/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], + + "@electron/rebuild/node-gyp/make-fetch-happen/cacache/glob/jackspeak/@isaacs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], } } diff --git a/flake.lock b/flake.lock index 9efa1883b1..59eb118fa4 100644 --- a/flake.lock +++ b/flake.lock @@ -2,11 +2,11 @@ "nodes": { "nixpkgs": { "locked": { - "lastModified": 1770812194, - "narHash": "sha256-OH+lkaIKAvPXR3nITO7iYZwew2nW9Y7Xxq0yfM/UcUU=", + "lastModified": 1772091128, + "narHash": "sha256-TnrYykX8Mf/Ugtkix6V+PjW7miU2yClA6uqWl/v6KWM=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "8482c7ded03bae7550f3d69884f1e611e3bd19e8", + "rev": "3f0336406035444b4a24b942788334af5f906259", "type": "github" }, "original": { diff --git a/github/index.ts b/github/index.ts index da310178a7..1a0a992622 100644 --- a/github/index.ts +++ b/github/index.ts @@ -8,6 +8,7 @@ import type { Context as GitHubContext } from "@actions/github/lib/context" import type { IssueCommentEvent, PullRequestReviewCommentEvent } from "@octokit/webhooks-types" import { createOpencodeClient } from "@opencode-ai/sdk" import { spawn } from "node:child_process" +import { setTimeout as sleep } from "node:timers/promises" type GitHubAuthor = { login: string @@ -281,7 +282,7 @@ async function assertOpencodeConnected() { connected = true break } catch (e) {} - await Bun.sleep(300) + await sleep(300) } while (retry++ < 30) if (!connected) { diff --git a/infra/console.ts b/infra/console.ts index 3f3c2b8d93..128e069863 100644 --- a/infra/console.ts +++ b/infra/console.ts @@ -100,29 +100,47 @@ export const stripeWebhook = new stripe.WebhookEndpoint("StripeWebhookEndpoint", ], }) -const zenProduct = new stripe.Product("ZenBlack", { +const zenLiteProduct = new stripe.Product("ZenLite", { + name: "OpenCode Go", +}) +const zenLitePrice = new stripe.Price("ZenLitePrice", { + product: zenLiteProduct.id, + currency: "usd", + recurring: { + interval: "month", + intervalCount: 1, + }, + unitAmount: 1000, +}) +const ZEN_LITE_PRICE = new sst.Linkable("ZEN_LITE_PRICE", { + properties: { + product: zenLiteProduct.id, + price: zenLitePrice.id, + }, +}) + +const zenBlackProduct = new stripe.Product("ZenBlack", { name: "OpenCode Black", }) -const zenPriceProps = { - product: zenProduct.id, +const zenBlackPriceProps = { + product: zenBlackProduct.id, currency: "usd", recurring: { interval: "month", intervalCount: 1, }, } -const zenPrice200 = new stripe.Price("ZenBlackPrice", { ...zenPriceProps, unitAmount: 20000 }) -const zenPrice100 = new stripe.Price("ZenBlack100Price", { ...zenPriceProps, unitAmount: 10000 }) -const zenPrice20 = new stripe.Price("ZenBlack20Price", { ...zenPriceProps, unitAmount: 2000 }) +const zenBlackPrice200 = new stripe.Price("ZenBlackPrice", { ...zenBlackPriceProps, unitAmount: 20000 }) +const zenBlackPrice100 = new stripe.Price("ZenBlack100Price", { ...zenBlackPriceProps, unitAmount: 10000 }) +const zenBlackPrice20 = new stripe.Price("ZenBlack20Price", { ...zenBlackPriceProps, unitAmount: 2000 }) const ZEN_BLACK_PRICE = new sst.Linkable("ZEN_BLACK_PRICE", { properties: { - product: zenProduct.id, - plan200: zenPrice200.id, - plan100: zenPrice100.id, - plan20: zenPrice20.id, + product: zenBlackProduct.id, + plan200: zenBlackPrice200.id, + plan100: zenBlackPrice100.id, + plan20: zenBlackPrice20.id, }, }) -const ZEN_BLACK_LIMITS = new sst.Secret("ZEN_BLACK_LIMITS") const ZEN_MODELS = [ new sst.Secret("ZEN_MODELS1"), @@ -195,7 +213,8 @@ new sst.cloudflare.x.SolidStart("Console", { AWS_SES_ACCESS_KEY_ID, AWS_SES_SECRET_ACCESS_KEY, ZEN_BLACK_PRICE, - ZEN_BLACK_LIMITS, + ZEN_LITE_PRICE, + new sst.Secret("ZEN_LIMITS"), new sst.Secret("ZEN_SESSION_SECRET"), ...ZEN_MODELS, ...($dev diff --git a/nix/hashes.json b/nix/hashes.json index d07b8f0f6b..2190feb256 100644 --- a/nix/hashes.json +++ b/nix/hashes.json @@ -1,8 +1,8 @@ { "nodeModules": { - "x86_64-linux": "sha256-fjrvCgQ2PHYxzw8NsiEHOcor46qN95/cfilFHFqCp/k=", - "aarch64-linux": "sha256-xWp4LLJrbrCPFL1F6SSbProq/t/az4CqhTcymPvjOBQ=", - "aarch64-darwin": "sha256-Wbfyy/bruFHKUWsyJ2aiPXAzLkk5MNBfN6QdGPQwZS0=", - "x86_64-darwin": "sha256-wDnMbiaBCRj5STkaLoVCZTdXVde+/YKfwWzwJZ1AJXQ=" + "x86_64-linux": "sha256-+SMpaj0jeIHjlddAu6QIwojmWFVIiA8/G32hiQMjcOk=", + "aarch64-linux": "sha256-uo63IF6OCMab+O3ngn1sVxqIGJMm04HXuDgIRmXNTNk=", + "aarch64-darwin": "sha256-yB2tWm6AsX6UifnDqe7VldhN5zTQkDoqZ87AGQYjxT4=", + "x86_64-darwin": "sha256-nNhtqMSG4/y+uxjj14Jc5QQ7X6hQli9ni4v56XAvaAU=" } } diff --git a/nix/node_modules.nix b/nix/node_modules.nix index e918846c24..6c188c07cf 100644 --- a/nix/node_modules.nix +++ b/nix/node_modules.nix @@ -31,6 +31,7 @@ stdenvNoCC.mkDerivation { ../package.json ../patches ../install # required by desktop build (cli.rs include_str!) + ../.github/TEAM_MEMBERS # required by @opencode-ai/script ] ); }; diff --git a/package.json b/package.json index 2e7c1172aa..530ab937c2 100644 --- a/package.json +++ b/package.json @@ -4,11 +4,12 @@ "description": "AI-powered development tool", "private": true, "type": "module", - "packageManager": "bun@1.3.9", + "packageManager": "bun@1.3.10", "scripts": { "dev": "bun run --cwd packages/opencode --conditions=browser src/index.ts", "dev:desktop": "bun --cwd packages/desktop tauri dev", "dev:web": "bun --cwd packages/app dev", + "dev:storybook": "bun --cwd packages/storybook storybook", "typecheck": "bun turbo typecheck", "prepare": "husky", "random": "echo 'Random script'", @@ -35,13 +36,13 @@ "@tsconfig/bun": "1.0.9", "@cloudflare/workers-types": "4.20251008.0", "@openauthjs/openauth": "0.0.0-20250322224806", - "@pierre/diffs": "1.1.0-beta.13", + "@pierre/diffs": "1.1.0-beta.18", "@solid-primitives/storage": "4.3.3", "@tailwindcss/vite": "4.1.11", "diff": "8.0.2", "dompurify": "3.3.1", - "drizzle-kit": "1.0.0-beta.12-a5629fb", - "drizzle-orm": "1.0.0-beta.12-a5629fb", + "drizzle-kit": "1.0.0-beta.16-ea816b6", + "drizzle-orm": "1.0.0-beta.16-ea816b6", "ai": "5.0.124", "hono": "4.10.7", "hono-openapi": "1.1.2", @@ -70,12 +71,13 @@ "@actions/artifact": "5.0.1", "@tsconfig/bun": "catalog:", "@types/mime-types": "3.0.1", + "@typescript/native-preview": "catalog:", "glob": "13.0.5", "husky": "9.1.7", "prettier": "3.6.2", "semver": "^7.6.0", "sst": "3.18.10", - "turbo": "2.5.6" + "turbo": "2.8.13" }, "dependencies": { "@aws-sdk/client-s3": "3.933.0", @@ -98,7 +100,8 @@ "protobufjs", "tree-sitter", "tree-sitter-bash", - "web-tree-sitter" + "web-tree-sitter", + "electron" ], "overrides": { "@types/bun": "catalog:", diff --git a/packages/app/create-effect-simplification-spec.md b/packages/app/create-effect-simplification-spec.md new file mode 100644 index 0000000000..cc101ab059 --- /dev/null +++ b/packages/app/create-effect-simplification-spec.md @@ -0,0 +1,515 @@ +# CreateEffect Simplification Implementation Spec + +Reduce reactive misuse across `packages/app`. + +--- + +## Context + +This work targets `packages/app/src`, which currently has 101 `createEffect` calls across 37 files. + +The biggest clusters are `pages/session.tsx` (19), `pages/layout.tsx` (13), `pages/session/file-tabs.tsx` (6), and several context providers that mirror one store into another. + +Key issues from the audit: + +- Derived state is being written through effects instead of computed directly +- Session and file resets are handled by watch-and-clear effects instead of keyed state boundaries +- User-driven actions are hidden inside reactive effects +- Context layers mirror and hydrate child stores with multiple sync effects +- Several areas repeat the same imperative trigger pattern in multiple effects + +Keep the implementation focused on removing unnecessary effects, not on broad UI redesign. + +## Goals + +- Cut high-churn `createEffect` usage in the hottest files first +- Replace effect-driven derived state with reactive derivation +- Replace reset-on-key effects with keyed ownership boundaries +- Move event-driven work to direct actions and write paths +- Remove mirrored store hydration where a single source of truth can exist +- Leave necessary external sync effects in place, but make them narrower and clearer + +## Non-Goals + +- Do not rewrite unrelated component structure just to reduce the count +- Do not change product behavior, navigation flow, or persisted data shape unless required for a cleaner write boundary +- Do not remove effects that bridge to DOM, editors, polling, or external APIs unless there is a clearly safer equivalent +- Do not attempt a repo-wide cleanup outside `packages/app` + +## Effect Taxonomy And Replacement Rules + +Use these rules during implementation. + +### Prefer `createMemo` + +Use `createMemo` when the target value is pure derived state from other signals or stores. + +Do this when an effect only reads reactive inputs and writes another reactive value that could be computed instead. + +Apply this to: + +- `packages/app/src/pages/session.tsx:141` +- `packages/app/src/pages/layout.tsx:557` +- `packages/app/src/components/terminal.tsx:261` +- `packages/app/src/components/session/session-header.tsx:309` + +Rules: + +- If no external system is touched, do not use `createEffect` +- Derive once, then read the memo where needed +- If normalization is required, prefer normalizing at the write boundary before falling back to a memo + +### Prefer Keyed Remounts + +Use keyed remounts when local UI state should reset because an identity changed. + +Do this with `sessionKey`, `scope()`, or another stable identity instead of watching the key and manually clearing signals. + +Apply this to: + +- `packages/app/src/pages/session.tsx:325` +- `packages/app/src/pages/session.tsx:336` +- `packages/app/src/pages/session.tsx:477` +- `packages/app/src/pages/session.tsx:869` +- `packages/app/src/pages/session.tsx:963` +- `packages/app/src/pages/session/message-timeline.tsx:149` +- `packages/app/src/context/file.tsx:100` + +Rules: + +- If the desired behavior is "new identity, fresh local state," key the owner subtree +- Keep state local to the keyed boundary so teardown and recreation handle the reset naturally + +### Prefer Event Handlers And Actions + +Use direct handlers, store actions, and async command functions when work happens because a user clicked, selected, reloaded, or navigated. + +Do this when an effect is just watching for a flag change, command token, or event-bus signal to trigger imperative logic. + +Apply this to: + +- `packages/app/src/pages/layout.tsx:484` +- `packages/app/src/pages/layout.tsx:652` +- `packages/app/src/pages/layout.tsx:776` +- `packages/app/src/pages/layout.tsx:1489` +- `packages/app/src/pages/layout.tsx:1519` +- `packages/app/src/components/file-tree.tsx:328` +- `packages/app/src/pages/session/terminal-panel.tsx:55` +- `packages/app/src/context/global-sync.tsx:148` +- Duplicated trigger sets in: + - `packages/app/src/pages/session/review-tab.tsx:122` + - `packages/app/src/pages/session/review-tab.tsx:130` + - `packages/app/src/pages/session/review-tab.tsx:138` + - `packages/app/src/pages/session/file-tabs.tsx:367` + - `packages/app/src/pages/session/file-tabs.tsx:378` + - `packages/app/src/pages/session/file-tabs.tsx:389` + - `packages/app/src/pages/session/use-session-hash-scroll.ts:144` + - `packages/app/src/pages/session/use-session-hash-scroll.ts:149` + - `packages/app/src/pages/session/use-session-hash-scroll.ts:167` + +Rules: + +- If the trigger is user intent, call the action at the source of that intent +- If the same imperative work is triggered from multiple places, extract one function and call it directly + +### Prefer `onMount` And `onCleanup` + +Use `onMount` and `onCleanup` for lifecycle-only setup and teardown. + +This is the right fit for subscriptions, one-time wiring, timers, and imperative integration that should not rerun for ordinary reactive changes. + +Use this when: + +- Setup should happen once per owner lifecycle +- Cleanup should always pair with teardown +- The work is not conceptually derived state + +### Keep `createEffect` When It Is A Real Bridge + +Keep `createEffect` when it synchronizes reactive data to an external imperative sink. + +Examples that should remain, though they may be narrowed or split: + +- DOM/editor sync in `packages/app/src/components/prompt-input.tsx:690` +- Scroll sync in `packages/app/src/pages/session.tsx:685` +- Scroll/hash sync in `packages/app/src/pages/session/use-session-hash-scroll.ts:149` +- External sync in: + - `packages/app/src/context/language.tsx:207` + - `packages/app/src/context/settings.tsx:110` + - `packages/app/src/context/sdk.tsx:26` +- Polling in: + - `packages/app/src/components/status-popover.tsx:59` + - `packages/app/src/components/dialog-select-server.tsx:273` + +Rules: + +- Keep the effect single-purpose +- Make dependencies explicit and narrow +- Avoid writing back into the same reactive graph unless absolutely required + +## Implementation Plan + +### Phase 0: Classification Pass + +Before changing code, tag each targeted effect as one of: derive, reset, event, lifecycle, or external bridge. + +Acceptance criteria: + +- Every targeted effect in this spec is tagged with a replacement strategy before refactoring starts +- Shared helpers to be introduced are identified up front to avoid repeating patterns + +### Phase 1: Derived-State Cleanup + +Tackle highest-value, lowest-risk derived-state cleanup first. + +Priority items: + +- Normalize tabs at write boundaries and remove `packages/app/src/pages/session.tsx:141` +- Stop syncing `workspaceOrder` in `packages/app/src/pages/layout.tsx:557` +- Make prompt slash filtering reactive so `packages/app/src/components/prompt-input.tsx:652` can be removed +- Replace other obvious derived-state effects in terminal and session header + +Acceptance criteria: + +- No behavior change in tab ordering, prompt filtering, terminal display, or header state +- Targeted derived-state effects are deleted, not just moved + +### Phase 2: Keyed Reset Cleanup + +Replace reset-on-key effects with keyed ownership boundaries. + +Priority items: + +- Key session-scoped UI and state by `sessionKey` +- Key file-scoped state by `scope()` +- Remove manual clear-and-reseed effects in session and file context + +Acceptance criteria: + +- Switching session or file scope recreates the intended local state cleanly +- No stale state leaks across session or scope changes +- Target reset effects are deleted + +### Phase 3: Event-Driven Work Extraction + +Move event-driven work out of reactive effects. + +Priority items: + +- Replace `globalStore.reload` effect dispatching with direct calls +- Split mixed-responsibility effect in `packages/app/src/pages/layout.tsx:1489` +- Collapse duplicated imperative trigger triplets into single functions +- Move file-tree and terminal-panel imperative work to explicit handlers + +Acceptance criteria: + +- User-triggered behavior still fires exactly once per intended action +- No effect remains whose only job is to notice a command-like state and trigger an imperative function + +### Phase 4: Context Ownership Cleanup + +Remove mirrored child-store hydration patterns. + +Priority items: + +- Remove child-store hydration mirrors in `packages/app/src/context/global-sync/child-store.ts:184`, `:190`, `:193` +- Simplify mirror logic in `packages/app/src/context/global-sync.tsx:130`, `:138` +- Revisit `packages/app/src/context/layout.tsx:424` if it still mirrors instead of deriving + +Acceptance criteria: + +- There is one clear source of truth for each synced value +- Child stores no longer need effect-based hydration to stay consistent +- Initialization and updates both work without manual mirror effects + +### Phase 5: Cleanup And Keeper Review + +Clean up remaining targeted hotspots and narrow the effects that should stay. + +Acceptance criteria: + +- Remaining `createEffect` calls in touched files are all true bridges or clearly justified lifecycle sync +- Mixed-responsibility effects are split into smaller units where still needed + +## Detailed Work Items By Area + +### 1. Normalize Tab State + +Files: + +- `packages/app/src/pages/session.tsx:141` + +Work: + +- Move tab normalization into the functions that create, load, or update tab state +- Make readers consume already-normalized tab data +- Remove the effect that rewrites derived tab state after the fact + +Rationale: + +- Tabs should become valid when written, not be repaired later +- This removes a feedback loop and makes state easier to trust + +Acceptance criteria: + +- The effect at `packages/app/src/pages/session.tsx:141` is removed +- Newly created and restored tabs are normalized before they enter local state +- Tab rendering still matches current behavior for valid and edge-case inputs + +### 2. Key Session-Owned State + +Files: + +- `packages/app/src/pages/session.tsx:325` +- `packages/app/src/pages/session.tsx:336` +- `packages/app/src/pages/session.tsx:477` +- `packages/app/src/pages/session.tsx:869` +- `packages/app/src/pages/session.tsx:963` +- `packages/app/src/pages/session/message-timeline.tsx:149` + +Work: + +- Identify state that should reset when `sessionKey` changes +- Move that state under a keyed subtree or keyed owner boundary +- Remove effects that watch `sessionKey` just to clear local state, refs, or temporary UI flags + +Rationale: + +- Session identity already defines the lifetime of this UI state +- Keyed ownership makes reset behavior automatic and easier to reason about + +Acceptance criteria: + +- The targeted reset effects are removed +- Changing sessions resets only the intended session-local state +- Scroll and editor state that should persist are not accidentally reset + +### 3. Derive Workspace Order + +Files: + +- `packages/app/src/pages/layout.tsx:557` + +Work: + +- Stop writing `workspaceOrder` from live workspace data in an effect +- Represent user overrides separately from live workspace data +- Compute effective order from current data plus overrides with a memo or pure helper + +Rationale: + +- Persisted user intent and live source data should not mirror each other through an effect +- A computed effective order avoids drift and racey resync behavior + +Acceptance criteria: + +- The effect at `packages/app/src/pages/layout.tsx:557` is removed +- Workspace order updates correctly when workspaces appear, disappear, or are reordered by the user +- User overrides persist without requiring a sync-back effect + +### 4. Remove Child-Store Mirrors + +Files: + +- `packages/app/src/context/global-sync.tsx:130` +- `packages/app/src/context/global-sync.tsx:138` +- `packages/app/src/context/global-sync.tsx:148` +- `packages/app/src/context/global-sync/child-store.ts:184` +- `packages/app/src/context/global-sync/child-store.ts:190` +- `packages/app/src/context/global-sync/child-store.ts:193` +- `packages/app/src/context/layout.tsx:424` + +Work: + +- Trace the actual ownership of global and child store values +- Replace hydration and mirror effects with explicit initialization and direct updates +- Remove the `globalStore.reload` event-bus pattern and call the needed reload paths directly + +Rationale: + +- Mirrors make it hard to tell which state is authoritative +- Event-bus style state toggles hide control flow and create accidental reruns + +Acceptance criteria: + +- Child store hydration no longer depends on effect-based copying +- Reload work can be followed from the event source to the handler without a reactive relay +- State remains correct on first load, child creation, and subsequent updates + +### 5. Key File-Scoped State + +Files: + +- `packages/app/src/context/file.tsx:100` + +Work: + +- Move file-scoped local state under a boundary keyed by `scope()` +- Remove any effect that watches `scope()` only to reset file-local state + +Rationale: + +- File scope changes are identity changes +- Keyed ownership gives a cleaner reset than manual clear logic + +Acceptance criteria: + +- The effect at `packages/app/src/context/file.tsx:100` is removed +- Switching scopes resets only scope-local state +- No previous-scope data appears after a scope change + +### 6. Split Layout Side Effects + +Files: + +- `packages/app/src/pages/layout.tsx:1489` +- Related event-driven effects near `packages/app/src/pages/layout.tsx:484`, `:652`, `:776`, `:1519` + +Work: + +- Break the mixed-responsibility effect at `:1489` into direct actions and smaller bridge effects only where required +- Move user-triggered branches into the actual command or handler that causes them +- Remove any branch that only exists because one effect is handling unrelated concerns + +Rationale: + +- Mixed effects hide cause and make reruns hard to predict +- Smaller units reduce accidental coupling and make future cleanup safer + +Acceptance criteria: + +- The effect at `packages/app/src/pages/layout.tsx:1489` no longer mixes unrelated responsibilities +- Event-driven branches execute from direct handlers +- Remaining effects in this area each have one clear external sync purpose + +### 7. Remove Duplicate Triggers + +Files: + +- `packages/app/src/pages/session/review-tab.tsx:122` +- `packages/app/src/pages/session/review-tab.tsx:130` +- `packages/app/src/pages/session/review-tab.tsx:138` +- `packages/app/src/pages/session/file-tabs.tsx:367` +- `packages/app/src/pages/session/file-tabs.tsx:378` +- `packages/app/src/pages/session/file-tabs.tsx:389` +- `packages/app/src/pages/session/use-session-hash-scroll.ts:144` +- `packages/app/src/pages/session/use-session-hash-scroll.ts:149` +- `packages/app/src/pages/session/use-session-hash-scroll.ts:167` + +Work: + +- Extract one explicit imperative function per behavior +- Call that function from each source event instead of replicating the same effect pattern multiple times +- Preserve the scroll-sync effect that is truly syncing with the DOM, but remove duplicate trigger scaffolding around it + +Rationale: + +- Duplicate triggers make it easy to miss a case or fire twice +- One named action is easier to test and reason about + +Acceptance criteria: + +- Repeated imperative effect triplets are collapsed into shared functions +- Scroll behavior still works, including hash-based navigation +- No duplicate firing is introduced + +### 8. Make Prompt Filtering Reactive + +Files: + +- `packages/app/src/components/prompt-input.tsx:652` +- Keep `packages/app/src/components/prompt-input.tsx:690` as needed + +Work: + +- Convert slash filtering into a pure reactive derivation from the current input and candidate command list +- Keep only the editor or DOM bridge effect if it is still needed for imperative syncing + +Rationale: + +- Filtering is classic derived state +- It should not need an effect if it can be computed from current inputs + +Acceptance criteria: + +- The effect at `packages/app/src/components/prompt-input.tsx:652` is removed +- Filtered slash-command results update correctly as the input changes +- The editor sync effect at `:690` still behaves correctly + +### 9. Clean Up Smaller Derived-State Cases + +Files: + +- `packages/app/src/components/terminal.tsx:261` +- `packages/app/src/components/session/session-header.tsx:309` + +Work: + +- Replace effect-written local state with memos or inline derivation +- Remove intermediate setters when the value can be computed directly + +Rationale: + +- These are low-risk wins that reinforce the same pattern +- They also help keep follow-up cleanup consistent + +Acceptance criteria: + +- Targeted effects are removed +- UI output remains unchanged under the same inputs + +## Verification And Regression Checks + +Run focused checks after each phase, not only at the end. + +### Suggested Verification + +- Switch between sessions rapidly and confirm local session UI resets only where intended +- Open, close, and reorder tabs and confirm order and normalization remain stable +- Change workspaces, reload workspace data, and verify effective ordering is correct +- Change file scope and confirm stale file state does not bleed across scopes +- Trigger layout actions that previously depended on effects and confirm they still fire once +- Use slash commands in the prompt and verify filtering updates as you type +- Test review tab, file tab, and hash-scroll flows for duplicate or missing triggers +- Verify global sync initialization, reload, and child-store creation paths + +### Regression Checks + +- No accidental infinite reruns +- No double-firing network or command actions +- No lost cleanup for listeners, timers, or scroll handlers +- No preserved stale state after identity changes +- No removed effect that was actually bridging to DOM or an external API + +If available, add or update tests around pure helpers introduced during this cleanup. + +Favor tests for derived ordering, normalization, and action extraction, since those are easiest to lock down. + +## Definition Of Done + +This work is done when all of the following are true: + +- The highest-leverage targets in this spec are implemented +- Each removed effect has been replaced by a clearer pattern: memo, keyed boundary, direct action, or lifecycle hook +- The "should remain" effects still exist only where they serve a real external sync purpose +- Touched files have fewer mixed-responsibility effects and clearer ownership of state +- Manual verification covers session switching, file scope changes, workspace ordering, prompt filtering, and reload flows +- No behavior regressions are found in the targeted areas + +A reduced raw `createEffect` count is helpful, but it is not the main success metric. + +The main success metric is clearer ownership and fewer effect-driven state repairs. + +## Risks And Rollout Notes + +Main risks: + +- Keyed remounts can reset too much if state boundaries are drawn too high +- Store mirror removal can break initialization order if ownership is not mapped first +- Moving event work out of effects can accidentally skip triggers that were previously implicit + +Rollout notes: + +- Land in small phases, with each phase keeping the app behaviorally stable +- Prefer isolated PRs by phase or by file cluster, especially for context-store changes +- Review each remaining effect in touched files and leave it only if it clearly bridges to something external diff --git a/packages/app/e2e/AGENTS.md b/packages/app/e2e/AGENTS.md index 59662dbea5..8bfbd111b2 100644 --- a/packages/app/e2e/AGENTS.md +++ b/packages/app/e2e/AGENTS.md @@ -71,6 +71,12 @@ test("test description", async ({ page, sdk, gotoSession }) => { - `closeDialog(page, dialog)` - Close any dialog - `openSidebar(page)` / `closeSidebar(page)` - Toggle sidebar - `withSession(sdk, title, callback)` - Create temp session +- `withProject(...)` - Create temp project/workspace +- `sessionIDFromUrl(url)` - Read session ID from URL +- `slugFromUrl(url)` - Read workspace slug from URL +- `waitSlug(page, skip?)` - Wait for resolved workspace slug +- `trackSession(sessionID, directory?)` - Register session for fixture cleanup +- `trackDirectory(directory)` - Register directory for fixture cleanup - `clickListItem(container, filter)` - Click list item by key/text **Selectors** (`selectors.ts`): @@ -109,7 +115,7 @@ import { test, expect } from "@playwright/test" ### Error Handling -Tests should clean up after themselves: +Tests should clean up after themselves. Prefer fixture-managed cleanup: ```typescript test("test with cleanup", async ({ page, sdk, gotoSession }) => { @@ -120,6 +126,11 @@ test("test with cleanup", async ({ page, sdk, gotoSession }) => { }) ``` +- Prefer `withSession(...)` for temp sessions +- In `withProject(...)` tests that create sessions or extra workspaces, call `trackSession(sessionID, directory?)` and `trackDirectory(directory)` +- This lets fixture teardown abort, wait for idle, and clean up safely under CI concurrency +- Avoid calling `sdk.session.delete(...)` directly + ### Timeouts Default: 60s per test, 10s per assertion. Override when needed: @@ -161,9 +172,10 @@ await page.keyboard.press(`${modKey}+Comma`) // Open settings 1. Choose appropriate folder or create new one 2. Import from `../fixtures` 3. Use helper functions from `../actions` and `../selectors` -4. Clean up any created resources -5. Use specific selectors (avoid CSS classes) -6. Test one feature per test file +4. When validating routing, use shared helpers from `../actions`. Workspace URL slugs can be canonicalized on Windows, so assert against canonical or resolved workspace slugs. +5. Clean up any created resources +6. Use specific selectors (avoid CSS classes) +7. Test one feature per test file ## Local Development diff --git a/packages/app/e2e/actions.ts b/packages/app/e2e/actions.ts index a7ccba6175..86147dc65d 100644 --- a/packages/app/e2e/actions.ts +++ b/packages/app/e2e/actions.ts @@ -3,12 +3,12 @@ import fs from "node:fs/promises" import os from "node:os" import path from "node:path" import { execSync } from "node:child_process" -import { modKey, serverUrl } from "./utils" +import { createSdk, modKey, resolveDirectory, serverUrl } from "./utils" import { - sessionItemSelector, dropdownMenuTriggerSelector, dropdownMenuContentSelector, projectMenuTriggerSelector, + projectCloseMenuSelector, projectWorkspacesToggleSelector, titlebarRightSelector, popoverBodySelector, @@ -18,7 +18,6 @@ import { workspaceItemSelector, workspaceMenuTriggerSelector, } from "./selectors" -import type { createSdk } from "./utils" export async function defocus(page: Page) { await page @@ -61,9 +60,9 @@ export async function closeDialog(page: Page, dialog: Locator) { } export async function isSidebarClosed(page: Page) { - const main = page.locator("main") - const classes = (await main.getAttribute("class")) ?? "" - return classes.includes("xl:border-l") + const button = page.getByRole("button", { name: /toggle sidebar/i }).first() + await expect(button).toBeVisible() + return (await button.getAttribute("aria-expanded")) !== "true" } export async function toggleSidebar(page: Page) { @@ -75,48 +74,34 @@ export async function openSidebar(page: Page) { if (!(await isSidebarClosed(page))) return const button = page.getByRole("button", { name: /toggle sidebar/i }).first() - const visible = await button - .isVisible() - .then((x) => x) - .catch(() => false) + await button.click() - if (visible) await button.click() - if (!visible) await toggleSidebar(page) - - const main = page.locator("main") - const opened = await expect(main) - .not.toHaveClass(/xl:border-l/, { timeout: 1500 }) + const opened = await expect(button) + .toHaveAttribute("aria-expanded", "true", { timeout: 1500 }) .then(() => true) .catch(() => false) if (opened) return await toggleSidebar(page) - await expect(main).not.toHaveClass(/xl:border-l/) + await expect(button).toHaveAttribute("aria-expanded", "true") } export async function closeSidebar(page: Page) { if (await isSidebarClosed(page)) return const button = page.getByRole("button", { name: /toggle sidebar/i }).first() - const visible = await button - .isVisible() - .then((x) => x) - .catch(() => false) + await button.click() - if (visible) await button.click() - if (!visible) await toggleSidebar(page) - - const main = page.locator("main") - const closed = await expect(main) - .toHaveClass(/xl:border-l/, { timeout: 1500 }) + const closed = await expect(button) + .toHaveAttribute("aria-expanded", "false", { timeout: 1500 }) .then(() => true) .catch(() => false) if (closed) return await toggleSidebar(page) - await expect(main).toHaveClass(/xl:border-l/) + await expect(button).toHaveAttribute("aria-expanded", "false") } export async function openSettings(page: Page) { @@ -197,17 +182,48 @@ export async function createTestProject() { await fs.writeFile(path.join(root, "README.md"), "# e2e\n") execSync("git init", { cwd: root, stdio: "ignore" }) + execSync("git config core.fsmonitor false", { cwd: root, stdio: "ignore" }) execSync("git add -A", { cwd: root, stdio: "ignore" }) execSync('git -c user.name="e2e" -c user.email="e2e@example.com" commit -m "init" --allow-empty', { cwd: root, stdio: "ignore", }) - return root + return resolveDirectory(root) } export async function cleanupTestProject(directory: string) { - await fs.rm(directory, { recursive: true, force: true }).catch(() => undefined) + try { + execSync("git fsmonitor--daemon stop", { cwd: directory, stdio: "ignore" }) + } catch {} + await fs.rm(directory, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }).catch(() => undefined) +} + +export function slugFromUrl(url: string) { + return /\/([^/]+)\/session(?:[/?#]|$)/.exec(url)?.[1] ?? "" +} + +export async function waitSlug(page: Page, skip: string[] = []) { + let prev = "" + let next = "" + await expect + .poll( + () => { + const slug = slugFromUrl(page.url()) + if (!slug) return "" + if (skip.includes(slug)) return "" + if (slug !== prev) { + prev = slug + next = "" + return "" + } + next = slug + return slug + }, + { timeout: 45_000 }, + ) + .not.toBe("") + return next } export function sessionIDFromUrl(url: string) { @@ -216,7 +232,7 @@ export function sessionIDFromUrl(url: string) { } export async function hoverSessionItem(page: Page, sessionID: string) { - const sessionEl = page.locator(sessionItemSelector(sessionID)).first() + const sessionEl = page.locator(`[data-session-id="${sessionID}"]`).last() await expect(sessionEl).toBeVisible() await sessionEl.hover() return sessionEl @@ -317,6 +333,57 @@ export async function clickListItem( return item } +async function status(sdk: ReturnType, sessionID: string) { + const data = await sdk.session + .status() + .then((x) => x.data ?? {}) + .catch(() => undefined) + return data?.[sessionID] +} + +async function stable(sdk: ReturnType, sessionID: string, timeout = 10_000) { + let prev = "" + await expect + .poll( + async () => { + const info = await sdk.session + .get({ sessionID }) + .then((x) => x.data) + .catch(() => undefined) + if (!info) return true + const next = `${info.title}:${info.time.updated ?? info.time.created}` + if (next !== prev) { + prev = next + return false + } + return true + }, + { timeout }, + ) + .toBe(true) +} + +export async function waitSessionIdle(sdk: ReturnType, sessionID: string, timeout = 30_000) { + await expect.poll(() => status(sdk, sessionID).then((x) => !x || x.type === "idle"), { timeout }).toBe(true) +} + +export async function cleanupSession(input: { + sessionID: string + directory?: string + sdk?: ReturnType +}) { + const sdk = input.sdk ?? (input.directory ? createSdk(input.directory) : undefined) + if (!sdk) throw new Error("cleanupSession requires sdk or directory") + await waitSessionIdle(sdk, input.sessionID, 5_000).catch(() => undefined) + const current = await status(sdk, input.sessionID).catch(() => undefined) + if (current && current.type !== "idle") { + await sdk.session.abort({ sessionID: input.sessionID }).catch(() => undefined) + await waitSessionIdle(sdk, input.sessionID).catch(() => undefined) + } + await stable(sdk, input.sessionID).catch(() => undefined) + await sdk.session.delete({ sessionID: input.sessionID }).catch(() => undefined) +} + export async function withSession( sdk: ReturnType, title: string, @@ -328,7 +395,7 @@ export async function withSession( try { return await callback(session) } finally { - await sdk.session.delete({ sessionID: session.id }).catch(() => undefined) + await cleanupSession({ sdk, sessionID: session.id }) } } @@ -441,6 +508,57 @@ export async function seedSessionPermission( return { id: result.id } } +export async function seedSessionTask( + sdk: ReturnType, + input: { + sessionID: string + description: string + prompt: string + subagentType?: string + }, +) { + const text = [ + "Your only valid response is one task tool call.", + `Use this JSON input: ${JSON.stringify({ + description: input.description, + prompt: input.prompt, + subagent_type: input.subagentType ?? "general", + })}`, + "Do not output plain text.", + "Wait for the task to start and return the child session id.", + ].join("\n") + + const result = await seed({ + sdk, + sessionID: input.sessionID, + prompt: text, + timeout: 90_000, + probe: async () => { + const messages = await sdk.session.messages({ sessionID: input.sessionID, limit: 50 }).then((x) => x.data ?? []) + const part = messages + .flatMap((message) => message.parts) + .find((part) => { + if (part.type !== "tool" || part.tool !== "task") return false + if (part.state.input?.description !== input.description) return false + return typeof part.state.metadata?.sessionId === "string" && part.state.metadata.sessionId.length > 0 + }) + + if (!part) return + const id = part.state.metadata?.sessionId + if (typeof id !== "string" || !id) return + const child = await sdk.session + .get({ sessionID: id }) + .then((x) => x.data) + .catch(() => undefined) + if (!child?.id) return + return { sessionID: id } + }, + }) + + if (!result) throw new Error("Timed out seeding task tool") + return result +} + export async function seedSessionTodos( sdk: ReturnType, input: { @@ -515,32 +633,42 @@ export async function openProjectMenu(page: Page, projectSlug: string) { const trigger = page.locator(projectMenuTriggerSelector(projectSlug)).first() await expect(trigger).toHaveCount(1) + const menu = page + .locator(dropdownMenuContentSelector) + .filter({ has: page.locator(projectCloseMenuSelector(projectSlug)) }) + .first() + const close = menu.locator(projectCloseMenuSelector(projectSlug)).first() + + const clicked = await trigger + .click({ timeout: 1500 }) + .then(() => true) + .catch(() => false) + + if (clicked) { + const opened = await menu + .waitFor({ state: "visible", timeout: 1500 }) + .then(() => true) + .catch(() => false) + if (opened) { + await expect(close).toBeVisible() + return menu + } + } + await trigger.focus() await page.keyboard.press("Enter") - const menu = page.locator(dropdownMenuContentSelector).first() const opened = await menu .waitFor({ state: "visible", timeout: 1500 }) .then(() => true) .catch(() => false) if (opened) { - const viewport = page.viewportSize() - const x = viewport ? Math.max(viewport.width - 5, 0) : 1200 - const y = viewport ? Math.max(viewport.height - 5, 0) : 800 - await page.mouse.move(x, y) + await expect(close).toBeVisible() return menu } - await trigger.click({ force: true }) - - await expect(menu).toBeVisible() - - const viewport = page.viewportSize() - const x = viewport ? Math.max(viewport.width - 5, 0) : 1200 - const y = viewport ? Math.max(viewport.height - 5, 0) : 800 - await page.mouse.move(x, y) - return menu + throw new Error(`Failed to open project menu: ${projectSlug}`) } export async function setWorkspacesEnabled(page: Page, projectSlug: string, enabled: boolean) { @@ -553,11 +681,18 @@ export async function setWorkspacesEnabled(page: Page, projectSlug: string, enab if (current === enabled) return - await openProjectMenu(page, projectSlug) + const flip = async (timeout?: number) => { + const menu = await openProjectMenu(page, projectSlug) + const toggle = menu.locator(projectWorkspacesToggleSelector(projectSlug)).first() + await expect(toggle).toBeVisible() + return toggle.click({ force: true, timeout }) + } - const toggle = page.locator(projectWorkspacesToggleSelector(projectSlug)).first() - await expect(toggle).toBeVisible() - await toggle.click({ force: true }) + const flipped = await flip(1500) + .then(() => true) + .catch(() => false) + + if (!flipped) await flip() const expected = enabled ? "New workspace" : "New session" await expect(page.getByRole("button", { name: expected }).first()).toBeVisible() diff --git a/packages/app/e2e/app/home.spec.ts b/packages/app/e2e/app/home.spec.ts index f21dc40ec2..a3cedf7cb6 100644 --- a/packages/app/e2e/app/home.spec.ts +++ b/packages/app/e2e/app/home.spec.ts @@ -1,17 +1,17 @@ import { test, expect } from "../fixtures" -import { serverName } from "../utils" +import { serverNamePattern } from "../utils" test("home renders and shows core entrypoints", async ({ page }) => { await page.goto("/") await expect(page.getByRole("button", { name: "Open project" }).first()).toBeVisible() - await expect(page.getByRole("button", { name: serverName })).toBeVisible() + await expect(page.getByRole("button", { name: serverNamePattern })).toBeVisible() }) test("server picker dialog opens from home", async ({ page }) => { await page.goto("/") - const trigger = page.getByRole("button", { name: serverName }) + const trigger = page.getByRole("button", { name: serverNamePattern }) await expect(trigger).toBeVisible() await trigger.click() diff --git a/packages/app/e2e/app/server-default.spec.ts b/packages/app/e2e/app/server-default.spec.ts index adbc83473b..2c63130f67 100644 --- a/packages/app/e2e/app/server-default.spec.ts +++ b/packages/app/e2e/app/server-default.spec.ts @@ -1,6 +1,6 @@ import { test, expect } from "../fixtures" -import { serverName, serverUrl } from "../utils" -import { clickListItem, closeDialog, clickMenuItem } from "../actions" +import { serverNamePattern, serverUrls } from "../utils" +import { closeDialog, clickMenuItem } from "../actions" const DEFAULT_SERVER_URL_KEY = "opencode.settings.dat:defaultServerUrl" @@ -31,10 +31,9 @@ test("can set a default server on web", async ({ page, gotoSession }) => { const dialog = page.getByRole("dialog") await expect(dialog).toBeVisible() - const row = dialog.locator('[data-slot="list-item"]').filter({ hasText: serverName }).first() - await expect(row).toBeVisible() + await expect(dialog.getByText(serverNamePattern).first()).toBeVisible() - const menuTrigger = row.locator('[data-slot="dropdown-menu-trigger"]').first() + const menuTrigger = dialog.locator('[data-slot="dropdown-menu-trigger"]').first() await expect(menuTrigger).toBeVisible() await menuTrigger.click({ force: true }) @@ -42,14 +41,18 @@ test("can set a default server on web", async ({ page, gotoSession }) => { await expect(menu).toBeVisible() await clickMenuItem(menu, /set as default/i) - await expect.poll(() => page.evaluate((key) => localStorage.getItem(key), DEFAULT_SERVER_URL_KEY)).toBe(serverUrl) - await expect(row.getByText("Default", { exact: true })).toBeVisible() + await expect + .poll(async () => + serverUrls.includes((await page.evaluate((key) => localStorage.getItem(key), DEFAULT_SERVER_URL_KEY)) ?? ""), + ) + .toBe(true) + await expect(dialog.getByText("Default", { exact: true })).toBeVisible() await closeDialog(page, dialog) await ensurePopoverOpen() - const serverRow = popover.locator("button").filter({ hasText: serverName }).first() + const serverRow = popover.locator("button").filter({ hasText: serverNamePattern }).first() await expect(serverRow).toBeVisible() await expect(serverRow.getByText("Default", { exact: true })).toBeVisible() }) diff --git a/packages/app/e2e/app/titlebar-history.spec.ts b/packages/app/e2e/app/titlebar-history.spec.ts index 9d6091176e..a4592ff1db 100644 --- a/packages/app/e2e/app/titlebar-history.spec.ts +++ b/packages/app/e2e/app/titlebar-history.spec.ts @@ -16,7 +16,6 @@ test("titlebar back/forward navigates between sessions", async ({ page, slug, sd const link = page.locator(`[data-session-id="${two.id}"] a`).first() await expect(link).toBeVisible() - await link.scrollIntoViewIfNeeded() await link.click() await expect(page).toHaveURL(new RegExp(`/${slug}/session/${two.id}(?:\\?|#|$)`)) @@ -56,7 +55,6 @@ test("titlebar forward is cleared after branching history from sidebar", async ( const second = page.locator(`[data-session-id="${b.id}"] a`).first() await expect(second).toBeVisible() - await second.scrollIntoViewIfNeeded() await second.click() await expect(page).toHaveURL(new RegExp(`/${slug}/session/${b.id}(?:\\?|#|$)`)) @@ -76,7 +74,6 @@ test("titlebar forward is cleared after branching history from sidebar", async ( const third = page.locator(`[data-session-id="${c.id}"] a`).first() await expect(third).toBeVisible() - await third.scrollIntoViewIfNeeded() await third.click() await expect(page).toHaveURL(new RegExp(`/${slug}/session/${c.id}(?:\\?|#|$)`)) @@ -102,7 +99,6 @@ test("keyboard shortcuts navigate titlebar history", async ({ page, slug, sdk, g const link = page.locator(`[data-session-id="${two.id}"] a`).first() await expect(link).toBeVisible() - await link.scrollIntoViewIfNeeded() await link.click() await expect(page).toHaveURL(new RegExp(`/${slug}/session/${two.id}(?:\\?|#|$)`)) diff --git a/packages/app/e2e/commands/panels.spec.ts b/packages/app/e2e/commands/panels.spec.ts index 58c1f0a9af..7e5d7bd6e7 100644 --- a/packages/app/e2e/commands/panels.spec.ts +++ b/packages/app/e2e/commands/panels.spec.ts @@ -10,6 +10,8 @@ const expanded = async (el: { getAttribute: (name: string) => Promise { await gotoSession() + const reviewPanel = page.locator("#review-panel") + const treeToggle = page.getByRole("button", { name: "Toggle file tree" }).first() await expect(treeToggle).toBeVisible() if (await expanded(treeToggle)) await treeToggle.click() @@ -19,13 +21,13 @@ test("review panel can be toggled via keybind", async ({ page, gotoSession }) => await expect(reviewToggle).toBeVisible() if (await expanded(reviewToggle)) await reviewToggle.click() await expect(reviewToggle).toHaveAttribute("aria-expanded", "false") - await expect(page.locator("#review-panel")).toHaveCount(0) + await expect(reviewPanel).toHaveAttribute("aria-hidden", "true") await page.keyboard.press(`${modKey}+Shift+R`) await expect(reviewToggle).toHaveAttribute("aria-expanded", "true") - await expect(page.locator("#review-panel")).toBeVisible() + await expect(reviewPanel).toHaveAttribute("aria-hidden", "false") await page.keyboard.press(`${modKey}+Shift+R`) await expect(reviewToggle).toHaveAttribute("aria-expanded", "false") - await expect(page.locator("#review-panel")).toHaveCount(0) + await expect(reviewPanel).toHaveAttribute("aria-hidden", "true") }) diff --git a/packages/app/e2e/files/file-tree.spec.ts b/packages/app/e2e/files/file-tree.spec.ts index 321d96af57..a5872bdf87 100644 --- a/packages/app/e2e/files/file-tree.spec.ts +++ b/packages/app/e2e/files/file-tree.spec.ts @@ -43,7 +43,14 @@ test("file tree can expand folders and open a file", async ({ page, gotoSession await tab.click() await expect(tab).toHaveAttribute("aria-selected", "true") - const code = page.locator('[data-component="code"]').first() - await expect(code).toBeVisible() - await expect(code).toContainText("export default function FileTree") + await toggle.click() + await expect(toggle).toHaveAttribute("aria-expanded", "false") + + await toggle.click() + await expect(toggle).toHaveAttribute("aria-expanded", "true") + await expect(allTab).toHaveAttribute("aria-selected", "true") + + const viewer = page.locator('[data-component="file"][data-mode="text"]').first() + await expect(viewer).toBeVisible() + await expect(viewer).toContainText("export default function FileTree") }) diff --git a/packages/app/e2e/files/file-viewer.spec.ts b/packages/app/e2e/files/file-viewer.spec.ts index b968acc130..49fe1baa13 100644 --- a/packages/app/e2e/files/file-viewer.spec.ts +++ b/packages/app/e2e/files/file-viewer.spec.ts @@ -1,5 +1,6 @@ import { test, expect } from "../fixtures" import { promptSelector } from "../selectors" +import { modKey } from "../utils" test("smoke file viewer renders real file content", async ({ page, gotoSession }) => { await gotoSession() @@ -43,7 +44,113 @@ test("smoke file viewer renders real file content", async ({ page, gotoSession } await expect(tab).toBeVisible() await tab.click() - const code = page.locator('[data-component="code"]').first() - await expect(code).toBeVisible() - await expect(code.getByText(/"name"\s*:\s*"@opencode-ai\/app"/)).toBeVisible() + const viewer = page.locator('[data-component="file"][data-mode="text"]').first() + await expect(viewer).toBeVisible() + await expect(viewer.getByText(/"name"\s*:\s*"@opencode-ai\/app"/)).toBeVisible() +}) + +test("cmd+f opens text viewer search while prompt is focused", async ({ page, gotoSession }) => { + await gotoSession() + + await page.locator(promptSelector).click() + await page.keyboard.type("/open") + + const command = page.locator('[data-slash-id="file.open"]').first() + await expect(command).toBeVisible() + await page.keyboard.press("Enter") + + const dialog = page + .getByRole("dialog") + .filter({ has: page.getByPlaceholder(/search files/i) }) + .first() + await expect(dialog).toBeVisible() + + const input = dialog.getByRole("textbox").first() + await input.fill("package.json") + + const items = dialog.locator('[data-slot="list-item"][data-key^="file:"]') + let index = -1 + await expect + .poll( + async () => { + const keys = await items.evaluateAll((nodes) => nodes.map((node) => node.getAttribute("data-key") ?? "")) + index = keys.findIndex((key) => /packages[\\/]+app[\\/]+package\.json$/i.test(key.replace(/^file:/, ""))) + return index >= 0 + }, + { timeout: 30_000 }, + ) + .toBe(true) + + const item = items.nth(index) + await expect(item).toBeVisible() + await item.click() + + await expect(dialog).toHaveCount(0) + + const tab = page.getByRole("tab", { name: "package.json" }) + await expect(tab).toBeVisible() + await tab.click() + + const viewer = page.locator('[data-component="file"][data-mode="text"]').first() + await expect(viewer).toBeVisible() + + await page.locator(promptSelector).click() + await page.keyboard.press(`${modKey}+f`) + + const findInput = page.getByPlaceholder("Find") + await expect(findInput).toBeVisible() + await expect(findInput).toBeFocused() +}) + +test("cmd+f opens text viewer search while prompt is not focused", async ({ page, gotoSession }) => { + await gotoSession() + + await page.locator(promptSelector).click() + await page.keyboard.type("/open") + + const command = page.locator('[data-slash-id="file.open"]').first() + await expect(command).toBeVisible() + await page.keyboard.press("Enter") + + const dialog = page + .getByRole("dialog") + .filter({ has: page.getByPlaceholder(/search files/i) }) + .first() + await expect(dialog).toBeVisible() + + const input = dialog.getByRole("textbox").first() + await input.fill("package.json") + + const items = dialog.locator('[data-slot="list-item"][data-key^="file:"]') + let index = -1 + await expect + .poll( + async () => { + const keys = await items.evaluateAll((nodes) => nodes.map((node) => node.getAttribute("data-key") ?? "")) + index = keys.findIndex((key) => /packages[\\/]+app[\\/]+package\.json$/i.test(key.replace(/^file:/, ""))) + return index >= 0 + }, + { timeout: 30_000 }, + ) + .toBe(true) + + const item = items.nth(index) + await expect(item).toBeVisible() + await item.click() + + await expect(dialog).toHaveCount(0) + + const tab = page.getByRole("tab", { name: "package.json" }) + await expect(tab).toBeVisible() + await tab.click() + + const viewer = page.locator('[data-component="file"][data-mode="text"]').first() + await expect(viewer).toBeVisible() + + await viewer.click() + await page.keyboard.press(`${modKey}+f`) + + const findInput = page.getByPlaceholder("Find") + await expect(findInput).toBeVisible() + await expect(findInput).toBeFocused() }) diff --git a/packages/app/e2e/fixtures.ts b/packages/app/e2e/fixtures.ts index ea41ed8516..6a35c6901e 100644 --- a/packages/app/e2e/fixtures.ts +++ b/packages/app/e2e/fixtures.ts @@ -1,5 +1,5 @@ import { test as base, expect, type Page } from "@playwright/test" -import { cleanupTestProject, createTestProject, seedProjects } from "./actions" +import { cleanupSession, cleanupTestProject, createTestProject, seedProjects, sessionIDFromUrl } from "./actions" import { promptSelector } from "./selectors" import { createSdk, dirSlug, getWorktree, sessionPath } from "./utils" @@ -13,6 +13,8 @@ type TestFixtures = { directory: string slug: string gotoSession: (sessionID?: string) => Promise + trackSession: (sessionID: string, directory?: string) => void + trackDirectory: (directory: string) => void }) => Promise, options?: { extra?: string[] }, ) => Promise @@ -51,20 +53,36 @@ export const test = base.extend({ }, withProject: async ({ page }, use) => { await use(async (callback, options) => { - const directory = await createTestProject() - const slug = dirSlug(directory) - await seedStorage(page, { directory, extra: options?.extra }) + const root = await createTestProject() + const slug = dirSlug(root) + const sessions = new Map() + const dirs = new Set() + await seedStorage(page, { directory: root, extra: options?.extra }) const gotoSession = async (sessionID?: string) => { - await page.goto(sessionPath(directory, sessionID)) + await page.goto(sessionPath(root, sessionID)) await expect(page.locator(promptSelector)).toBeVisible() + const current = sessionIDFromUrl(page.url()) + if (current) trackSession(current) + } + + const trackSession = (sessionID: string, directory?: string) => { + sessions.set(sessionID, directory ?? root) + } + + const trackDirectory = (directory: string) => { + if (directory !== root) dirs.add(directory) } try { await gotoSession() - return await callback({ directory, slug, gotoSession }) + return await callback({ directory: root, slug, gotoSession, trackSession, trackDirectory }) } finally { - await cleanupTestProject(directory) + await Promise.allSettled( + Array.from(sessions, ([sessionID, directory]) => cleanupSession({ sessionID, directory })), + ) + await Promise.allSettled(Array.from(dirs, (directory) => cleanupTestProject(directory))) + await cleanupTestProject(root) } }) }, diff --git a/packages/app/e2e/projects/project-edit.spec.ts b/packages/app/e2e/projects/project-edit.spec.ts index 4a286fea75..7c20f29ec1 100644 --- a/packages/app/e2e/projects/project-edit.spec.ts +++ b/packages/app/e2e/projects/project-edit.spec.ts @@ -1,25 +1,15 @@ import { test, expect } from "../fixtures" -import { openSidebar } from "../actions" +import { clickMenuItem, openProjectMenu, openSidebar } from "../actions" test("dialog edit project updates name and startup script", async ({ page, withProject }) => { await page.setViewportSize({ width: 1400, height: 800 }) - await withProject(async () => { + await withProject(async ({ slug }) => { await openSidebar(page) const open = async () => { - const header = page.locator(".group\\/project").first() - await header.hover() - const trigger = header.getByRole("button", { name: "More options" }).first() - await expect(trigger).toBeVisible() - await trigger.click({ force: true }) - - const menu = page.locator('[data-component="dropdown-menu-content"]').first() - await expect(menu).toBeVisible() - - const editItem = menu.getByRole("menuitem", { name: "Edit" }).first() - await expect(editItem).toBeVisible() - await editItem.click({ force: true }) + const menu = await openProjectMenu(page, slug) + await clickMenuItem(menu, /^Edit$/i, { force: true }) const dialog = page.getByRole("dialog") await expect(dialog).toBeVisible() diff --git a/packages/app/e2e/projects/projects-close.spec.ts b/packages/app/e2e/projects/projects-close.spec.ts index 4b39ed82c3..9454d683f0 100644 --- a/packages/app/e2e/projects/projects-close.spec.ts +++ b/packages/app/e2e/projects/projects-close.spec.ts @@ -1,36 +1,8 @@ import { test, expect } from "../fixtures" import { createTestProject, cleanupTestProject, openSidebar, clickMenuItem, openProjectMenu } from "../actions" -import { projectCloseHoverSelector, projectSwitchSelector } from "../selectors" +import { projectSwitchSelector } from "../selectors" import { dirSlug } from "../utils" -test("can close a project via hover card close button", async ({ page, withProject }) => { - await page.setViewportSize({ width: 1400, height: 800 }) - - const other = await createTestProject() - const otherSlug = dirSlug(other) - - try { - await withProject( - async () => { - await openSidebar(page) - - const otherButton = page.locator(projectSwitchSelector(otherSlug)).first() - await expect(otherButton).toBeVisible() - await otherButton.hover() - - const close = page.locator(projectCloseHoverSelector(otherSlug)).first() - await expect(close).toBeVisible() - await close.click() - - await expect(otherButton).toHaveCount(0) - }, - { extra: [other] }, - ) - } finally { - await cleanupTestProject(other) - } -}) - test("closing active project navigates to another open project", async ({ page, withProject }) => { await page.setViewportSize({ width: 1400, height: 800 }) @@ -53,16 +25,26 @@ test("closing active project navigates to another open project", async ({ page, await clickMenuItem(menu, /^Close$/i, { force: true }) await expect - .poll(() => { - const pathname = new URL(page.url()).pathname - if (new RegExp(`^/${slug}/session(?:/[^/]+)?/?$`).test(pathname)) return "project" - if (pathname === "/") return "home" - return "" - }) + .poll( + () => { + const pathname = new URL(page.url()).pathname + if (new RegExp(`^/${slug}/session(?:/[^/]+)?/?$`).test(pathname)) return "project" + if (pathname === "/") return "home" + return "" + }, + { timeout: 15_000 }, + ) .toMatch(/^(project|home)$/) await expect(page).not.toHaveURL(new RegExp(`/${otherSlug}/session(?:[/?#]|$)`)) - await expect(otherButton).toHaveCount(0) + await expect + .poll( + async () => { + return await page.locator(projectSwitchSelector(otherSlug)).count() + }, + { timeout: 15_000 }, + ) + .toBe(0) }, { extra: [other] }, ) diff --git a/packages/app/e2e/projects/projects-switch.spec.ts b/packages/app/e2e/projects/projects-switch.spec.ts index f17557a800..6ad64f5927 100644 --- a/packages/app/e2e/projects/projects-switch.spec.ts +++ b/packages/app/e2e/projects/projects-switch.spec.ts @@ -1,18 +1,39 @@ import { base64Decode } from "@opencode-ai/util/encode" +import type { Page } from "@playwright/test" import { test, expect } from "../fixtures" -import { - defocus, - createTestProject, - cleanupTestProject, - openSidebar, - setWorkspacesEnabled, - sessionIDFromUrl, -} from "../actions" +import { defocus, createTestProject, cleanupTestProject, openSidebar, sessionIDFromUrl, waitSlug } from "../actions" import { projectSwitchSelector, promptSelector, workspaceItemSelector, workspaceNewSessionSelector } from "../selectors" -import { createSdk, dirSlug } from "../utils" +import { dirSlug, resolveDirectory } from "../utils" -function slugFromUrl(url: string) { - return /\/([^/]+)\/session(?:\/|$)/.exec(url)?.[1] ?? "" +async function workspaces(page: Page, directory: string, enabled: boolean) { + await page.evaluate( + ({ directory, enabled }: { directory: string; enabled: boolean }) => { + const key = "opencode.global.dat:layout" + const raw = localStorage.getItem(key) + const data = raw ? JSON.parse(raw) : {} + const sidebar = data.sidebar && typeof data.sidebar === "object" ? data.sidebar : {} + const current = + sidebar.workspaces && typeof sidebar.workspaces === "object" && !Array.isArray(sidebar.workspaces) + ? sidebar.workspaces + : {} + const next = { ...current } + + if (enabled) next[directory] = true + if (!enabled) delete next[directory] + + localStorage.setItem( + key, + JSON.stringify({ + ...data, + sidebar: { + ...sidebar, + workspaces: next, + }, + }), + ) + }, + { directory, enabled }, + ) } test("can switch between projects from sidebar", async ({ page, withProject }) => { @@ -51,57 +72,54 @@ test("switching back to a project opens the latest workspace session", async ({ const other = await createTestProject() const otherSlug = dirSlug(other) - const stamp = Date.now() - let rootDir: string | undefined - let workspaceDir: string | undefined - let sessionID: string | undefined - try { await withProject( - async ({ directory, slug }) => { - rootDir = directory + async ({ directory, slug, trackSession, trackDirectory }) => { await defocus(page) + await workspaces(page, directory, true) + await page.reload() + await expect(page.locator(promptSelector)).toBeVisible() await openSidebar(page) - await setWorkspacesEnabled(page, slug, true) + await expect(page.getByRole("button", { name: "New workspace" }).first()).toBeVisible() await page.getByRole("button", { name: "New workspace" }).first().click() - await expect - .poll( - () => { - const next = slugFromUrl(page.url()) - if (!next) return "" - if (next === slug) return "" - return next - }, - { timeout: 45_000 }, - ) - .not.toBe("") - - const workspaceSlug = slugFromUrl(page.url()) - workspaceDir = base64Decode(workspaceSlug) + const raw = await waitSlug(page, [slug]) + const dir = base64Decode(raw) + if (!dir) throw new Error(`Failed to decode workspace slug: ${raw}`) + const space = await resolveDirectory(dir) + const next = dirSlug(space) + trackDirectory(space) await openSidebar(page) - const workspace = page.locator(workspaceItemSelector(workspaceSlug)).first() - await expect(workspace).toBeVisible() - await workspace.hover() + const item = page.locator(`${workspaceItemSelector(next)}, ${workspaceItemSelector(raw)}`).first() + await expect(item).toBeVisible() + await item.hover() - const newSession = page.locator(workspaceNewSessionSelector(workspaceSlug)).first() - await expect(newSession).toBeVisible() - await newSession.click({ force: true }) + const btn = page.locator(`${workspaceNewSessionSelector(next)}, ${workspaceNewSessionSelector(raw)}`).first() + await expect(btn).toBeVisible() + await btn.click({ force: true }) - await expect(page).toHaveURL(new RegExp(`/${workspaceSlug}/session(?:[/?#]|$)`)) + // A new workspace can be discovered via a transient slug before the route and sidebar + // settle to the canonical workspace path on Windows, so interact with either and assert + // against the resolved workspace slug. + await waitSlug(page) + await expect(page).toHaveURL(new RegExp(`/${next}/session(?:[/?#]|$)`)) + // Create a session by sending a prompt const prompt = page.locator(promptSelector) await expect(prompt).toBeVisible() - await prompt.fill(`project switch remembers workspace ${stamp}`) - await prompt.press("Enter") + await prompt.fill("test") + await page.keyboard.press("Enter") + + // Wait for the URL to update with the new session ID + await expect.poll(() => sessionIDFromUrl(page.url()) ?? "", { timeout: 15_000 }).not.toBe("") - await expect.poll(() => sessionIDFromUrl(page.url()) ?? "", { timeout: 30_000 }).not.toBe("") const created = sessionIDFromUrl(page.url()) - if (!created) throw new Error(`Failed to parse session id from URL: ${page.url()}`) - sessionID = created - await expect(page).toHaveURL(new RegExp(`/${workspaceSlug}/session/${created}(?:[/?#]|$)`)) + if (!created) throw new Error(`Failed to get session ID from url: ${page.url()}`) + trackSession(created, space) + + await expect(page).toHaveURL(new RegExp(`/${next}/session/${created}(?:[/?#]|$)`)) await openSidebar(page) @@ -114,25 +132,12 @@ test("switching back to a project opens the latest workspace session", async ({ await expect(rootButton).toBeVisible() await rootButton.click() - await expect(page).toHaveURL(new RegExp(`/${workspaceSlug}/session/${created}(?:[/?#]|$)`)) + await expect.poll(() => sessionIDFromUrl(page.url()) ?? "").toBe(created) + await expect(page).toHaveURL(new RegExp(`/session/${created}(?:[/?#]|$)`)) }, { extra: [other] }, ) } finally { - if (sessionID) { - const id = sessionID - const dirs = [rootDir, workspaceDir].filter((x): x is string => !!x) - await Promise.all( - dirs.map((directory) => - createSdk(directory) - .session.delete({ sessionID: id }) - .catch(() => undefined), - ), - ) - } - if (workspaceDir) { - await cleanupTestProject(workspaceDir) - } await cleanupTestProject(other) } }) diff --git a/packages/app/e2e/projects/workspace-new-session.spec.ts b/packages/app/e2e/projects/workspace-new-session.spec.ts index f33972cc3a..18fa46d329 100644 --- a/packages/app/e2e/projects/workspace-new-session.spec.ts +++ b/packages/app/e2e/projects/workspace-new-session.spec.ts @@ -1,14 +1,10 @@ import { base64Decode } from "@opencode-ai/util/encode" import type { Page } from "@playwright/test" import { test, expect } from "../fixtures" -import { cleanupTestProject, openSidebar, sessionIDFromUrl, setWorkspacesEnabled } from "../actions" +import { openSidebar, sessionIDFromUrl, setWorkspacesEnabled, slugFromUrl, waitSlug } from "../actions" import { promptSelector, workspaceItemSelector, workspaceNewSessionSelector } from "../selectors" import { createSdk } from "../utils" -function slugFromUrl(url: string) { - return /\/([^/]+)\/session(?:\/|$)/.exec(url)?.[1] ?? "" -} - async function waitWorkspaceReady(page: Page, slug: string) { await openSidebar(page) await expect @@ -31,20 +27,7 @@ async function createWorkspace(page: Page, root: string, seen: string[]) { await openSidebar(page) await page.getByRole("button", { name: "New workspace" }).first().click() - await expect - .poll( - () => { - const slug = slugFromUrl(page.url()) - if (!slug) return "" - if (slug === root) return "" - if (seen.includes(slug)) return "" - return slug - }, - { timeout: 45_000 }, - ) - .not.toBe("") - - const slug = slugFromUrl(page.url()) + const slug = await waitSlug(page, [root, ...seen]) const directory = base64Decode(slug) if (!directory) throw new Error(`Failed to decode workspace slug: ${slug}`) return { slug, directory } @@ -60,12 +43,13 @@ async function openWorkspaceNewSession(page: Page, slug: string) { await expect(button).toBeVisible() await button.click({ force: true }) - await expect.poll(() => slugFromUrl(page.url())).toBe(slug) - await expect(page).toHaveURL(new RegExp(`/${slug}/session(?:[/?#]|$)`)) + const next = await waitSlug(page) + await expect(page).toHaveURL(new RegExp(`/${next}/session(?:[/?#]|$)`)) + return next } async function createSessionFromWorkspace(page: Page, slug: string, text: string) { - await openWorkspaceNewSession(page, slug) + const next = await openWorkspaceNewSession(page, slug) const prompt = page.locator(promptSelector) await expect(prompt).toBeVisible() @@ -76,13 +60,13 @@ async function createSessionFromWorkspace(page: Page, slug: string, text: string await expect.poll(async () => ((await prompt.textContent()) ?? "").trim()).toContain(text) await prompt.press("Enter") - await expect.poll(() => slugFromUrl(page.url())).toBe(slug) + await expect.poll(() => slugFromUrl(page.url())).toBe(next) await expect.poll(() => sessionIDFromUrl(page.url()) ?? "", { timeout: 30_000 }).not.toBe("") const sessionID = sessionIDFromUrl(page.url()) if (!sessionID) throw new Error(`Failed to parse session id from url: ${page.url()}`) - await expect(page).toHaveURL(new RegExp(`/${slug}/session/${sessionID}(?:[/?#]|$)`)) - return sessionID + await expect(page).toHaveURL(new RegExp(`/${next}/session/${sessionID}(?:[/?#]|$)`)) + return { sessionID, slug: next } } async function sessionDirectory(directory: string, sessionID: string) { @@ -97,48 +81,29 @@ async function sessionDirectory(directory: string, sessionID: string) { test("new sessions from sidebar workspace actions stay in selected workspace", async ({ page, withProject }) => { await page.setViewportSize({ width: 1400, height: 800 }) - await withProject(async ({ directory, slug: root }) => { - const workspaces = [] as { slug: string; directory: string }[] - const sessions = [] as string[] + await withProject(async ({ directory, slug: root, trackSession, trackDirectory }) => { + await openSidebar(page) + await setWorkspacesEnabled(page, root, true) - try { - await openSidebar(page) - await setWorkspacesEnabled(page, root, true) + const first = await createWorkspace(page, root, []) + trackDirectory(first.directory) + await waitWorkspaceReady(page, first.slug) - const first = await createWorkspace(page, root, []) - workspaces.push(first) - await waitWorkspaceReady(page, first.slug) + const second = await createWorkspace(page, root, [first.slug]) + trackDirectory(second.directory) + await waitWorkspaceReady(page, second.slug) - const second = await createWorkspace(page, root, [first.slug]) - workspaces.push(second) - await waitWorkspaceReady(page, second.slug) + const firstSession = await createSessionFromWorkspace(page, first.slug, `workspace one ${Date.now()}`) + trackSession(firstSession.sessionID, first.directory) - const firstSession = await createSessionFromWorkspace(page, first.slug, `workspace one ${Date.now()}`) - sessions.push(firstSession) + const secondSession = await createSessionFromWorkspace(page, second.slug, `workspace two ${Date.now()}`) + trackSession(secondSession.sessionID, second.directory) - const secondSession = await createSessionFromWorkspace(page, second.slug, `workspace two ${Date.now()}`) - sessions.push(secondSession) + const thirdSession = await createSessionFromWorkspace(page, first.slug, `workspace one again ${Date.now()}`) + trackSession(thirdSession.sessionID, first.directory) - const thirdSession = await createSessionFromWorkspace(page, first.slug, `workspace one again ${Date.now()}`) - sessions.push(thirdSession) - - await expect.poll(() => sessionDirectory(first.directory, firstSession)).toBe(first.directory) - await expect.poll(() => sessionDirectory(second.directory, secondSession)).toBe(second.directory) - await expect.poll(() => sessionDirectory(first.directory, thirdSession)).toBe(first.directory) - } finally { - const dirs = [directory, ...workspaces.map((workspace) => workspace.directory)] - await Promise.all( - sessions.map((sessionID) => - Promise.all( - dirs.map((dir) => - createSdk(dir) - .session.delete({ sessionID }) - .catch(() => undefined), - ), - ), - ), - ) - await Promise.all(workspaces.map((workspace) => cleanupTestProject(workspace.directory))) - } + await expect.poll(() => sessionDirectory(first.directory, firstSession.sessionID)).toBe(first.directory) + await expect.poll(() => sessionDirectory(second.directory, secondSession.sessionID)).toBe(second.directory) + await expect.poll(() => sessionDirectory(first.directory, thirdSession.sessionID)).toBe(first.directory) }) }) diff --git a/packages/app/e2e/projects/workspaces.spec.ts b/packages/app/e2e/projects/workspaces.spec.ts index 3867395267..aeeccb9bba 100644 --- a/packages/app/e2e/projects/workspaces.spec.ts +++ b/packages/app/e2e/projects/workspaces.spec.ts @@ -14,14 +14,12 @@ import { openSidebar, openWorkspaceMenu, setWorkspacesEnabled, + slugFromUrl, + waitSlug, } from "../actions" import { dropdownMenuContentSelector, inlineInputSelector, workspaceItemSelector } from "../selectors" import { createSdk, dirSlug } from "../utils" -function slugFromUrl(url: string) { - return /\/([^/]+)\/session(?:\/|$)/.exec(url)?.[1] ?? "" -} - async function setupWorkspaceTest(page: Page, project: { slug: string }) { const rootSlug = project.slug await openSidebar(page) @@ -29,17 +27,7 @@ async function setupWorkspaceTest(page: Page, project: { slug: string }) { await setWorkspacesEnabled(page, rootSlug, true) await page.getByRole("button", { name: "New workspace" }).first().click() - await expect - .poll( - () => { - const slug = slugFromUrl(page.url()) - return slug.length > 0 && slug !== rootSlug - }, - { timeout: 45_000 }, - ) - .toBe(true) - - const slug = slugFromUrl(page.url()) + const slug = await waitSlug(page, [rootSlug]) const dir = base64Decode(slug) await openSidebar(page) @@ -91,18 +79,7 @@ test("can create a workspace", async ({ page, withProject }) => { await expect(page.getByRole("button", { name: "New workspace" }).first()).toBeVisible() await page.getByRole("button", { name: "New workspace" }).first().click() - - await expect - .poll( - () => { - const currentSlug = slugFromUrl(page.url()) - return currentSlug.length > 0 && currentSlug !== slug - }, - { timeout: 45_000 }, - ) - .toBe(true) - - const workspaceSlug = slugFromUrl(page.url()) + const workspaceSlug = await waitSlug(page, [slug]) const workspaceDir = base64Decode(workspaceSlug) await openSidebar(page) @@ -279,7 +256,7 @@ test("can delete a workspace", async ({ page, withProject }) => { await clickMenuItem(menu, /^Delete$/i, { force: true }) await confirmDialog(page, /^Delete workspace$/i) - await expect(page).toHaveURL(new RegExp(`/${rootSlug}/session`)) + await expect.poll(() => base64Decode(slugFromUrl(page.url()))).toBe(project.directory) await expect .poll( @@ -336,9 +313,6 @@ test("can reorder workspaces by drag and drop", async ({ page, withProject }) => const src = page.locator(workspaceItemSelector(from)).first() const dst = page.locator(workspaceItemSelector(to)).first() - await src.scrollIntoViewIfNeeded() - await dst.scrollIntoViewIfNeeded() - const a = await src.boundingBox() const b = await dst.boundingBox() if (!a || !b) throw new Error("Failed to resolve workspace drag bounds") @@ -357,17 +331,7 @@ test("can reorder workspaces by drag and drop", async ({ page, withProject }) => for (const _ of [0, 1]) { const prev = slugFromUrl(page.url()) await page.getByRole("button", { name: "New workspace" }).first().click() - await expect - .poll( - () => { - const slug = slugFromUrl(page.url()) - return slug.length > 0 && slug !== rootSlug && slug !== prev - }, - { timeout: 45_000 }, - ) - .toBe(true) - - const slug = slugFromUrl(page.url()) + const slug = await waitSlug(page, [rootSlug, prev]) const dir = base64Decode(slug) workspaces.push({ slug, directory: dir }) diff --git a/packages/app/e2e/prompt/prompt-async.spec.ts b/packages/app/e2e/prompt/prompt-async.spec.ts index ce9b1a7a3b..51fbc3e4ae 100644 --- a/packages/app/e2e/prompt/prompt-async.spec.ts +++ b/packages/app/e2e/prompt/prompt-async.spec.ts @@ -1,6 +1,8 @@ import { test, expect } from "../fixtures" import { promptSelector } from "../selectors" -import { sessionIDFromUrl } from "../actions" +import { cleanupSession, sessionIDFromUrl, withSession } from "../actions" + +const text = (value: string | null) => (value ?? "").replace(/\u200B/g, "").trim() // Regression test for Issue #12453: the synchronous POST /message endpoint holds // the connection open while the agent works, causing "Failed to fetch" over @@ -38,6 +40,37 @@ test("prompt succeeds when sync message endpoint is unreachable", async ({ page, ) .toContain(token) } finally { - await sdk.session.delete({ sessionID }).catch(() => undefined) + await cleanupSession({ sdk, sessionID }) } }) + +test("failed prompt send restores the composer input", async ({ page, sdk, gotoSession }) => { + await withSession(sdk, `e2e prompt failure ${Date.now()}`, async (session) => { + const prompt = page.locator(promptSelector) + const value = `restore ${Date.now()}` + + await page.route(`**/session/${session.id}/prompt_async`, (route) => + route.fulfill({ + status: 500, + contentType: "application/json", + body: JSON.stringify({ message: "e2e prompt failure" }), + }), + ) + + await gotoSession(session.id) + await prompt.click() + await page.keyboard.type(value) + await page.keyboard.press("Enter") + + await expect.poll(async () => text(await prompt.textContent())).toBe(value) + await expect + .poll( + async () => { + const messages = await sdk.session.messages({ sessionID: session.id, limit: 50 }).then((r) => r.data ?? []) + return messages.length + }, + { timeout: 15_000 }, + ) + .toBe(0) + }) +}) diff --git a/packages/app/e2e/prompt/prompt-history.spec.ts b/packages/app/e2e/prompt/prompt-history.spec.ts new file mode 100644 index 0000000000..ec68998144 --- /dev/null +++ b/packages/app/e2e/prompt/prompt-history.spec.ts @@ -0,0 +1,181 @@ +import type { ToolPart } from "@opencode-ai/sdk/v2/client" +import type { Page } from "@playwright/test" +import { test, expect } from "../fixtures" +import { withSession } from "../actions" +import { promptSelector } from "../selectors" + +const text = (value: string | null) => (value ?? "").replace(/\u200B/g, "").trim() + +const isBash = (part: unknown): part is ToolPart => { + if (!part || typeof part !== "object") return false + if (!("type" in part) || part.type !== "tool") return false + if (!("tool" in part) || part.tool !== "bash") return false + return "state" in part +} + +async function edge(page: Page, pos: "start" | "end") { + await page.locator(promptSelector).evaluate((el: HTMLDivElement, pos: "start" | "end") => { + const selection = window.getSelection() + if (!selection) return + + const walk = document.createTreeWalker(el, NodeFilter.SHOW_TEXT) + const nodes: Text[] = [] + for (let node = walk.nextNode(); node; node = walk.nextNode()) { + nodes.push(node as Text) + } + + if (nodes.length === 0) { + const node = document.createTextNode("") + el.appendChild(node) + nodes.push(node) + } + + const node = pos === "start" ? nodes[0]! : nodes[nodes.length - 1]! + const range = document.createRange() + range.setStart(node, pos === "start" ? 0 : (node.textContent ?? "").length) + range.collapse(true) + selection.removeAllRanges() + selection.addRange(range) + }, pos) +} + +async function wait(page: Page, value: string) { + await expect.poll(async () => text(await page.locator(promptSelector).textContent())).toBe(value) +} + +async function reply(sdk: Parameters[0], sessionID: string, token: string) { + await expect + .poll( + async () => { + const messages = await sdk.session.messages({ sessionID, limit: 50 }).then((r) => r.data ?? []) + return messages + .filter((item) => item.info.role === "assistant") + .flatMap((item) => item.parts) + .filter((item) => item.type === "text") + .map((item) => item.text) + .join("\n") + }, + { timeout: 90_000 }, + ) + .toContain(token) +} + +async function shell(sdk: Parameters[0], sessionID: string, cmd: string, token: string) { + await expect + .poll( + async () => { + const messages = await sdk.session.messages({ sessionID, limit: 50 }).then((r) => r.data ?? []) + const part = messages + .filter((item) => item.info.role === "assistant") + .flatMap((item) => item.parts) + .filter(isBash) + .find((item) => item.state.input?.command === cmd && item.state.status === "completed") + + if (!part || part.state.status !== "completed") return + return typeof part.state.metadata?.output === "string" ? part.state.metadata.output : part.state.output + }, + { timeout: 90_000 }, + ) + .toContain(token) +} + +test("prompt history restores unsent draft with arrow navigation", async ({ page, sdk, gotoSession }) => { + test.setTimeout(120_000) + + await withSession(sdk, `e2e prompt history ${Date.now()}`, async (session) => { + await gotoSession(session.id) + + const prompt = page.locator(promptSelector) + const firstToken = `E2E_HISTORY_ONE_${Date.now()}` + const secondToken = `E2E_HISTORY_TWO_${Date.now()}` + const first = `Reply with exactly: ${firstToken}` + const second = `Reply with exactly: ${secondToken}` + const draft = `draft ${Date.now()}` + + await prompt.click() + await page.keyboard.type(first) + await page.keyboard.press("Enter") + await wait(page, "") + await reply(sdk, session.id, firstToken) + + await prompt.click() + await page.keyboard.type(second) + await page.keyboard.press("Enter") + await wait(page, "") + await reply(sdk, session.id, secondToken) + + await prompt.click() + await page.keyboard.type(draft) + await wait(page, draft) + + await edge(page, "start") + await page.keyboard.press("ArrowUp") + await wait(page, second) + + await page.keyboard.press("ArrowUp") + await wait(page, first) + + await page.keyboard.press("ArrowDown") + await wait(page, second) + + await page.keyboard.press("ArrowDown") + await wait(page, draft) + }) +}) + +test("shell history stays separate from normal prompt history", async ({ page, sdk, gotoSession }) => { + test.setTimeout(120_000) + + await withSession(sdk, `e2e shell history ${Date.now()}`, async (session) => { + await gotoSession(session.id) + + const prompt = page.locator(promptSelector) + const firstToken = `E2E_SHELL_ONE_${Date.now()}` + const secondToken = `E2E_SHELL_TWO_${Date.now()}` + const normalToken = `E2E_NORMAL_${Date.now()}` + const first = `echo ${firstToken}` + const second = `echo ${secondToken}` + const normal = `Reply with exactly: ${normalToken}` + + await prompt.click() + await page.keyboard.type("!") + await page.keyboard.type(first) + await page.keyboard.press("Enter") + await wait(page, "") + await shell(sdk, session.id, first, firstToken) + + await prompt.click() + await page.keyboard.type("!") + await page.keyboard.type(second) + await page.keyboard.press("Enter") + await wait(page, "") + await shell(sdk, session.id, second, secondToken) + + await prompt.click() + await page.keyboard.type("!") + await page.keyboard.press("ArrowUp") + await wait(page, second) + + await page.keyboard.press("ArrowUp") + await wait(page, first) + + await page.keyboard.press("ArrowDown") + await wait(page, second) + + await page.keyboard.press("ArrowDown") + await wait(page, "") + + await page.keyboard.press("Escape") + await wait(page, "") + + await prompt.click() + await page.keyboard.type(normal) + await page.keyboard.press("Enter") + await wait(page, "") + await reply(sdk, session.id, normalToken) + + await prompt.click() + await page.keyboard.press("ArrowUp") + await wait(page, normal) + }) +}) diff --git a/packages/app/e2e/prompt/prompt-shell.spec.ts b/packages/app/e2e/prompt/prompt-shell.spec.ts new file mode 100644 index 0000000000..4c92f4a2f2 --- /dev/null +++ b/packages/app/e2e/prompt/prompt-shell.spec.ts @@ -0,0 +1,62 @@ +import type { ToolPart } from "@opencode-ai/sdk/v2/client" +import { test, expect } from "../fixtures" +import { sessionIDFromUrl } from "../actions" +import { promptSelector } from "../selectors" +import { createSdk } from "../utils" + +const isBash = (part: unknown): part is ToolPart => { + if (!part || typeof part !== "object") return false + if (!("type" in part) || part.type !== "tool") return false + if (!("tool" in part) || part.tool !== "bash") return false + return "state" in part +} + +test("shell mode runs a command in the project directory", async ({ page, withProject }) => { + test.setTimeout(120_000) + + await withProject(async ({ directory, gotoSession, trackSession }) => { + const sdk = createSdk(directory) + const prompt = page.locator(promptSelector) + const cmd = process.platform === "win32" ? "dir" : "ls" + + await gotoSession() + await prompt.click() + await page.keyboard.type("!") + await expect(prompt).toHaveAttribute("aria-label", /enter shell command/i) + + await page.keyboard.type(cmd) + await page.keyboard.press("Enter") + + await expect(page).toHaveURL(/\/session\/[^/?#]+/, { timeout: 30_000 }) + + const id = sessionIDFromUrl(page.url()) + if (!id) throw new Error(`Failed to parse session id from url: ${page.url()}`) + trackSession(id, directory) + + await expect + .poll( + async () => { + const list = await sdk.session.messages({ sessionID: id, limit: 50 }).then((x) => x.data ?? []) + const msg = list.findLast( + (item) => item.info.role === "assistant" && "path" in item.info && item.info.path.cwd === directory, + ) + if (!msg) return + + const part = msg.parts + .filter(isBash) + .find((item) => item.state.input?.command === cmd && item.state.status === "completed") + + if (!part || part.state.status !== "completed") return + const output = + typeof part.state.metadata?.output === "string" ? part.state.metadata.output : part.state.output + if (!output.includes("README.md")) return + + return { cwd: directory, output } + }, + { timeout: 90_000 }, + ) + .toEqual(expect.objectContaining({ cwd: directory, output: expect.stringContaining("README.md") })) + + await expect(prompt).toHaveText("") + }) +}) diff --git a/packages/app/e2e/prompt/prompt-slash-share.spec.ts b/packages/app/e2e/prompt/prompt-slash-share.spec.ts new file mode 100644 index 0000000000..817b353a7c --- /dev/null +++ b/packages/app/e2e/prompt/prompt-slash-share.spec.ts @@ -0,0 +1,64 @@ +import { test, expect } from "../fixtures" +import { promptSelector } from "../selectors" +import { withSession } from "../actions" + +const shareDisabled = process.env.OPENCODE_DISABLE_SHARE === "true" || process.env.OPENCODE_DISABLE_SHARE === "1" + +async function seed(sdk: Parameters[0], sessionID: string) { + await sdk.session.promptAsync({ + sessionID, + noReply: true, + parts: [{ type: "text", text: "e2e share seed" }], + }) + + await expect + .poll( + async () => { + const messages = await sdk.session.messages({ sessionID, limit: 1 }).then((r) => r.data ?? []) + return messages.length + }, + { timeout: 30_000 }, + ) + .toBeGreaterThan(0) +} + +test("/share and /unshare update session share state", async ({ page, sdk, gotoSession }) => { + test.skip(shareDisabled, "Share is disabled in this environment (OPENCODE_DISABLE_SHARE).") + + await withSession(sdk, `e2e slash share ${Date.now()}`, async (session) => { + const prompt = page.locator(promptSelector) + + await seed(sdk, session.id) + await gotoSession(session.id) + + await prompt.click() + await page.keyboard.type("/share") + await expect(page.locator('[data-slash-id="session.share"]').first()).toBeVisible() + await page.keyboard.press("Enter") + + await expect + .poll( + async () => { + const data = await sdk.session.get({ sessionID: session.id }).then((r) => r.data) + return data?.share?.url || undefined + }, + { timeout: 30_000 }, + ) + .not.toBeUndefined() + + await prompt.click() + await page.keyboard.type("/unshare") + await expect(page.locator('[data-slash-id="session.unshare"]').first()).toBeVisible() + await page.keyboard.press("Enter") + + await expect + .poll( + async () => { + const data = await sdk.session.get({ sessionID: session.id }).then((r) => r.data) + return data?.share?.url || undefined + }, + { timeout: 30_000 }, + ) + .toBeUndefined() + }) +}) diff --git a/packages/app/e2e/prompt/prompt.spec.ts b/packages/app/e2e/prompt/prompt.spec.ts index ff9f5daf0d..0466d0988c 100644 --- a/packages/app/e2e/prompt/prompt.spec.ts +++ b/packages/app/e2e/prompt/prompt.spec.ts @@ -1,6 +1,6 @@ import { test, expect } from "../fixtures" import { promptSelector } from "../selectors" -import { sessionIDFromUrl, withSession } from "../actions" +import { cleanupSession, sessionIDFromUrl, withSession } from "../actions" test("can send a prompt and receive a reply", async ({ page, sdk, gotoSession }) => { test.setTimeout(120_000) @@ -46,7 +46,7 @@ test("can send a prompt and receive a reply", async ({ page, sdk, gotoSession }) .toContain(token) } finally { page.off("pageerror", onPageError) - await sdk.session.delete({ sessionID }).catch(() => undefined) + await cleanupSession({ sdk, sessionID }) } if (pageErrors.length > 0) { diff --git a/packages/app/e2e/selectors.ts b/packages/app/e2e/selectors.ts index be0bc05717..2061a11284 100644 --- a/packages/app/e2e/selectors.ts +++ b/packages/app/e2e/selectors.ts @@ -20,11 +20,8 @@ export const settingsNotificationsAgentSelector = '[data-action="settings-notifi export const settingsNotificationsPermissionsSelector = '[data-action="settings-notifications-permissions"]' export const settingsNotificationsErrorsSelector = '[data-action="settings-notifications-errors"]' export const settingsSoundsAgentSelector = '[data-action="settings-sounds-agent"]' -export const settingsSoundsAgentEnabledSelector = '[data-action="settings-sounds-agent-enabled"]' export const settingsSoundsPermissionsSelector = '[data-action="settings-sounds-permissions"]' -export const settingsSoundsPermissionsEnabledSelector = '[data-action="settings-sounds-permissions-enabled"]' export const settingsSoundsErrorsSelector = '[data-action="settings-sounds-errors"]' -export const settingsSoundsErrorsEnabledSelector = '[data-action="settings-sounds-errors-enabled"]' export const settingsUpdatesStartupSelector = '[data-action="settings-updates-startup"]' export const settingsReleaseNotesSelector = '[data-action="settings-release-notes"]' @@ -33,8 +30,6 @@ export const sidebarNavSelector = '[data-component="sidebar-nav-desktop"]' export const projectSwitchSelector = (slug: string) => `${sidebarNavSelector} [data-action="project-switch"][data-project="${slug}"]` -export const projectCloseHoverSelector = (slug: string) => `[data-action="project-close-hover"][data-project="${slug}"]` - export const projectMenuTriggerSelector = (slug: string) => `${sidebarNavSelector} [data-action="project-menu"][data-project="${slug}"]` diff --git a/packages/app/e2e/session/session-child-navigation.spec.ts b/packages/app/e2e/session/session-child-navigation.spec.ts new file mode 100644 index 0000000000..ac2dca33c8 --- /dev/null +++ b/packages/app/e2e/session/session-child-navigation.spec.ts @@ -0,0 +1,37 @@ +import { seedSessionTask, withSession } from "../actions" +import { test, expect } from "../fixtures" + +test("task tool child-session link does not trigger stale show errors", async ({ page, sdk, gotoSession }) => { + test.setTimeout(120_000) + + const errs: string[] = [] + const onError = (err: Error) => { + errs.push(err.message) + } + page.on("pageerror", onError) + + await withSession(sdk, `e2e child nav ${Date.now()}`, async (session) => { + const child = await seedSessionTask(sdk, { + sessionID: session.id, + description: "Open child session", + prompt: "Search the repository for AssistantParts and then reply with exactly CHILD_OK.", + }) + + try { + await gotoSession(session.id) + + const link = page + .locator("a.subagent-link") + .filter({ hasText: /open child session/i }) + .first() + await expect(link).toBeVisible({ timeout: 30_000 }) + await link.click() + + await expect(page).toHaveURL(new RegExp(`/session/${child.sessionID}(?:[/?#]|$)`), { timeout: 30_000 }) + await page.waitForTimeout(1000) + expect(errs).toEqual([]) + } finally { + page.off("pageerror", onError) + } + }) +}) diff --git a/packages/app/e2e/session/session-composer-dock.spec.ts b/packages/app/e2e/session/session-composer-dock.spec.ts index 6bf7714a66..055e8eed29 100644 --- a/packages/app/e2e/session/session-composer-dock.spec.ts +++ b/packages/app/e2e/session/session-composer-dock.spec.ts @@ -1,5 +1,5 @@ import { test, expect } from "../fixtures" -import { clearSessionDockSeed, seedSessionPermission, seedSessionQuestion, seedSessionTodos } from "../actions" +import { cleanupSession, clearSessionDockSeed, seedSessionQuestion, seedSessionTodos } from "../actions" import { permissionDockSelector, promptSelector, @@ -11,11 +11,23 @@ import { } from "../selectors" type Sdk = Parameters[0] +type PermissionRule = { permission: string; pattern: string; action: "allow" | "deny" | "ask" } -async function withDockSession(sdk: Sdk, title: string, fn: (session: { id: string; title: string }) => Promise) { - const session = await sdk.session.create({ title }).then((r) => r.data) +async function withDockSession( + sdk: Sdk, + title: string, + fn: (session: { id: string; title: string }) => Promise, + opts?: { permission?: PermissionRule[] }, +) { + const session = await sdk.session + .create(opts?.permission ? { title, permission: opts.permission } : { title }) + .then((r) => r.data) if (!session?.id) throw new Error("Session create did not return an id") - return fn(session) + try { + return await fn(session) + } finally { + await cleanupSession({ sdk, sessionID: session.id }) + } } test.setTimeout(120_000) @@ -28,6 +40,94 @@ async function withDockSeed(sdk: Sdk, sessionID: string, fn: () => Promise } } +async function clearPermissionDock(page: any, label: RegExp) { + const dock = page.locator(permissionDockSelector) + for (let i = 0; i < 3; i++) { + const count = await dock.count() + if (count === 0) return + await dock.getByRole("button", { name: label }).click() + await page.waitForTimeout(150) + } +} + +async function setAutoAccept(page: any, enabled: boolean) { + const button = page.locator('[data-action="prompt-permissions"]').first() + await expect(button).toBeVisible() + const pressed = (await button.getAttribute("aria-pressed")) === "true" + if (pressed === enabled) return + await button.click() + await expect(button).toHaveAttribute("aria-pressed", enabled ? "true" : "false") +} + +async function withMockPermission( + page: any, + request: { + id: string + sessionID: string + permission: string + patterns: string[] + metadata?: Record + always?: string[] + }, + opts: { child?: any } | undefined, + fn: () => Promise, +) { + let pending = [ + { + ...request, + always: request.always ?? ["*"], + metadata: request.metadata ?? {}, + }, + ] + + const list = async (route: any) => { + await route.fulfill({ + status: 200, + contentType: "application/json", + body: JSON.stringify(pending), + }) + } + + const reply = async (route: any) => { + const url = new URL(route.request().url()) + const id = url.pathname.split("/").pop() + pending = pending.filter((item) => item.id !== id) + await route.fulfill({ + status: 200, + contentType: "application/json", + body: JSON.stringify(true), + }) + } + + await page.route("**/permission", list) + await page.route("**/session/*/permissions/*", reply) + + const sessionList = opts?.child + ? async (route: any) => { + const res = await route.fetch() + const json = await res.json() + const list = Array.isArray(json) ? json : Array.isArray(json?.data) ? json.data : undefined + if (Array.isArray(list) && !list.some((item) => item?.id === opts.child?.id)) list.push(opts.child) + await route.fulfill({ + status: res.status(), + headers: res.headers(), + contentType: "application/json", + body: JSON.stringify(json), + }) + } + : undefined + + if (sessionList) await page.route("**/session?*", sessionList) + + try { + return await fn() + } finally { + await page.unroute("**/permission", list) + await page.unroute("**/session/*/permissions/*", reply) + if (sessionList) await page.unroute("**/session?*", sessionList) + } +} + test("default dock shows prompt input", async ({ page, sdk, gotoSession }) => { await withDockSession(sdk, "e2e composer dock default", async (session) => { await gotoSession(session.id) @@ -42,6 +142,17 @@ test("default dock shows prompt input", async ({ page, sdk, gotoSession }) => { }) }) +test("auto-accept toggle works before first submit", async ({ page, gotoSession }) => { + await gotoSession() + + const button = page.locator('[data-action="prompt-permissions"]').first() + await expect(button).toBeVisible() + await expect(button).toHaveAttribute("aria-pressed", "false") + + await setAutoAccept(page, true) + await setAutoAccept(page, false) +}) + test("blocked question flow unblocks after submit", async ({ page, sdk, gotoSession }) => { await withDockSession(sdk, "e2e composer dock question", async (session) => { await withDockSeed(sdk, session.id, async () => { @@ -76,72 +187,179 @@ test("blocked question flow unblocks after submit", async ({ page, sdk, gotoSess test("blocked permission flow supports allow once", async ({ page, sdk, gotoSession }) => { await withDockSession(sdk, "e2e composer dock permission once", async (session) => { - await withDockSeed(sdk, session.id, async () => { - await gotoSession(session.id) - - await seedSessionPermission(sdk, { + await gotoSession(session.id) + await setAutoAccept(page, false) + await withMockPermission( + page, + { + id: "per_e2e_once", sessionID: session.id, permission: "bash", - patterns: ["README.md"], - description: "Need permission for command", - }) + patterns: ["/tmp/opencode-e2e-perm-once"], + metadata: { description: "Need permission for command" }, + }, + undefined, + async () => { + await page.goto(page.url()) + await expect.poll(() => page.locator(permissionDockSelector).count(), { timeout: 10_000 }).toBe(1) + await expect(page.locator(promptSelector)).toHaveCount(0) - await expect.poll(() => page.locator(permissionDockSelector).count(), { timeout: 10_000 }).toBe(1) - await expect(page.locator(promptSelector)).toHaveCount(0) - - await page - .locator(permissionDockSelector) - .getByRole("button", { name: /allow once/i }) - .click() - await expect.poll(() => page.locator(permissionDockSelector).count(), { timeout: 10_000 }).toBe(0) - await expect(page.locator(promptSelector)).toBeVisible() - }) + await clearPermissionDock(page, /allow once/i) + await page.goto(page.url()) + await expect.poll(() => page.locator(permissionDockSelector).count(), { timeout: 10_000 }).toBe(0) + await expect(page.locator(promptSelector)).toBeVisible() + }, + ) }) }) test("blocked permission flow supports reject", async ({ page, sdk, gotoSession }) => { await withDockSession(sdk, "e2e composer dock permission reject", async (session) => { - await withDockSeed(sdk, session.id, async () => { - await gotoSession(session.id) - - await seedSessionPermission(sdk, { + await gotoSession(session.id) + await setAutoAccept(page, false) + await withMockPermission( + page, + { + id: "per_e2e_reject", sessionID: session.id, permission: "bash", - patterns: ["REJECT.md"], - }) + patterns: ["/tmp/opencode-e2e-perm-reject"], + }, + undefined, + async () => { + await page.goto(page.url()) + await expect.poll(() => page.locator(permissionDockSelector).count(), { timeout: 10_000 }).toBe(1) + await expect(page.locator(promptSelector)).toHaveCount(0) - await expect.poll(() => page.locator(permissionDockSelector).count(), { timeout: 10_000 }).toBe(1) - await expect(page.locator(promptSelector)).toHaveCount(0) - - await page.locator(permissionDockSelector).getByRole("button", { name: /deny/i }).click() - await expect.poll(() => page.locator(permissionDockSelector).count(), { timeout: 10_000 }).toBe(0) - await expect(page.locator(promptSelector)).toBeVisible() - }) + await clearPermissionDock(page, /deny/i) + await page.goto(page.url()) + await expect.poll(() => page.locator(permissionDockSelector).count(), { timeout: 10_000 }).toBe(0) + await expect(page.locator(promptSelector)).toBeVisible() + }, + ) }) }) test("blocked permission flow supports allow always", async ({ page, sdk, gotoSession }) => { await withDockSession(sdk, "e2e composer dock permission always", async (session) => { - await withDockSeed(sdk, session.id, async () => { - await gotoSession(session.id) - - await seedSessionPermission(sdk, { + await gotoSession(session.id) + await setAutoAccept(page, false) + await withMockPermission( + page, + { + id: "per_e2e_always", sessionID: session.id, permission: "bash", - patterns: ["README.md"], - description: "Need permission for command", + patterns: ["/tmp/opencode-e2e-perm-always"], + metadata: { description: "Need permission for command" }, + }, + undefined, + async () => { + await page.goto(page.url()) + await expect.poll(() => page.locator(permissionDockSelector).count(), { timeout: 10_000 }).toBe(1) + await expect(page.locator(promptSelector)).toHaveCount(0) + + await clearPermissionDock(page, /allow always/i) + await page.goto(page.url()) + await expect.poll(() => page.locator(permissionDockSelector).count(), { timeout: 10_000 }).toBe(0) + await expect(page.locator(promptSelector)).toBeVisible() + }, + ) + }) +}) + +test("child session question request blocks parent dock and unblocks after submit", async ({ + page, + sdk, + gotoSession, +}) => { + await withDockSession(sdk, "e2e composer dock child question parent", async (session) => { + await gotoSession(session.id) + + const child = await sdk.session + .create({ + title: "e2e composer dock child question", + parentID: session.id, }) + .then((r) => r.data) + if (!child?.id) throw new Error("Child session create did not return an id") - await expect.poll(() => page.locator(permissionDockSelector).count(), { timeout: 10_000 }).toBe(1) - await expect(page.locator(promptSelector)).toHaveCount(0) + try { + await withDockSeed(sdk, child.id, async () => { + await seedSessionQuestion(sdk, { + sessionID: child.id, + questions: [ + { + header: "Child input", + question: "Pick one child option", + options: [ + { label: "Continue", description: "Continue child" }, + { label: "Stop", description: "Stop child" }, + ], + }, + ], + }) - await page - .locator(permissionDockSelector) - .getByRole("button", { name: /allow always/i }) - .click() - await expect.poll(() => page.locator(permissionDockSelector).count(), { timeout: 10_000 }).toBe(0) - await expect(page.locator(promptSelector)).toBeVisible() - }) + const dock = page.locator(questionDockSelector) + await expect.poll(() => dock.count(), { timeout: 10_000 }).toBe(1) + await expect(page.locator(promptSelector)).toHaveCount(0) + + await dock.locator('[data-slot="question-option"]').first().click() + await dock.getByRole("button", { name: /submit/i }).click() + + await expect.poll(() => page.locator(questionDockSelector).count(), { timeout: 10_000 }).toBe(0) + await expect(page.locator(promptSelector)).toBeVisible() + }) + } finally { + await cleanupSession({ sdk, sessionID: child.id }) + } + }) +}) + +test("child session permission request blocks parent dock and supports allow once", async ({ + page, + sdk, + gotoSession, +}) => { + await withDockSession(sdk, "e2e composer dock child permission parent", async (session) => { + await gotoSession(session.id) + await setAutoAccept(page, false) + + const child = await sdk.session + .create({ + title: "e2e composer dock child permission", + parentID: session.id, + }) + .then((r) => r.data) + if (!child?.id) throw new Error("Child session create did not return an id") + + try { + await withMockPermission( + page, + { + id: "per_e2e_child", + sessionID: child.id, + permission: "bash", + patterns: ["/tmp/opencode-e2e-perm-child"], + metadata: { description: "Need child permission" }, + }, + { child }, + async () => { + await page.goto(page.url()) + const dock = page.locator(permissionDockSelector) + await expect.poll(() => dock.count(), { timeout: 10_000 }).toBe(1) + await expect(page.locator(promptSelector)).toHaveCount(0) + + await clearPermissionDock(page, /allow once/i) + await page.goto(page.url()) + + await expect.poll(() => page.locator(permissionDockSelector).count(), { timeout: 10_000 }).toBe(0) + await expect(page.locator(promptSelector)).toBeVisible() + }, + ) + } finally { + await cleanupSession({ sdk, sessionID: child.id }) + } }) }) diff --git a/packages/app/e2e/session/session-undo-redo.spec.ts b/packages/app/e2e/session/session-undo-redo.spec.ts index c6ea2aea0a..eb0840f7cc 100644 --- a/packages/app/e2e/session/session-undo-redo.spec.ts +++ b/packages/app/e2e/session/session-undo-redo.spec.ts @@ -45,7 +45,7 @@ async function seedConversation(input: { .toBe(true) if (!userMessageID) throw new Error("Expected a user message id") - await expect(input.page.locator(`[data-message-id="${userMessageID}"]`).first()).toBeVisible({ timeout: 30_000 }) + await expect(input.page.locator(`[data-message-id="${userMessageID}"]`)).toHaveCount(1, { timeout: 30_000 }) return { prompt, userMessageID } } @@ -123,7 +123,7 @@ test("slash redo clears revert and restores latest state", async ({ page, withPr .toBeUndefined() await expect(seeded.prompt).not.toContainText(token) - await expect(page.locator(`[data-message-id="${seeded.userMessageID}"]`).first()).toBeVisible() + await expect(page.locator(`[data-message-id="${seeded.userMessageID}"]`)).toHaveCount(1) }) }) }) @@ -158,8 +158,8 @@ test("slash undo/redo traverses multi-step revert stack", async ({ page, withPro const firstMessage = page.locator(`[data-message-id="${first.userMessageID}"]`) const secondMessage = page.locator(`[data-message-id="${second.userMessageID}"]`) - await expect(firstMessage.first()).toBeVisible() - await expect(secondMessage.first()).toBeVisible() + await expect(firstMessage).toHaveCount(1) + await expect(secondMessage).toHaveCount(1) await second.prompt.click() await page.keyboard.press(`${modKey}+A`) @@ -176,7 +176,7 @@ test("slash undo/redo traverses multi-step revert stack", async ({ page, withPro }) .toBe(second.userMessageID) - await expect(firstMessage.first()).toBeVisible() + await expect(firstMessage).toHaveCount(1) await expect(secondMessage).toHaveCount(0) await second.prompt.click() @@ -210,7 +210,7 @@ test("slash undo/redo traverses multi-step revert stack", async ({ page, withPro }) .toBe(second.userMessageID) - await expect(firstMessage.first()).toBeVisible() + await expect(firstMessage).toHaveCount(1) await expect(secondMessage).toHaveCount(0) await second.prompt.click() @@ -226,8 +226,8 @@ test("slash undo/redo traverses multi-step revert stack", async ({ page, withPro }) .toBeUndefined() - await expect(firstMessage.first()).toBeVisible() - await expect(secondMessage.first()).toBeVisible() + await expect(firstMessage).toHaveCount(1) + await expect(secondMessage).toHaveCount(1) }) }) }) diff --git a/packages/app/e2e/settings/settings-keybinds.spec.ts b/packages/app/e2e/settings/settings-keybinds.spec.ts index 5e98bd158a..e0d590b31a 100644 --- a/packages/app/e2e/settings/settings-keybinds.spec.ts +++ b/packages/app/e2e/settings/settings-keybinds.spec.ts @@ -32,22 +32,19 @@ test("changing sidebar toggle keybind works", async ({ page, gotoSession }) => { await closeDialog(page, dialog) - const main = page.locator("main") - const initialClasses = (await main.getAttribute("class")) ?? "" - const initiallyClosed = initialClasses.includes("xl:border-l") + const button = page.getByRole("button", { name: /toggle sidebar/i }).first() + const initiallyClosed = (await button.getAttribute("aria-expanded")) !== "true" await page.keyboard.press(`${modKey}+Shift+H`) - await page.waitForTimeout(100) + await expect(button).toHaveAttribute("aria-expanded", initiallyClosed ? "true" : "false") - const afterToggleClasses = (await main.getAttribute("class")) ?? "" - const afterToggleClosed = afterToggleClasses.includes("xl:border-l") + const afterToggleClosed = (await button.getAttribute("aria-expanded")) !== "true" expect(afterToggleClosed).toBe(!initiallyClosed) await page.keyboard.press(`${modKey}+Shift+H`) - await page.waitForTimeout(100) + await expect(button).toHaveAttribute("aria-expanded", initiallyClosed ? "false" : "true") - const finalClasses = (await main.getAttribute("class")) ?? "" - const finalClosed = finalClasses.includes("xl:border-l") + const finalClosed = (await button.getAttribute("aria-expanded")) !== "true" expect(finalClosed).toBe(initiallyClosed) }) diff --git a/packages/app/e2e/settings/settings.spec.ts b/packages/app/e2e/settings/settings.spec.ts index 9fbcf79f5e..f25e91a315 100644 --- a/packages/app/e2e/settings/settings.spec.ts +++ b/packages/app/e2e/settings/settings.spec.ts @@ -9,7 +9,6 @@ import { settingsNotificationsPermissionsSelector, settingsReleaseNotesSelector, settingsSoundsAgentSelector, - settingsSoundsAgentEnabledSelector, settingsSoundsErrorsSelector, settingsSoundsPermissionsSelector, settingsThemeSelector, @@ -84,16 +83,23 @@ test("changing theme persists in localStorage", async ({ page, gotoSession }) => const select = dialog.locator(settingsThemeSelector) await expect(select).toBeVisible() + const currentThemeId = await page.evaluate(() => { + return document.documentElement.getAttribute("data-theme") + }) + const currentTheme = (await select.locator('[data-slot="select-select-trigger-value"]').textContent())?.trim() ?? "" + await select.locator('[data-slot="select-select-trigger"]').click() const items = page.locator('[data-slot="select-select-item"]') const count = await items.count() expect(count).toBeGreaterThan(1) - const firstTheme = await items.nth(1).locator('[data-slot="select-select-item-label"]').textContent() - expect(firstTheme).toBeTruthy() + const nextTheme = (await items.locator('[data-slot="select-select-item-label"]').allTextContents()) + .map((x) => x.trim()) + .find((x) => x && x !== currentTheme) + expect(nextTheme).toBeTruthy() - await items.nth(1).click() + await items.filter({ hasText: nextTheme! }).first().click() await page.keyboard.press("Escape") @@ -102,7 +108,7 @@ test("changing theme persists in localStorage", async ({ page, gotoSession }) => }) expect(storedThemeId).not.toBeNull() - expect(storedThemeId).not.toBe("oc-1") + expect(storedThemeId).not.toBe(currentThemeId) const dataTheme = await page.evaluate(() => { return document.documentElement.getAttribute("data-theme") @@ -110,6 +116,42 @@ test("changing theme persists in localStorage", async ({ page, gotoSession }) => expect(dataTheme).toBe(storedThemeId) }) +test("legacy oc-1 theme migrates to oc-2", async ({ page, gotoSession }) => { + await page.addInitScript(() => { + localStorage.setItem("opencode-theme-id", "oc-1") + localStorage.setItem("opencode-theme-css-light", "--background-base:#fff;") + localStorage.setItem("opencode-theme-css-dark", "--background-base:#000;") + }) + + await gotoSession() + + await expect(page.locator("html")).toHaveAttribute("data-theme", "oc-2") + + await expect + .poll(async () => { + return await page.evaluate(() => { + return localStorage.getItem("opencode-theme-id") + }) + }) + .toBe("oc-2") + + await expect + .poll(async () => { + return await page.evaluate(() => { + return localStorage.getItem("opencode-theme-css-light") + }) + }) + .toBeNull() + + await expect + .poll(async () => { + return await page.evaluate(() => { + return localStorage.getItem("opencode-theme-css-dark") + }) + }) + .toBeNull() +}) + test("changing font persists in localStorage and updates CSS variable", async ({ page, gotoSession }) => { await gotoSession() @@ -336,21 +378,19 @@ test("changing sound agent selection persists in localStorage", async ({ page, g expect(stored?.sounds?.agent).not.toBe("staplebops-01") }) -test("disabling agent sound disables sound selection", async ({ page, gotoSession }) => { +test("selecting none disables agent sound", async ({ page, gotoSession }) => { await gotoSession() const dialog = await openSettings(page) const select = dialog.locator(settingsSoundsAgentSelector) - const switchContainer = dialog.locator(settingsSoundsAgentEnabledSelector) const trigger = select.locator('[data-slot="select-select-trigger"]') await expect(select).toBeVisible() - await expect(switchContainer).toBeVisible() await expect(trigger).toBeEnabled() - await switchContainer.locator('[data-slot="switch-control"]').click() - await page.waitForTimeout(100) - - await expect(trigger).toBeDisabled() + await trigger.click() + const items = page.locator('[data-slot="select-select-item"]') + await expect(items.first()).toBeVisible() + await items.first().click() const stored = await page.evaluate((key) => { const raw = localStorage.getItem(key) diff --git a/packages/app/e2e/sidebar/sidebar-popover-actions.spec.ts b/packages/app/e2e/sidebar/sidebar-popover-actions.spec.ts index e37f94f3a7..d10fca0e49 100644 --- a/packages/app/e2e/sidebar/sidebar-popover-actions.spec.ts +++ b/packages/app/e2e/sidebar/sidebar-popover-actions.spec.ts @@ -1,6 +1,6 @@ import { test, expect } from "../fixtures" -import { closeSidebar, hoverSessionItem } from "../actions" -import { projectSwitchSelector, sessionItemSelector } from "../selectors" +import { cleanupSession, closeSidebar, hoverSessionItem } from "../actions" +import { projectSwitchSelector } from "../selectors" test("collapsed sidebar popover stays open when archiving a session", async ({ page, slug, sdk, gotoSession }) => { const stamp = Date.now() @@ -15,12 +15,15 @@ test("collapsed sidebar popover stays open when archiving a session", async ({ p await gotoSession(one.id) await closeSidebar(page) + const oneItem = page.locator(`[data-session-id="${one.id}"]`).last() + const twoItem = page.locator(`[data-session-id="${two.id}"]`).last() + const project = page.locator(projectSwitchSelector(slug)).first() await expect(project).toBeVisible() await project.hover() - await expect(page.locator(sessionItemSelector(one.id)).first()).toBeVisible() - await expect(page.locator(sessionItemSelector(two.id)).first()).toBeVisible() + await expect(oneItem).toBeVisible() + await expect(twoItem).toBeVisible() const item = await hoverSessionItem(page, one.id) await item @@ -28,9 +31,9 @@ test("collapsed sidebar popover stays open when archiving a session", async ({ p .first() .click() - await expect(page.locator(sessionItemSelector(two.id)).first()).toBeVisible() + await expect(twoItem).toBeVisible() } finally { - await sdk.session.delete({ sessionID: one.id }).catch(() => undefined) - await sdk.session.delete({ sessionID: two.id }).catch(() => undefined) + await cleanupSession({ sdk, sessionID: one.id }) + await cleanupSession({ sdk, sessionID: two.id }) } }) diff --git a/packages/app/e2e/sidebar/sidebar-session-links.spec.ts b/packages/app/e2e/sidebar/sidebar-session-links.spec.ts index cda2278a95..22f98e94ca 100644 --- a/packages/app/e2e/sidebar/sidebar-session-links.spec.ts +++ b/packages/app/e2e/sidebar/sidebar-session-links.spec.ts @@ -1,5 +1,5 @@ import { test, expect } from "../fixtures" -import { openSidebar, withSession } from "../actions" +import { cleanupSession, openSidebar, withSession } from "../actions" import { promptSelector } from "../selectors" test("sidebar session links navigate to the selected session", async ({ page, slug, sdk, gotoSession }) => { @@ -18,14 +18,13 @@ test("sidebar session links navigate to the selected session", async ({ page, sl const target = page.locator(`[data-session-id="${two.id}"] a`).first() await expect(target).toBeVisible() - await target.scrollIntoViewIfNeeded() await target.click() await expect(page).toHaveURL(new RegExp(`/${slug}/session/${two.id}(?:\\?|#|$)`)) await expect(page.locator(promptSelector)).toBeVisible() await expect(page.locator(`[data-session-id="${two.id}"] a`).first()).toHaveClass(/\bactive\b/) } finally { - await sdk.session.delete({ sessionID: one.id }).catch(() => undefined) - await sdk.session.delete({ sessionID: two.id }).catch(() => undefined) + await cleanupSession({ sdk, sessionID: one.id }) + await cleanupSession({ sdk, sessionID: two.id }) } }) diff --git a/packages/app/e2e/sidebar/sidebar.spec.ts b/packages/app/e2e/sidebar/sidebar.spec.ts index 5c78c2220d..c6bf3fa9ab 100644 --- a/packages/app/e2e/sidebar/sidebar.spec.ts +++ b/packages/app/e2e/sidebar/sidebar.spec.ts @@ -5,12 +5,14 @@ test("sidebar can be collapsed and expanded", async ({ page, gotoSession }) => { await gotoSession() await openSidebar(page) + const button = page.getByRole("button", { name: /toggle sidebar/i }).first() + await expect(button).toHaveAttribute("aria-expanded", "true") await toggleSidebar(page) - await expect(page.locator("main")).toHaveClass(/xl:border-l/) + await expect(button).toHaveAttribute("aria-expanded", "false") await toggleSidebar(page) - await expect(page.locator("main")).not.toHaveClass(/xl:border-l/) + await expect(button).toHaveAttribute("aria-expanded", "true") }) test("sidebar collapsed state persists across navigation and reload", async ({ page, sdk, gotoSession }) => { @@ -19,14 +21,15 @@ test("sidebar collapsed state persists across navigation and reload", async ({ p await gotoSession(session1.id) await openSidebar(page) + const button = page.getByRole("button", { name: /toggle sidebar/i }).first() await toggleSidebar(page) - await expect(page.locator("main")).toHaveClass(/xl:border-l/) + await expect(button).toHaveAttribute("aria-expanded", "false") await gotoSession(session2.id) - await expect(page.locator("main")).toHaveClass(/xl:border-l/) + await expect(button).toHaveAttribute("aria-expanded", "false") await page.reload() - await expect(page.locator("main")).toHaveClass(/xl:border-l/) + await expect(button).toHaveAttribute("aria-expanded", "false") const opened = await page.evaluate( () => JSON.parse(localStorage.getItem("opencode.global.dat:layout") ?? "{}").sidebar?.opened, diff --git a/packages/app/e2e/terminal/terminal-tabs.spec.ts b/packages/app/e2e/terminal/terminal-tabs.spec.ts new file mode 100644 index 0000000000..afa6254cd0 --- /dev/null +++ b/packages/app/e2e/terminal/terminal-tabs.spec.ts @@ -0,0 +1,139 @@ +import type { Page } from "@playwright/test" +import { test, expect } from "../fixtures" +import { terminalSelector } from "../selectors" +import { terminalToggleKey, workspacePersistKey } from "../utils" + +type State = { + active?: string + all: Array<{ + id: string + title: string + titleNumber: number + buffer?: string + }> +} + +async function open(page: Page) { + const terminal = page.locator(terminalSelector) + const visible = await terminal.isVisible().catch(() => false) + if (!visible) await page.keyboard.press(terminalToggleKey) + await expect(terminal).toBeVisible() + await expect(terminal.locator("textarea")).toHaveCount(1) +} + +async function run(page: Page, cmd: string) { + const terminal = page.locator(terminalSelector) + await expect(terminal).toBeVisible() + await terminal.click() + await page.keyboard.type(cmd) + await page.keyboard.press("Enter") +} + +async function store(page: Page, key: string) { + return page.evaluate((key) => { + const raw = localStorage.getItem(key) + if (raw) return JSON.parse(raw) as State + + for (let i = 0; i < localStorage.length; i++) { + const next = localStorage.key(i) + if (!next?.endsWith(":workspace:terminal")) continue + const value = localStorage.getItem(next) + if (!value) continue + return JSON.parse(value) as State + } + }, key) +} + +test("inactive terminal tab buffers persist across tab switches", async ({ page, withProject }) => { + await withProject(async ({ directory, gotoSession }) => { + const key = workspacePersistKey(directory, "terminal") + const one = `E2E_TERM_ONE_${Date.now()}` + const two = `E2E_TERM_TWO_${Date.now()}` + const tabs = page.locator('#terminal-panel [data-slot="tabs-trigger"]') + const first = tabs.filter({ hasText: /Terminal 1/ }).first() + const second = tabs.filter({ hasText: /Terminal 2/ }).first() + + await gotoSession() + await open(page) + + await run(page, `echo ${one}`) + + await page.getByRole("button", { name: /new terminal/i }).click() + await expect(tabs).toHaveCount(2) + + await run(page, `echo ${two}`) + + await first.click() + await expect(first).toHaveAttribute("aria-selected", "true") + await expect + .poll( + async () => { + const state = await store(page, key) + const first = state?.all.find((item) => item.titleNumber === 1)?.buffer ?? "" + const second = state?.all.find((item) => item.titleNumber === 2)?.buffer ?? "" + return { + first: first.includes(one), + second: second.includes(two), + } + }, + { timeout: 30_000 }, + ) + .toEqual({ first: false, second: true }) + + await second.click() + await expect(second).toHaveAttribute("aria-selected", "true") + await expect + .poll( + async () => { + const state = await store(page, key) + const first = state?.all.find((item) => item.titleNumber === 1)?.buffer ?? "" + const second = state?.all.find((item) => item.titleNumber === 2)?.buffer ?? "" + return { + first: first.includes(one), + second: second.includes(two), + } + }, + { timeout: 30_000 }, + ) + .toEqual({ first: true, second: false }) + }) +}) + +test("closing the active terminal tab falls back to the previous tab", async ({ page, withProject }) => { + await withProject(async ({ directory, gotoSession }) => { + const key = workspacePersistKey(directory, "terminal") + const tabs = page.locator('#terminal-panel [data-slot="tabs-trigger"]') + + await gotoSession() + await open(page) + + await page.getByRole("button", { name: /new terminal/i }).click() + await expect(tabs).toHaveCount(2) + + const second = tabs.filter({ hasText: /Terminal 2/ }).first() + await second.click() + await expect(second).toHaveAttribute("aria-selected", "true") + + await second.hover() + await page + .getByRole("button", { name: /close terminal/i }) + .nth(1) + .click({ force: true }) + + const first = tabs.filter({ hasText: /Terminal 1/ }).first() + await expect(tabs).toHaveCount(1) + await expect(first).toHaveAttribute("aria-selected", "true") + await expect + .poll( + async () => { + const state = await store(page, key) + return { + count: state?.all.length ?? 0, + first: state?.all.some((item) => item.titleNumber === 1) ?? false, + } + }, + { timeout: 15_000 }, + ) + .toEqual({ count: 1, first: true }) + }) +}) diff --git a/packages/app/e2e/utils.ts b/packages/app/e2e/utils.ts index ec6cdf8302..f07a8d3f11 100644 --- a/packages/app/e2e/utils.ts +++ b/packages/app/e2e/utils.ts @@ -1,12 +1,28 @@ import { createOpencodeClient } from "@opencode-ai/sdk/v2/client" -import { base64Encode } from "@opencode-ai/util/encode" +import { base64Encode, checksum } from "@opencode-ai/util/encode" -export const serverHost = process.env.PLAYWRIGHT_SERVER_HOST ?? "localhost" +export const serverHost = process.env.PLAYWRIGHT_SERVER_HOST ?? "127.0.0.1" export const serverPort = process.env.PLAYWRIGHT_SERVER_PORT ?? "4096" export const serverUrl = `http://${serverHost}:${serverPort}` export const serverName = `${serverHost}:${serverPort}` +const localHosts = ["127.0.0.1", "localhost"] + +const serverLabels = (() => { + const url = new URL(serverUrl) + if (!localHosts.includes(url.hostname)) return [serverName] + return localHosts.map((host) => `${host}:${url.port}`) +})() + +export const serverNames = [...new Set(serverLabels)] + +export const serverUrls = serverNames.map((name) => `http://${name}`) + +const escape = (value: string) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") + +export const serverNamePattern = new RegExp(`(?:${serverNames.map(escape).join("|")})`) + export const modKey = process.platform === "darwin" ? "Meta" : "Control" export const terminalToggleKey = "Control+Backquote" @@ -14,6 +30,12 @@ export function createSdk(directory?: string) { return createOpencodeClient({ baseUrl: serverUrl, directory, throwOnError: true }) } +export async function resolveDirectory(directory: string) { + return createSdk(directory) + .path.get() + .then((x) => x.data?.directory ?? directory) +} + export async function getWorktree() { const sdk = createSdk() const result = await sdk.path.get() @@ -33,3 +55,9 @@ export function dirPath(directory: string) { export function sessionPath(directory: string, sessionID?: string) { return `${dirPath(directory)}/session${sessionID ? `/${sessionID}` : ""}` } + +export function workspacePersistKey(directory: string, key: string) { + const head = (directory.slice(0, 12) || "workspace").replace(/[^a-zA-Z0-9._-]/g, "-") + const sum = checksum(directory) ?? "0" + return `opencode.workspace.${head}.${sum}.dat:workspace:${key}` +} diff --git a/packages/app/package.json b/packages/app/package.json index b9397b0f40..10ef17d1bf 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/app", - "version": "1.2.10", + "version": "1.2.24", "description": "", "type": "module", "exports": { @@ -57,7 +57,7 @@ "@thisbeyond/solid-dnd": "0.7.5", "diff": "catalog:", "fuzzysort": "catalog:", - "ghostty-web": "0.4.0", + "ghostty-web": "github:anomalyco/ghostty-web#main", "luxon": "catalog:", "marked": "catalog:", "marked-shiki": "catalog:", diff --git a/packages/app/playwright.config.ts b/packages/app/playwright.config.ts index ea85829e0b..a97c826514 100644 --- a/packages/app/playwright.config.ts +++ b/packages/app/playwright.config.ts @@ -1,8 +1,8 @@ import { defineConfig, devices } from "@playwright/test" const port = Number(process.env.PLAYWRIGHT_PORT ?? 3000) -const baseURL = process.env.PLAYWRIGHT_BASE_URL ?? `http://localhost:${port}` -const serverHost = process.env.PLAYWRIGHT_SERVER_HOST ?? "localhost" +const baseURL = process.env.PLAYWRIGHT_BASE_URL ?? `http://127.0.0.1:${port}` +const serverHost = process.env.PLAYWRIGHT_SERVER_HOST ?? "127.0.0.1" const serverPort = process.env.PLAYWRIGHT_SERVER_PORT ?? "4096" const command = `bun run dev -- --host 0.0.0.0 --port ${port}` const reuse = !process.env.CI diff --git a/packages/app/public/oc-theme-preload.js b/packages/app/public/oc-theme-preload.js index f8c7104961..36fa5d726a 100644 --- a/packages/app/public/oc-theme-preload.js +++ b/packages/app/public/oc-theme-preload.js @@ -1,6 +1,13 @@ ;(function () { - var themeId = localStorage.getItem("opencode-theme-id") - if (!themeId) return + var key = "opencode-theme-id" + var themeId = localStorage.getItem(key) || "oc-2" + + if (themeId === "oc-1") { + themeId = "oc-2" + localStorage.setItem(key, themeId) + localStorage.removeItem("opencode-theme-css-light") + localStorage.removeItem("opencode-theme-css-dark") + } var scheme = localStorage.getItem("opencode-color-scheme") || "system" var isDark = scheme === "dark" || (scheme === "system" && matchMedia("(prefers-color-scheme: dark)").matches) @@ -9,9 +16,9 @@ document.documentElement.dataset.theme = themeId document.documentElement.dataset.colorScheme = mode - if (themeId === "oc-1") return + if (themeId === "oc-2") return - var css = localStorage.getItem("opencode-theme-css-" + themeId + "-" + mode) + var css = localStorage.getItem("opencode-theme-css-" + mode) if (css) { var style = document.createElement("style") style.id = "oc-theme-preload" diff --git a/packages/app/script/e2e-local.ts b/packages/app/script/e2e-local.ts index 112e2bc60a..9a83411b1d 100644 --- a/packages/app/script/e2e-local.ts +++ b/packages/app/script/e2e-local.ts @@ -145,6 +145,7 @@ try { Object.assign(process.env, serverEnv) process.env.AGENT = "1" process.env.OPENCODE = "1" + process.env.OPENCODE_PID = String(process.pid) const log = await import("../../opencode/src/util/log") const install = await import("../../opencode/src/installation") diff --git a/packages/app/src/app.tsx b/packages/app/src/app.tsx index 1be9f38d74..52a1dac6a2 100644 --- a/packages/app/src/app.tsx +++ b/packages/app/src/app.tsx @@ -1,16 +1,14 @@ import "@/index.css" -import { Code } from "@opencode-ai/ui/code" +import { File } from "@opencode-ai/ui/file" import { I18nProvider } from "@opencode-ai/ui/context" -import { CodeComponentProvider } from "@opencode-ai/ui/context/code" import { DialogProvider } from "@opencode-ai/ui/context/dialog" -import { DiffComponentProvider } from "@opencode-ai/ui/context/diff" +import { FileComponentProvider } from "@opencode-ai/ui/context/file" import { MarkedProvider } from "@opencode-ai/ui/context/marked" -import { Diff } from "@opencode-ai/ui/diff" import { Font } from "@opencode-ai/ui/font" import { ThemeProvider } from "@opencode-ai/ui/theme" import { MetaProvider } from "@solidjs/meta" -import { Navigate, Route, Router } from "@solidjs/router" -import { ErrorBoundary, type JSX, lazy, type ParentProps, Show, Suspense } from "solid-js" +import { BaseRouterProps, Navigate, Route, Router } from "@solidjs/router" +import { Component, ErrorBoundary, type JSX, lazy, type ParentProps, Show, Suspense } from "solid-js" import { CommandProvider } from "@/context/command" import { CommentsProvider } from "@/context/comments" import { FileProvider } from "@/context/file" @@ -30,6 +28,7 @@ import { TerminalProvider } from "@/context/terminal" import DirectoryLayout from "@/pages/directory-layout" import Layout from "@/pages/layout" import { ErrorPage } from "./pages/error" +import { Dynamic } from "solid-js/web" const Home = lazy(() => import("@/pages/home")) const Session = lazy(() => import("@/pages/session")) @@ -122,9 +121,7 @@ export function AppBaseProviders(props: ParentProps) { }> - - {props.children} - + {props.children} @@ -148,13 +145,15 @@ export function AppInterface(props: { children?: JSX.Element defaultServer: ServerConnection.Key servers?: Array + router?: Component }) { return ( - {routerProps.children}} > @@ -162,7 +161,7 @@ export function AppInterface(props: { - + diff --git a/packages/app/src/components/debug-bar.tsx b/packages/app/src/components/debug-bar.tsx new file mode 100644 index 0000000000..93a4654f86 --- /dev/null +++ b/packages/app/src/components/debug-bar.tsx @@ -0,0 +1,432 @@ +import { useIsRouting, useLocation } from "@solidjs/router" +import { batch, createEffect, onCleanup, onMount } from "solid-js" +import { createStore } from "solid-js/store" +import { Tooltip } from "@opencode-ai/ui/tooltip" + +type Mem = Performance & { + memory?: { + usedJSHeapSize: number + jsHeapSizeLimit: number + } +} + +type Evt = PerformanceEntry & { + interactionId?: number + processingStart?: number +} + +type Shift = PerformanceEntry & { + hadRecentInput: boolean + value: number +} + +type Obs = PerformanceObserverInit & { + durationThreshold?: number +} + +const span = 5000 + +const ms = (n?: number, d = 0) => { + if (n === undefined || Number.isNaN(n)) return "n/a" + return `${n.toFixed(d)}ms` +} + +const time = (n?: number) => { + if (n === undefined || Number.isNaN(n)) return "n/a" + return `${Math.round(n)}` +} + +const mb = (n?: number) => { + if (n === undefined || Number.isNaN(n)) return "n/a" + const v = n / 1024 / 1024 + return `${v >= 1024 ? v.toFixed(0) : v.toFixed(1)}MB` +} + +const bad = (n: number | undefined, limit: number, low = false) => { + if (n === undefined || Number.isNaN(n)) return false + return low ? n < limit : n > limit +} + +const session = (path: string) => path.includes("/session") + +function Cell(props: { bad?: boolean; dim?: boolean; label: string; tip: string; value: string }) { + return ( + +
+
{props.label}
+
+ {props.value} +
+
+
+ ) +} + +export function DebugBar() { + const location = useLocation() + const routing = useIsRouting() + const [state, setState] = createStore({ + cls: undefined as number | undefined, + delay: undefined as number | undefined, + fps: undefined as number | undefined, + gap: undefined as number | undefined, + heap: { + limit: undefined as number | undefined, + used: undefined as number | undefined, + }, + inp: undefined as number | undefined, + jank: undefined as number | undefined, + long: { + block: undefined as number | undefined, + count: undefined as number | undefined, + max: undefined as number | undefined, + }, + nav: { + dur: undefined as number | undefined, + pending: false, + }, + }) + + const heap = () => (state.heap.limit ? (state.heap.used ?? 0) / state.heap.limit : undefined) + const heapv = () => { + const value = heap() + if (value === undefined) return "n/a" + return `${Math.round(value * 100)}%` + } + const longv = () => (state.long.count === undefined ? "n/a" : `${time(state.long.block)}/${state.long.count}`) + const navv = () => (state.nav.pending ? "..." : time(state.nav.dur)) + + let prev = "" + let start = 0 + let init = false + let one = 0 + let two = 0 + + createEffect(() => { + const busy = routing() + const next = `${location.pathname}${location.search}` + + if (!init) { + init = true + prev = next + return + } + + if (busy) { + if (one !== 0) cancelAnimationFrame(one) + if (two !== 0) cancelAnimationFrame(two) + one = 0 + two = 0 + if (start !== 0) return + start = performance.now() + if (session(prev)) setState("nav", { dur: undefined, pending: true }) + return + } + + if (start === 0) { + prev = next + return + } + + const at = start + const from = prev + start = 0 + prev = next + + if (!(session(from) || session(next))) return + + if (one !== 0) cancelAnimationFrame(one) + if (two !== 0) cancelAnimationFrame(two) + one = requestAnimationFrame(() => { + one = 0 + two = requestAnimationFrame(() => { + two = 0 + setState("nav", { dur: performance.now() - at, pending: false }) + }) + }) + }) + + onMount(() => { + const obs: PerformanceObserver[] = [] + const fps: Array<{ at: number; dur: number }> = [] + const long: Array<{ at: number; dur: number }> = [] + const seen = new Map() + let hasLong = false + let poll: number | undefined + let raf = 0 + let last = 0 + let snap = 0 + + const trim = (list: Array<{ at: number; dur: number }>, span: number, at: number) => { + while (list[0] && at - list[0].at > span) list.shift() + } + + const syncFrame = (at: number) => { + trim(fps, span, at) + const total = fps.reduce((sum, entry) => sum + entry.dur, 0) + const gap = fps.reduce((max, entry) => Math.max(max, entry.dur), 0) + const jank = fps.filter((entry) => entry.dur > 32).length + batch(() => { + setState("fps", total > 0 ? (fps.length * 1000) / total : undefined) + setState("gap", gap > 0 ? gap : undefined) + setState("jank", jank) + }) + } + + const syncLong = (at = performance.now()) => { + if (!hasLong) return + trim(long, span, at) + const block = long.reduce((sum, entry) => sum + Math.max(0, entry.dur - 50), 0) + const max = long.reduce((hi, entry) => Math.max(hi, entry.dur), 0) + setState("long", { block, count: long.length, max }) + } + + const syncInp = (at = performance.now()) => { + for (const [key, entry] of seen) { + if (at - entry.at > span) seen.delete(key) + } + let delay = 0 + let inp = 0 + for (const entry of seen.values()) { + delay = Math.max(delay, entry.delay) + inp = Math.max(inp, entry.dur) + } + batch(() => { + setState("delay", delay > 0 ? delay : undefined) + setState("inp", inp > 0 ? inp : undefined) + }) + } + + const syncHeap = () => { + const mem = (performance as Mem).memory + if (!mem) return + setState("heap", { limit: mem.jsHeapSizeLimit, used: mem.usedJSHeapSize }) + } + + const reset = () => { + fps.length = 0 + long.length = 0 + seen.clear() + last = 0 + snap = 0 + batch(() => { + setState("fps", undefined) + setState("gap", undefined) + setState("jank", undefined) + setState("delay", undefined) + setState("inp", undefined) + if (hasLong) setState("long", { block: 0, count: 0, max: 0 }) + }) + } + + const watch = (type: string, init: Obs, fn: (entries: PerformanceEntry[]) => void) => { + if (typeof PerformanceObserver === "undefined") return false + if (!(PerformanceObserver.supportedEntryTypes ?? []).includes(type)) return false + const ob = new PerformanceObserver((list) => fn(list.getEntries())) + try { + ob.observe(init) + obs.push(ob) + return true + } catch { + ob.disconnect() + return false + } + } + + if ( + watch("layout-shift", { buffered: true, type: "layout-shift" }, (entries) => { + const add = entries.reduce((sum, entry) => { + const item = entry as Shift + if (item.hadRecentInput) return sum + return sum + item.value + }, 0) + if (add === 0) return + setState("cls", (value) => (value ?? 0) + add) + }) + ) { + setState("cls", 0) + } + + if ( + watch("longtask", { buffered: true, type: "longtask" }, (entries) => { + const at = performance.now() + long.push(...entries.map((entry) => ({ at: entry.startTime, dur: entry.duration }))) + syncLong(at) + }) + ) { + hasLong = true + setState("long", { block: 0, count: 0, max: 0 }) + } + + watch("event", { buffered: true, durationThreshold: 16, type: "event" }, (entries) => { + for (const raw of entries) { + const entry = raw as Evt + if (entry.duration < 16) continue + const key = + entry.interactionId && entry.interactionId > 0 + ? entry.interactionId + : `${entry.name}:${Math.round(entry.startTime)}` + const prev = seen.get(key) + const delay = Math.max(0, (entry.processingStart ?? entry.startTime) - entry.startTime) + seen.set(key, { + at: entry.startTime, + delay: Math.max(prev?.delay ?? 0, delay), + dur: Math.max(prev?.dur ?? 0, entry.duration), + }) + if (seen.size <= 200) continue + const first = seen.keys().next().value + if (first !== undefined) seen.delete(first) + } + syncInp() + }) + + const loop = (at: number) => { + if (document.visibilityState !== "visible") { + raf = 0 + return + } + + if (last === 0) { + last = at + raf = requestAnimationFrame(loop) + return + } + + fps.push({ at, dur: at - last }) + last = at + + if (at - snap >= 250) { + snap = at + syncFrame(at) + } + + raf = requestAnimationFrame(loop) + } + + const stop = () => { + if (raf !== 0) cancelAnimationFrame(raf) + raf = 0 + if (poll === undefined) return + clearInterval(poll) + poll = undefined + } + + const start = () => { + if (document.visibilityState !== "visible") return + if (poll === undefined) { + poll = window.setInterval(() => { + syncLong() + syncInp() + syncHeap() + }, 1000) + } + if (raf !== 0) return + raf = requestAnimationFrame(loop) + } + + const vis = () => { + if (document.visibilityState !== "visible") { + stop() + return + } + reset() + start() + } + + syncHeap() + start() + document.addEventListener("visibilitychange", vis) + + onCleanup(() => { + if (one !== 0) cancelAnimationFrame(one) + if (two !== 0) cancelAnimationFrame(two) + stop() + document.removeEventListener("visibilitychange", vis) + for (const ob of obs) ob.disconnect() + }) + }) + + return ( + + ) +} diff --git a/packages/app/src/components/dialog-connect-provider.tsx b/packages/app/src/components/dialog-connect-provider.tsx index 90f4f41f7c..b042205cf4 100644 --- a/packages/app/src/components/dialog-connect-provider.tsx +++ b/packages/app/src/components/dialog-connect-provider.tsx @@ -4,7 +4,6 @@ import { useDialog } from "@opencode-ai/ui/context/dialog" import { Dialog } from "@opencode-ai/ui/dialog" import { Icon } from "@opencode-ai/ui/icon" import { IconButton } from "@opencode-ai/ui/icon-button" -import type { IconName } from "@opencode-ai/ui/icons/provider" import { List, type ListRef } from "@opencode-ai/ui/list" import { ProviderIcon } from "@opencode-ai/ui/provider-icon" import { Spinner } from "@opencode-ai/ui/spinner" @@ -447,7 +446,7 @@ export function DialogConnectProvider(props: { provider: string }) { >
- +
diff --git a/packages/app/src/components/dialog-release-notes.tsx b/packages/app/src/components/dialog-release-notes.tsx index 2040009a8c..d0a35b71be 100644 --- a/packages/app/src/components/dialog-release-notes.tsx +++ b/packages/app/src/components/dialog-release-notes.tsx @@ -2,6 +2,7 @@ import { createSignal } from "solid-js" import { Dialog } from "@opencode-ai/ui/dialog" import { Button } from "@opencode-ai/ui/button" import { useDialog } from "@opencode-ai/ui/context/dialog" +import { useLanguage } from "@/context/language" import { useSettings } from "@/context/settings" export type Highlight = { @@ -16,6 +17,7 @@ export type Highlight = { export function DialogReleaseNotes(props: { highlights: Highlight[] }) { const dialog = useDialog() + const language = useLanguage() const settings = useSettings() const [index, setIndex] = createSignal(0) @@ -83,16 +85,16 @@ export function DialogReleaseNotes(props: { highlights: Highlight[] }) {
{isLast() ? ( ) : ( )}
@@ -128,7 +130,7 @@ export function DialogReleaseNotes(props: { highlights: Highlight[] }) { {feature()!.media!.type === "image" ? ( {feature()!.media!.alt ) : ( diff --git a/packages/app/src/components/dialog-select-directory.tsx b/packages/app/src/components/dialog-select-directory.tsx index 515e640c9f..91e23f8ffa 100644 --- a/packages/app/src/components/dialog-select-directory.tsx +++ b/packages/app/src/components/dialog-select-directory.tsx @@ -8,6 +8,7 @@ import fuzzysort from "fuzzysort" import { createMemo, createResource, createSignal } from "solid-js" import { useGlobalSDK } from "@/context/global-sdk" import { useGlobalSync } from "@/context/global-sync" +import { useLayout } from "@/context/layout" import { useLanguage } from "@/context/language" interface DialogSelectDirectoryProps { @@ -19,6 +20,7 @@ interface DialogSelectDirectoryProps { type Row = { absolute: string search: string + group: "recent" | "folders" } function cleanInput(value: string) { @@ -101,7 +103,7 @@ function displayPath(path: string, input: string, home: string) { return tildeOf(full, home) || full } -function toRow(absolute: string, home: string): Row { +function toRow(absolute: string, home: string, group: Row["group"]): Row { const full = trimTrailing(absolute) const tilde = tildeOf(full, home) const withSlash = (value: string) => { @@ -113,7 +115,16 @@ function toRow(absolute: string, home: string): Row { const search = Array.from( new Set([full, withSlash(full), tilde, withSlash(tilde), getFilename(full)].filter(Boolean)), ).join("\n") - return { absolute: full, search } + return { absolute: full, search, group } +} + +function uniqueRows(rows: Row[]) { + const seen = new Set() + return rows.filter((row) => { + if (seen.has(row.absolute)) return false + seen.add(row.absolute) + return true + }) } function useDirectorySearch(args: { @@ -237,6 +248,7 @@ function useDirectorySearch(args: { export function DialogSelectDirectory(props: DialogSelectDirectoryProps) { const sync = useGlobalSync() const sdk = useGlobalSDK() + const layout = useLayout() const dialog = useDialog() const language = useLanguage() @@ -266,9 +278,42 @@ export function DialogSelectDirectory(props: DialogSelectDirectoryProps) { start, }) + const recentProjects = createMemo(() => { + const projects = layout.projects.list() + const byProject = new Map() + + for (const project of projects) { + let at = 0 + const dirs = [project.worktree, ...(project.sandboxes ?? [])] + for (const directory of dirs) { + const sessions = sync.child(directory, { bootstrap: false })[0].session + for (const session of sessions) { + if (session.time.archived) continue + const updated = session.time.updated ?? session.time.created + if (updated > at) at = updated + } + } + byProject.set(project.worktree, at) + } + + return projects + .map((project, index) => ({ project, at: byProject.get(project.worktree) ?? 0, index })) + .sort((a, b) => b.at - a.at || a.index - b.index) + .slice(0, 5) + .map(({ project }) => { + const row = toRow(project.worktree, home(), "recent") + const name = project.name || getFilename(project.worktree) + return { + ...row, + search: `${row.search}\n${name}`, + } + }) + }) + const items = async (value: string) => { const results = await directories(value) - return results.map((absolute) => toRow(absolute, home())) + const directoryRows = results.map((absolute) => toRow(absolute, home(), "folders")) + return uniqueRows([...recentProjects(), ...directoryRows]) } function resolve(absolute: string) { @@ -285,6 +330,14 @@ export function DialogSelectDirectory(props: DialogSelectDirectoryProps) { items={items} key={(x) => x.absolute} filterKeys={["search"]} + groupBy={(item) => item.group} + sortGroupsBy={(a, b) => { + if (a.category === b.category) return 0 + return a.category === "recent" ? -1 : 1 + }} + groupHeader={(group) => + group.category === "recent" ? language.t("home.recentProjects") : language.t("command.project.open") + } ref={(r) => (list = r)} onFilter={(value) => setFilter(cleanInput(value))} onKeyEvent={(e, item) => { diff --git a/packages/app/src/components/dialog-select-file.tsx b/packages/app/src/components/dialog-select-file.tsx index 29a3666c03..b530aff532 100644 --- a/packages/app/src/components/dialog-select-file.tsx +++ b/packages/app/src/components/dialog-select-file.tsx @@ -449,7 +449,7 @@ export function DialogSelectFile(props: { mode?: DialogSelectFileMode; onOpenFil
- {getRelativeTime(new Date(item.updated!).toISOString())} + {getRelativeTime(new Date(item.updated!).toISOString(), language.t)}
diff --git a/packages/app/src/components/dialog-select-model-unpaid.tsx b/packages/app/src/components/dialog-select-model-unpaid.tsx index af788d05b0..bcee3f501f 100644 --- a/packages/app/src/components/dialog-select-model-unpaid.tsx +++ b/packages/app/src/components/dialog-select-model-unpaid.tsx @@ -1,7 +1,6 @@ import { Button } from "@opencode-ai/ui/button" import { useDialog } from "@opencode-ai/ui/context/dialog" import { Dialog } from "@opencode-ai/ui/dialog" -import type { IconName } from "@opencode-ai/ui/icons/provider" import { List, type ListRef } from "@opencode-ai/ui/list" import { ProviderIcon } from "@opencode-ai/ui/provider-icon" import { Tag } from "@opencode-ai/ui/tag" @@ -95,11 +94,22 @@ export const DialogSelectModelUnpaid: Component = () => { > {(i) => (
- + {i.name} + +
{language.t("dialog.provider.opencode.tagline")}
+
{language.t("dialog.provider.tag.recommended")} + + <> +
+ {language.t("dialog.provider.opencodeGo.tagline")} +
+ {language.t("dialog.provider.tag.recommended")} + +
{language.t("dialog.provider.anthropic.note")}
diff --git a/packages/app/src/components/dialog-select-provider.tsx b/packages/app/src/components/dialog-select-provider.tsx index 8bbd3054b9..e53738399a 100644 --- a/packages/app/src/components/dialog-select-provider.tsx +++ b/packages/app/src/components/dialog-select-provider.tsx @@ -5,18 +5,12 @@ import { Dialog } from "@opencode-ai/ui/dialog" import { List } from "@opencode-ai/ui/list" import { Tag } from "@opencode-ai/ui/tag" import { ProviderIcon } from "@opencode-ai/ui/provider-icon" -import { iconNames, type IconName } from "@opencode-ai/ui/icons/provider" import { DialogConnectProvider } from "./dialog-connect-provider" import { useLanguage } from "@/context/language" import { DialogCustomProvider } from "./dialog-custom-provider" const CUSTOM_ID = "_custom" -function icon(id: string): IconName { - if (iconNames.includes(id as IconName)) return id as IconName - return "synthetic" -} - export const DialogSelectProvider: Component = () => { const dialog = useDialog() const providers = useProviders() @@ -29,6 +23,7 @@ export const DialogSelectProvider: Component = () => { if (id === "anthropic") return language.t("dialog.provider.anthropic.note") if (id === "openai") return language.t("dialog.provider.openai.note") if (id.startsWith("github-copilot")) return language.t("dialog.provider.copilot.note") + if (id === "opencode-go") return language.t("dialog.provider.opencodeGo.tagline") } return ( @@ -68,8 +63,11 @@ export const DialogSelectProvider: Component = () => { > {(i) => (
- + {i.name} + +
{language.t("dialog.provider.opencode.tagline")}
+
{language.t("settings.providers.tag.custom")} @@ -77,6 +75,9 @@ export const DialogSelectProvider: Component = () => { {language.t("dialog.provider.tag.recommended")} {(value) =>
{value()}
}
+ + {language.t("dialog.provider.tag.recommended")} +
)} diff --git a/packages/app/src/components/dialog-select-server.tsx b/packages/app/src/components/dialog-select-server.tsx index 76c8ff60ef..4813ecc45d 100644 --- a/packages/app/src/components/dialog-select-server.tsx +++ b/packages/app/src/components/dialog-select-server.tsx @@ -2,6 +2,7 @@ import { Button } from "@opencode-ai/ui/button" import { useDialog } from "@opencode-ai/ui/context/dialog" import { Dialog } from "@opencode-ai/ui/dialog" import { DropdownMenu } from "@opencode-ai/ui/dropdown-menu" +import { Icon } from "@opencode-ai/ui/icon" import { IconButton } from "@opencode-ai/ui/icon-button" import { List } from "@opencode-ai/ui/list" import { TextField } from "@opencode-ai/ui/text-field" @@ -9,32 +10,27 @@ import { showToast } from "@opencode-ai/ui/toast" import { useNavigate } from "@solidjs/router" import { createEffect, createMemo, createResource, onCleanup, Show } from "solid-js" import { createStore, reconcile } from "solid-js/store" -import { ServerRow } from "@/components/server/server-row" +import { ServerHealthIndicator, ServerRow } from "@/components/server/server-row" import { useLanguage } from "@/context/language" import { usePlatform } from "@/context/platform" import { normalizeServerUrl, ServerConnection, useServer } from "@/context/server" import { checkServerHealth, type ServerHealth } from "@/utils/server-health" -interface AddRowProps { - value: string - placeholder: string - adding: boolean - error: string - status: boolean | undefined - onChange: (value: string) => void - onKeyDown: (event: KeyboardEvent) => void - onBlur: () => void -} - -interface EditRowProps { +interface ServerFormProps { value: string + name: string + username: string + password: string placeholder: string busy: boolean error: string status: boolean | undefined onChange: (value: string) => void - onKeyDown: (event: KeyboardEvent) => void - onBlur: () => void + onNameChange: (value: string) => void + onUsernameChange: (value: string) => void + onPasswordChange: (value: string) => void + onSubmit: () => void + onBack: () => void } function showRequestError(language: ReturnType, err: unknown) { @@ -83,83 +79,86 @@ function useServerPreview(fetcher: typeof fetch) { return host.includes(".") || host.includes(":") } - const previewStatus = async (value: string, setStatus: (value: boolean | undefined) => void) => { + const previewStatus = async ( + value: string, + username: string, + password: string, + setStatus: (value: boolean | undefined) => void, + ) => { setStatus(undefined) if (!looksComplete(value)) return const normalized = normalizeServerUrl(value) if (!normalized) return - const result = await checkServerHealth({ url: normalized }, fetcher) + const http: ServerConnection.HttpBase = { url: normalized } + if (username) http.username = username + if (password) http.password = password + const result = await checkServerHealth(http, fetcher) setStatus(result.healthy) } return { previewStatus } } -function AddRow(props: AddRowProps) { - return ( -
-
-
{ - // Position relative to input-wrapper - requestAnimationFrame(() => { - const wrapper = el.parentElement?.querySelector('[data-slot="input-wrapper"]') - if (wrapper instanceof HTMLElement) { - wrapper.appendChild(el) - } - }) - }} - /> - -
-
- ) -} +function ServerForm(props: ServerFormProps) { + const language = useLanguage() + const keyDown = (event: KeyboardEvent) => { + event.stopPropagation() + if (event.key === "Escape") { + event.preventDefault() + props.onBack() + return + } + if (event.key !== "Enter" || event.isComposing) return + event.preventDefault() + props.onSubmit() + } -function EditRow(props: EditRowProps) { return ( -
event.stopPropagation()}> -
-
+
+
+
+ +
+
+ + +
) @@ -174,11 +173,13 @@ export function DialogSelectServer() { const fetcher = platform.fetch ?? globalThis.fetch const { defaultUrl, canDefault, setDefault } = useDefaultServer(platform, language) const { previewStatus } = useServerPreview(fetcher) - let listRoot: HTMLDivElement | undefined const [store, setStore] = createStore({ status: {} as Record, addServer: { url: "", + name: "", + username: "", + password: "", adding: false, error: "", showForm: false, @@ -187,6 +188,9 @@ export function DialogSelectServer() { editServer: { id: undefined as string | undefined, value: "", + name: "", + username: "", + password: "", error: "", busy: false, status: undefined as boolean | undefined, @@ -196,27 +200,32 @@ export function DialogSelectServer() { const resetAdd = () => { setStore("addServer", { url: "", + name: "", + username: "", + password: "", + adding: false, error: "", showForm: false, status: undefined, }) } - const resetEdit = () => { setStore("editServer", { id: undefined, value: "", + name: "", + username: "", + password: "", error: "", status: undefined, busy: false, }) } - const replaceServer = (original: ServerConnection.Http, next: string) => { + const replaceServer = (original: ServerConnection.Http, next: ServerConnection.Http) => { const active = server.key const newConn = server.add(next) if (!newConn) return - const nextActive = active === ServerConnection.key(original) ? ServerConnection.key(newConn) : active if (nextActive) server.setActive(nextActive) server.remove(ServerConnection.key(original)) @@ -271,8 +280,8 @@ export function DialogSelectServer() { async function select(conn: ServerConnection.Any, persist?: boolean) { if (!persist && store.status[ServerConnection.key(conn)]?.healthy === false) return dialog.close() - if (persist) { - server.add(conn.http.url) + if (persist && conn.type === "http") { + server.add(conn) navigate("/") return } @@ -283,21 +292,59 @@ export function DialogSelectServer() { const handleAddChange = (value: string) => { if (store.addServer.adding) return setStore("addServer", { url: value, error: "" }) - void previewStatus(value, (next) => setStore("addServer", { status: next })) + void previewStatus(value, store.addServer.username, store.addServer.password, (next) => + setStore("addServer", { status: next }), + ) } - const scrollListToBottom = () => { - const scroll = listRoot?.querySelector('[data-slot="list-scroll"]') - if (!scroll) return - requestAnimationFrame(() => { - scroll.scrollTop = scroll.scrollHeight - }) + const handleAddNameChange = (value: string) => { + if (store.addServer.adding) return + setStore("addServer", { name: value, error: "" }) + } + + const handleAddUsernameChange = (value: string) => { + if (store.addServer.adding) return + setStore("addServer", { username: value, error: "" }) + void previewStatus(store.addServer.url, value, store.addServer.password, (next) => + setStore("addServer", { status: next }), + ) + } + + const handleAddPasswordChange = (value: string) => { + if (store.addServer.adding) return + setStore("addServer", { password: value, error: "" }) + void previewStatus(store.addServer.url, store.addServer.username, value, (next) => + setStore("addServer", { status: next }), + ) } const handleEditChange = (value: string) => { if (store.editServer.busy) return setStore("editServer", { value, error: "" }) - void previewStatus(value, (next) => setStore("editServer", { status: next })) + void previewStatus(value, store.editServer.username, store.editServer.password, (next) => + setStore("editServer", { status: next }), + ) + } + + const handleEditNameChange = (value: string) => { + if (store.editServer.busy) return + setStore("editServer", { name: value, error: "" }) + } + + const handleEditUsernameChange = (value: string) => { + if (store.editServer.busy) return + setStore("editServer", { username: value, error: "" }) + void previewStatus(store.editServer.value, value, store.editServer.password, (next) => + setStore("editServer", { status: next }), + ) + } + + const handleEditPasswordChange = (value: string) => { + if (store.editServer.busy) return + setStore("editServer", { password: value, error: "" }) + void previewStatus(store.editServer.value, store.editServer.username, value, (next) => + setStore("editServer", { status: next }), + ) } async function handleAdd(value: string) { @@ -310,16 +357,22 @@ export function DialogSelectServer() { setStore("addServer", { adding: true, error: "" }) - const result = await checkServerHealth({ url: normalized }, fetcher) + const conn: ServerConnection.Http = { + type: "http", + http: { url: normalized }, + } + if (store.addServer.name.trim()) conn.displayName = store.addServer.name.trim() + if (store.addServer.username) conn.http.username = store.addServer.username + if (store.addServer.password) conn.http.password = store.addServer.password + const result = await checkServerHealth(conn.http, fetcher) setStore("addServer", { adding: false }) - if (!result.healthy) { setStore("addServer", { error: language.t("dialog.server.add.error") }) return } resetAdd() - await select({ type: "http", http: { url: normalized } }, true) + await select(conn, true) } async function handleEdit(original: ServerConnection.Any, value: string) { @@ -330,53 +383,115 @@ export function DialogSelectServer() { return } - if (normalized === original.http.url) { + const name = store.editServer.name.trim() || undefined + const username = store.editServer.username || undefined + const password = store.editServer.password || undefined + const existingName = original.displayName + if ( + normalized === original.http.url && + name === existingName && + username === original.http.username && + password === original.http.password + ) { resetEdit() return } setStore("editServer", { busy: true, error: "" }) - const result = await checkServerHealth({ url: normalized }, fetcher) + const conn: ServerConnection.Http = { + type: "http", + displayName: name, + http: { url: normalized, username, password }, + } + const result = await checkServerHealth(conn.http, fetcher) setStore("editServer", { busy: false }) - if (!result.healthy) { setStore("editServer", { error: language.t("dialog.server.add.error") }) return } - - replaceServer(original, normalized) + if (normalized === original.http.url) { + server.add(conn) + } else { + replaceServer(original, conn) + } resetEdit() } - const handleAddKey = (event: KeyboardEvent) => { - event.stopPropagation() - if (event.key !== "Enter" || event.isComposing) return - event.preventDefault() - handleAdd(store.addServer.url) + const mode = createMemo<"list" | "add" | "edit">(() => { + if (store.editServer.id) return "edit" + if (store.addServer.showForm) return "add" + return "list" + }) + + const editing = createMemo(() => { + if (!store.editServer.id) return + return items().find((x) => x.type === "http" && x.http.url === store.editServer.id) + }) + + const resetForm = () => { + resetAdd() + resetEdit() } - const blurAdd = () => { - if (!store.addServer.url.trim()) { - resetAdd() - return - } - handleAdd(store.addServer.url) + const startAdd = () => { + resetEdit() + setStore("addServer", { + showForm: true, + url: "", + name: "", + username: "", + password: "", + error: "", + status: undefined, + }) } - const handleEditKey = (event: KeyboardEvent, original: ServerConnection.Any) => { - event.stopPropagation() - if (event.key === "Escape") { - event.preventDefault() - resetEdit() + const startEdit = (conn: ServerConnection.Http) => { + resetAdd() + setStore("editServer", { + id: conn.http.url, + value: conn.http.url, + name: conn.displayName ?? "", + username: conn.http.username ?? "", + password: conn.http.password ?? "", + error: "", + status: store.status[ServerConnection.key(conn)]?.healthy, + busy: false, + }) + } + + const submitForm = () => { + if (mode() === "add") { + void handleAdd(store.addServer.url) return } - if (event.key !== "Enter" || event.isComposing) return - event.preventDefault() - handleEdit(original, store.editServer.value) + const original = editing() + if (!original) return + void handleEdit(original, store.editServer.value) } + const isFormMode = createMemo(() => mode() !== "list") + const isAddMode = createMemo(() => mode() === "add") + const formBusy = createMemo(() => (isAddMode() ? store.addServer.adding : store.editServer.busy)) + + const formTitle = createMemo(() => { + if (!isFormMode()) return language.t("dialog.server.title") + return ( +
+ + {isAddMode() ? language.t("dialog.server.add.title") : language.t("dialog.server.edit.title")} +
+ ) + }) + + createEffect(() => { + if (!store.editServer.id) return + if (editing()) return + resetEdit() + }) + async function handleRemove(url: ServerConnection.Key) { server.remove(url) if ((await platform.getDefaultServerUrl?.()) === url) { @@ -385,9 +500,29 @@ export function DialogSelectServer() { } return ( - +
-
(listRoot = el)}> + + } + > { if (x) select(x) }} - onFilter={(value) => { - if (value && store.addServer.showForm && !store.addServer.adding) { - resetAdd() - } - }} divider={true} - class="px-5 [&_[data-slot=list-search-wrapper]]:w-full [&_[data-slot=list-scroll]]:max-h-[300px] [&_[data-slot=list-scroll]]:overflow-y-auto [&_[data-slot=list-items]]:bg-surface-raised-base [&_[data-slot=list-items]]:rounded-md [&_[data-slot=list-item]]:h-14 [&_[data-slot=list-item]]:p-3 [&_[data-slot=list-item]]:!bg-transparent [&_[data-slot=list-item-add]]:px-0" - add={ - store.addServer.showForm - ? { - render: () => ( - - ), - } - : undefined - } + class="px-5 [&_[data-slot=list-search-wrapper]]:w-full [&_[data-slot=list-scroll]]h-[300px] [&_[data-slot=list-scroll]]:overflow-y-auto [&_[data-slot=list-items]]:bg-surface-raised-base [&_[data-slot=list-items]]:rounded-md [&_[data-slot=list-item]]:min-h-14 [&_[data-slot=list-item]]:p-3 [&_[data-slot=list-item]]:!bg-transparent" > {(i) => { const key = ServerConnection.key(i) return ( -
- handleEditKey(event, i)} - onBlur={() => handleEdit(i, store.editServer.value)} - /> - } - > - - - {language.t("dialog.server.status.default")} - - - } - /> - - -
- -

{language.t("dialog.server.current")}

+
+
+ +
+ + + {language.t("dialog.server.status.default")} + + } + showCredentials + /> +
+ + + - - - e.stopPropagation()} - onPointerDown={(e: PointerEvent) => e.stopPropagation()} - /> - - - { - setStore("editServer", { - id: i.http.url, - value: i.http.url, - error: "", - status: store.status[ServerConnection.key(i)]?.healthy, - }) - }} - > - {language.t("dialog.server.menu.edit")} - - - setDefault(i.http.url)}> - - {language.t("dialog.server.menu.default")} - - - - - setDefault(null)}> - - {language.t("dialog.server.menu.defaultRemove")} - - - - - handleRemove(ServerConnection.key(i))} - class="text-text-on-critical-base hover:bg-surface-critical-weak" - > + + + e.stopPropagation()} + onPointerDown={(e: PointerEvent) => e.stopPropagation()} + /> + + + { + if (i.type !== "http") return + startEdit(i) + }} + > + {language.t("dialog.server.menu.edit")} + + + setDefault(i.http.url)}> - {language.t("dialog.server.menu.delete")} + {language.t("dialog.server.menu.default")} - - - - -
- + + + setDefault(null)}> + + {language.t("dialog.server.menu.defaultRemove")} + + + + + handleRemove(ServerConnection.key(i))} + class="text-text-on-critical-base hover:bg-surface-critical-weak" + > + {language.t("dialog.server.menu.delete")} + + + + + +
) }} -
+
- + } > - {store.addServer.adding ? language.t("dialog.server.add.checking") : language.t("dialog.server.add.button")} - + +
diff --git a/packages/app/src/components/file-tree.tsx b/packages/app/src/components/file-tree.tsx index cec0943542..930832fb65 100644 --- a/packages/app/src/components/file-tree.tsx +++ b/packages/app/src/components/file-tree.tsx @@ -3,7 +3,6 @@ import { encodeFilePath } from "@/context/file/path" import { Collapsible } from "@opencode-ai/ui/collapsible" import { FileIcon } from "@opencode-ai/ui/file-icon" import { Icon } from "@opencode-ai/ui/icon" -import { Tooltip } from "@opencode-ai/ui/tooltip" import { createEffect, createMemo, @@ -192,59 +191,6 @@ const FileTreeNode = ( ) } -const FileTreeNodeTooltip = (props: { enabled: boolean; node: FileNode; kind?: Kind; children: JSXElement }) => { - if (!props.enabled) return props.children - - const parts = props.node.path.split("/") - const leaf = parts[parts.length - 1] ?? props.node.path - const head = parts.slice(0, -1).join("/") - const prefix = head ? `${head}/` : "" - const label = - props.kind === "add" - ? "Additions" - : props.kind === "del" - ? "Deletions" - : props.kind === "mix" - ? "Modifications" - : undefined - - return ( - - - {prefix} - - {leaf} - - {(text) => ( - <> - - {text()} - - )} - - - <> - - Ignored - - -
- } - > - {props.children} - - ) -} - export default function FileTree(props: { path: string class?: string @@ -255,7 +201,6 @@ export default function FileTree(props: { modified?: readonly string[] kinds?: ReadonlyMap draggable?: boolean - tooltip?: boolean onFileClick?: (file: FileNode) => void _filter?: Filter @@ -267,7 +212,6 @@ export default function FileTree(props: { const file = useFile() const level = props.level ?? 0 const draggable = () => props.draggable ?? true - const tooltip = () => props.tooltip ?? true const key = (p: string) => file @@ -381,12 +325,6 @@ export default function FileTree(props: { ), ) - createEffect(() => { - const dir = file.tree.state(props.path) - if (!shouldListExpanded({ level, dir })) return - void file.tree.list(props.path) - }) - const nodes = createMemo(() => { const nodes = file.tree.children(props.path) const current = filter() @@ -467,21 +405,19 @@ export default function FileTree(props: { onOpenChange={(open) => (open ? file.tree.expand(node.path) : file.tree.collapse(node.path))} > - - -
- -
-
-
+ +
+ +
+
- - props.onFileClick?.(node)} - > -
- - + props.onFileClick?.(node)} + > +
+ + + + + + + + + - - - - - - - - - - - - + + + + ) diff --git a/packages/app/src/components/prompt-input.tsx b/packages/app/src/components/prompt-input.tsx index adfd592f8d..532edd3bcd 100644 --- a/packages/app/src/components/prompt-input.tsx +++ b/packages/app/src/components/prompt-input.tsx @@ -1,9 +1,10 @@ import { useFilteredList } from "@opencode-ai/ui/hooks" +import { useSpring } from "@opencode-ai/ui/motion-spring" import { createEffect, on, Component, Show, onCleanup, Switch, Match, createMemo, createSignal } from "solid-js" import { createStore } from "solid-js/store" import { createFocusSignal } from "@solid-primitives/active-element" import { useLocal } from "@/context/local" -import { useFile } from "@/context/file" +import { selectionFromLines, type SelectedLineRange, useFile } from "@/context/file" import { ContentPart, DEFAULT_PROMPT, @@ -23,7 +24,6 @@ import { Button } from "@opencode-ai/ui/button" import { DockShellForm, DockTray } from "@opencode-ai/ui/dock-surface" import { Icon } from "@opencode-ai/ui/icon" import { ProviderIcon } from "@opencode-ai/ui/provider-icon" -import type { IconName } from "@opencode-ai/ui/icons/provider" import { Tooltip, TooltipKeybind } from "@opencode-ai/ui/tooltip" import { IconButton } from "@opencode-ai/ui/icon-button" import { Select } from "@opencode-ai/ui/select" @@ -43,6 +43,9 @@ import { canNavigateHistoryAtCursor, navigatePromptHistory, prependHistoryEntry, + type PromptHistoryComment, + type PromptHistoryEntry, + type PromptHistoryStoredEntry, promptLength, } from "./prompt-input/history" import { createPromptSubmit } from "./prompt-input/submit" @@ -170,12 +173,29 @@ export const PromptInput: Component = (props) => { const focus = { file: item.path, id: item.commentID } comments.setActive(focus) + const queueCommentFocus = (attempts = 6) => { + const schedule = (left: number) => { + requestAnimationFrame(() => { + comments.setFocus({ ...focus }) + if (left <= 0) return + requestAnimationFrame(() => { + const current = comments.focus() + if (!current) return + if (current.file !== focus.file || current.id !== focus.id) return + schedule(left - 1) + }) + }) + } + + schedule(attempts) + } + const wantsReview = item.commentOrigin === "review" || (item.commentOrigin !== "file" && commentInReview(item.path)) if (wantsReview) { if (!view().reviewPanel.opened()) view().reviewPanel.open() layout.fileTree.setTab("changes") tabs().setActive("review") - requestAnimationFrame(() => comments.setFocus(focus)) + queueCommentFocus() return } @@ -183,8 +203,8 @@ export const PromptInput: Component = (props) => { layout.fileTree.setTab("all") const tab = files.tab(item.path) tabs().open(tab) - files.load(item.path) - requestAnimationFrame(() => comments.setFocus(focus)) + tabs().setActive(tab) + Promise.resolve(files.load(item.path)).finally(() => queueCommentFocus()) } const recent = createMemo(() => { @@ -219,7 +239,7 @@ export const PromptInput: Component = (props) => { const [store, setStore] = createStore<{ popover: "at" | "slash" | null historyIndex: number - savedPrompt: Prompt | null + savedPrompt: PromptHistoryEntry | null placeholder: number draggingType: "image" | "@mention" | null mode: "normal" | "shell" @@ -227,13 +247,15 @@ export const PromptInput: Component = (props) => { }>({ popover: null, historyIndex: -1, - savedPrompt: null, + savedPrompt: null as PromptHistoryEntry | null, placeholder: Math.floor(Math.random() * EXAMPLES.length), draggingType: null, mode: "normal", applyingHistory: false, }) + const buttonsSpring = useSpring(() => (store.mode === "normal" ? 1 : 0), { visualDuration: 0.2, bounce: 0 }) + const commentCount = createMemo(() => { if (store.mode === "shell") return 0 return prompt.context.items().filter((item) => !!item.comment?.trim()).length @@ -256,7 +278,7 @@ export const PromptInput: Component = (props) => { const [history, setHistory] = persisted( Persist.global("prompt-history", ["prompt-history.v1"]), createStore<{ - entries: Prompt[] + entries: PromptHistoryStoredEntry[] }>({ entries: [], }), @@ -264,7 +286,7 @@ export const PromptInput: Component = (props) => { const [shellHistory, setShellHistory] = persisted( Persist.global("prompt-history-shell", ["prompt-history-shell.v1"]), createStore<{ - entries: Prompt[] + entries: PromptHistoryStoredEntry[] }>({ entries: [], }), @@ -282,9 +304,66 @@ export const PromptInput: Component = (props) => { }), ) - const applyHistoryPrompt = (p: Prompt, position: "start" | "end") => { + const historyComments = () => { + const byID = new Map(comments.all().map((item) => [`${item.file}\n${item.id}`, item] as const)) + return prompt.context.items().flatMap((item) => { + if (item.type !== "file") return [] + const comment = item.comment?.trim() + if (!comment) return [] + + const selection = item.commentID ? byID.get(`${item.path}\n${item.commentID}`)?.selection : undefined + const nextSelection = + selection ?? + (item.selection + ? ({ + start: item.selection.startLine, + end: item.selection.endLine, + } satisfies SelectedLineRange) + : undefined) + if (!nextSelection) return [] + + return [ + { + id: item.commentID ?? item.key, + path: item.path, + selection: { ...nextSelection }, + comment, + time: item.commentID ? (byID.get(`${item.path}\n${item.commentID}`)?.time ?? Date.now()) : Date.now(), + origin: item.commentOrigin, + preview: item.preview, + } satisfies PromptHistoryComment, + ] + }) + } + + const applyHistoryComments = (items: PromptHistoryComment[]) => { + comments.replace( + items.map((item) => ({ + id: item.id, + file: item.path, + selection: { ...item.selection }, + comment: item.comment, + time: item.time, + })), + ) + prompt.context.replaceComments( + items.map((item) => ({ + type: "file" as const, + path: item.path, + selection: selectionFromLines(item.selection), + comment: item.comment, + commentID: item.id, + commentOrigin: item.origin, + preview: item.preview, + })), + ) + } + + const applyHistoryPrompt = (entry: PromptHistoryEntry, position: "start" | "end") => { + const p = entry.prompt const length = position === "start" ? 0 : promptLength(p) setStore("applyingHistory", true) + applyHistoryComments(entry.comments) prompt.set(p, length) requestAnimationFrame(() => { editorRef.focus() @@ -515,7 +594,6 @@ export const PromptInput: Component = (props) => { setActive: setSlashActive, onInput: slashOnInput, onKeyDown: slashOnKeyDown, - refetch: slashRefetch, } = useFilteredList({ items: slashCommands, key: (x) => x?.id, @@ -572,14 +650,6 @@ export const PromptInput: Component = (props) => { } } - createEffect( - on( - () => sync.data.command, - () => slashRefetch(), - { defer: true }, - ), - ) - // Auto-scroll active command into view when navigating with keyboard createEffect(() => { const activeId = slashActive() @@ -846,7 +916,7 @@ export const PromptInput: Component = (props) => { const addToHistory = (prompt: Prompt, mode: "normal" | "shell") => { const currentHistory = mode === "shell" ? shellHistory : history const setCurrentHistory = mode === "shell" ? setShellHistory : setHistory - const next = prependHistoryEntry(currentHistory.entries, prompt) + const next = prependHistoryEntry(currentHistory.entries, prompt, mode === "shell" ? [] : historyComments()) if (next === currentHistory.entries) return setCurrentHistory("entries", next) } @@ -857,12 +927,13 @@ export const PromptInput: Component = (props) => { entries: store.mode === "shell" ? shellHistory.entries : history.entries, historyIndex: store.historyIndex, currentPrompt: prompt.current(), + currentComments: historyComments(), savedPrompt: store.savedPrompt, }) if (!result.handled) return false setStore("historyIndex", result.historyIndex) setStore("savedPrompt", result.savedPrompt) - applyHistoryPrompt(result.prompt, result.cursor) + applyHistoryPrompt(result.entry, result.cursor) return true } @@ -879,10 +950,18 @@ export const PromptInput: Component = (props) => { readClipboardImage: platform.readClipboardImage, }) + const variants = createMemo(() => ["default", ...local.model.variant.list()]) + const accepting = createMemo(() => { + const id = params.id + if (!id) return permission.isAutoAcceptingDirectory(sdk.directory) + return permission.isAutoAccepting(id, sdk.directory) + }) + const { abort, handleSubmit } = createPromptSubmit({ info, imageAttachments, commentCount, + autoAccept: () => accepting(), mode: () => store.mode, working, editor: () => editorRef, @@ -1047,8 +1126,6 @@ export const PromptInput: Component = (props) => { } } - const variants = createMemo(() => ["default", ...local.model.variant.list()]) - return (
= (props) => { aria-multiline="true" aria-label={placeholder()} contenteditable="true" - autocapitalize="off" - autocorrect="off" - spellcheck={false} + autocapitalize={store.mode === "normal" ? "sentences" : "off"} + autocorrect={store.mode === "normal" ? "on" : "off"} + spellcheck={store.mode === "normal"} onInput={handleInput} onPaste={handlePaste} onCompositionStart={() => setComposing(true)} @@ -1168,10 +1245,9 @@ export const PromptInput: Component = (props) => {
0.5 ? "auto" : "none", }} > = (props) => { type="button" variant="ghost" class="size-8 p-0" + style={{ + opacity: buttonsSpring(), + transform: `scale(${0.95 + buttonsSpring() * 0.05})`, + filter: `blur(${(1 - buttonsSpring()) * 2}px)`, + }} onClick={pick} disabled={store.mode !== "normal"} tabIndex={store.mode === "normal" ? undefined : -1} @@ -1221,60 +1302,78 @@ export const PromptInput: Component = (props) => { icon={working() ? "stop" : "arrow-up"} variant="primary" class="size-8" + style={{ + opacity: buttonsSpring(), + transform: `scale(${0.95 + buttonsSpring() * 0.05})`, + filter: `blur(${(1 - buttonsSpring()) * 2}px)`, + }} aria-label={working() ? language.t("prompt.action.stop") : language.t("prompt.action.send")} />
- -
-
- - - -
+ permission.toggleAutoAccept(params.id, sdk.directory) + }} + classList={{ + "size-6 flex items-center justify-center": true, + "text-text-base": !accepting(), + "hover:bg-surface-success-base": accepting(), + }} + aria-label={ + accepting() + ? language.t("command.permissions.autoaccept.disable") + : language.t("command.permissions.autoaccept.enable") + } + aria-pressed={accepting()} + > + + +
-
+
-
- -
- {language.t("prompt.mode.shell")} -
-
- - +
+
+ {language.t("prompt.mode.shell")} +
+
+
= (props) => { onSelect={local.agent.set} class="capitalize max-w-[160px]" valueClass="truncate text-13-regular" - triggerStyle={{ height: "28px" }} + triggerStyle={{ + height: "28px", + opacity: buttonsSpring(), + transform: `scale(${0.95 + buttonsSpring() * 0.05})`, + filter: `blur(${(1 - buttonsSpring()) * 2}px)`, + "pointer-events": buttonsSpring() > 0.5 ? "auto" : "none", + }} variant="ghost" /> @@ -1306,12 +1411,18 @@ export const PromptInput: Component = (props) => { variant="ghost" size="normal" class="min-w-0 max-w-[320px] text-13-regular group" - style={{ height: "28px" }} + style={{ + height: "28px", + opacity: buttonsSpring(), + transform: `scale(${0.95 + buttonsSpring() * 0.05})`, + filter: `blur(${(1 - buttonsSpring()) * 2}px)`, + "pointer-events": buttonsSpring() > 0.5 ? "auto" : "none", + }} onClick={() => dialog.show(() => )} > @@ -1335,13 +1446,19 @@ export const PromptInput: Component = (props) => { triggerProps={{ variant: "ghost", size: "normal", - style: { height: "28px" }, + style: { + height: "28px", + opacity: buttonsSpring(), + transform: `scale(${0.95 + buttonsSpring() * 0.05})`, + filter: `blur(${(1 - buttonsSpring()) * 2}px)`, + "pointer-events": buttonsSpring() > 0.5 ? "auto" : "none", + }, class: "min-w-0 max-w-[320px] text-13-regular group", }} > @@ -1367,11 +1484,17 @@ export const PromptInput: Component = (props) => { onSelect={(x) => local.model.variant.set(x === "default" ? undefined : x)} class="capitalize max-w-[160px]" valueClass="truncate text-13-regular" - triggerStyle={{ height: "28px" }} + triggerStyle={{ + height: "28px", + opacity: buttonsSpring(), + transform: `scale(${0.95 + buttonsSpring() * 0.05})`, + filter: `blur(${(1 - buttonsSpring()) * 2}px)`, + "pointer-events": buttonsSpring() > 0.5 ? "auto" : "none", + }} variant="ghost" /> - +
{ result.requestParts.some((part) => part.type === "file" && part.url.startsWith("file:///repo/src/foo.ts")), ).toBe(true) expect(result.requestParts.some((part) => part.type === "text" && part.synthetic)).toBe(true) + expect( + result.requestParts.some( + (part) => + part.type === "text" && + part.synthetic && + part.metadata?.opencodeComment && + (part.metadata.opencodeComment as { comment?: string }).comment === "check this", + ), + ).toBe(true) expect(result.optimisticParts).toHaveLength(result.requestParts.length) expect(result.optimisticParts.every((part) => part.sessionID === "ses_1" && part.messageID === "msg_1")).toBe(true) diff --git a/packages/app/src/components/prompt-input/build-request-parts.ts b/packages/app/src/components/prompt-input/build-request-parts.ts index 0cc54dc2b7..4146fb4847 100644 --- a/packages/app/src/components/prompt-input/build-request-parts.ts +++ b/packages/app/src/components/prompt-input/build-request-parts.ts @@ -4,6 +4,7 @@ import type { FileSelection } from "@/context/file" import { encodeFilePath } from "@/context/file/path" import type { AgentPart, FileAttachmentPart, ImageAttachmentPart, Prompt } from "@/context/prompt" import { Identifier } from "@/utils/id" +import { createCommentMetadata, formatCommentNote } from "@/utils/comment-note" type PromptRequestPart = (TextPartInput | FilePartInput | AgentPartInput) & { id: string } @@ -41,18 +42,6 @@ const fileQuery = (selection: FileSelection | undefined) => const isFileAttachment = (part: Prompt[number]): part is FileAttachmentPart => part.type === "file" const isAgentAttachment = (part: Prompt[number]): part is AgentPart => part.type === "agent" -const commentNote = (path: string, selection: FileSelection | undefined, comment: string) => { - const start = selection ? Math.min(selection.startLine, selection.endLine) : undefined - const end = selection ? Math.max(selection.startLine, selection.endLine) : undefined - const range = - start === undefined || end === undefined - ? "this file" - : start === end - ? `line ${start}` - : `lines ${start} through ${end}` - return `The user made the following comment regarding ${range} of ${path}: ${comment}` -} - const toOptimisticPart = (part: PromptRequestPart, sessionID: string, messageID: string): Part => { if (part.type === "text") { return { @@ -153,8 +142,15 @@ export function buildRequestParts(input: BuildRequestPartsInput) { { id: Identifier.ascending("part"), type: "text", - text: commentNote(item.path, item.selection, comment), + text: formatCommentNote({ path: item.path, selection: item.selection, comment }), synthetic: true, + metadata: createCommentMetadata({ + path: item.path, + selection: item.selection, + comment, + preview: item.preview, + origin: item.commentOrigin, + }), } satisfies PromptRequestPart, filePart, ] diff --git a/packages/app/src/components/prompt-input/history.test.ts b/packages/app/src/components/prompt-input/history.test.ts index b7a4f896b8..37b5ce1962 100644 --- a/packages/app/src/components/prompt-input/history.test.ts +++ b/packages/app/src/components/prompt-input/history.test.ts @@ -3,25 +3,42 @@ import type { Prompt } from "@/context/prompt" import { canNavigateHistoryAtCursor, clonePromptParts, + normalizePromptHistoryEntry, navigatePromptHistory, prependHistoryEntry, promptLength, + type PromptHistoryComment, } from "./history" const DEFAULT_PROMPT: Prompt = [{ type: "text", content: "", start: 0, end: 0 }] const text = (value: string): Prompt => [{ type: "text", content: value, start: 0, end: value.length }] +const comment = (id: string, value = "note"): PromptHistoryComment => ({ + id, + path: "src/a.ts", + selection: { start: 2, end: 4 }, + comment: value, + time: 1, + origin: "review", + preview: "const a = 1", +}) describe("prompt-input history", () => { test("prependHistoryEntry skips empty prompt and deduplicates consecutive entries", () => { const first = prependHistoryEntry([], DEFAULT_PROMPT) expect(first).toEqual([]) + const commentsOnly = prependHistoryEntry([], DEFAULT_PROMPT, [comment("c1")]) + expect(commentsOnly).toHaveLength(1) + const withOne = prependHistoryEntry([], text("hello")) expect(withOne).toHaveLength(1) const deduped = prependHistoryEntry(withOne, text("hello")) expect(deduped).toBe(withOne) + + const dedupedComments = prependHistoryEntry(commentsOnly, DEFAULT_PROMPT, [comment("c1")]) + expect(dedupedComments).toBe(commentsOnly) }) test("navigatePromptHistory restores saved prompt when moving down from newest", () => { @@ -31,24 +48,57 @@ describe("prompt-input history", () => { entries, historyIndex: -1, currentPrompt: text("draft"), + currentComments: [comment("draft")], savedPrompt: null, }) expect(up.handled).toBe(true) if (!up.handled) throw new Error("expected handled") expect(up.historyIndex).toBe(0) expect(up.cursor).toBe("start") + expect(up.entry.comments).toEqual([]) const down = navigatePromptHistory({ direction: "down", entries, historyIndex: up.historyIndex, currentPrompt: text("ignored"), + currentComments: [], savedPrompt: up.savedPrompt, }) expect(down.handled).toBe(true) if (!down.handled) throw new Error("expected handled") expect(down.historyIndex).toBe(-1) - expect(down.prompt[0]?.type === "text" ? down.prompt[0].content : "").toBe("draft") + expect(down.entry.prompt[0]?.type === "text" ? down.entry.prompt[0].content : "").toBe("draft") + expect(down.entry.comments).toEqual([comment("draft")]) + }) + + test("navigatePromptHistory keeps entry comments when moving through history", () => { + const entries = [ + { + prompt: text("with comment"), + comments: [comment("c1")], + }, + ] + + const up = navigatePromptHistory({ + direction: "up", + entries, + historyIndex: -1, + currentPrompt: text("draft"), + currentComments: [], + savedPrompt: null, + }) + + expect(up.handled).toBe(true) + if (!up.handled) throw new Error("expected handled") + expect(up.entry.prompt[0]?.type === "text" ? up.entry.prompt[0].content : "").toBe("with comment") + expect(up.entry.comments).toEqual([comment("c1")]) + }) + + test("normalizePromptHistoryEntry supports legacy prompt arrays", () => { + const entry = normalizePromptHistoryEntry(text("legacy")) + expect(entry.prompt[0]?.type === "text" ? entry.prompt[0].content : "").toBe("legacy") + expect(entry.comments).toEqual([]) }) test("helpers clone prompt and count text content length", () => { diff --git a/packages/app/src/components/prompt-input/history.ts b/packages/app/src/components/prompt-input/history.ts index c279a3ed56..de62653211 100644 --- a/packages/app/src/components/prompt-input/history.ts +++ b/packages/app/src/components/prompt-input/history.ts @@ -1,9 +1,27 @@ import type { Prompt } from "@/context/prompt" +import type { SelectedLineRange } from "@/context/file" const DEFAULT_PROMPT: Prompt = [{ type: "text", content: "", start: 0, end: 0 }] export const MAX_HISTORY = 100 +export type PromptHistoryComment = { + id: string + path: string + selection: SelectedLineRange + comment: string + time: number + origin?: "review" | "file" + preview?: string +} + +export type PromptHistoryEntry = { + prompt: Prompt + comments: PromptHistoryComment[] +} + +export type PromptHistoryStoredEntry = Prompt | PromptHistoryEntry + export function canNavigateHistoryAtCursor(direction: "up" | "down", text: string, cursor: number, inHistory = false) { const position = Math.max(0, Math.min(cursor, text.length)) const atStart = position === 0 @@ -25,29 +43,82 @@ export function clonePromptParts(prompt: Prompt): Prompt { }) } +function cloneSelection(selection: SelectedLineRange): SelectedLineRange { + return { + start: selection.start, + end: selection.end, + ...(selection.side ? { side: selection.side } : {}), + ...(selection.endSide ? { endSide: selection.endSide } : {}), + } +} + +export function clonePromptHistoryComments(comments: PromptHistoryComment[]) { + return comments.map((comment) => ({ + ...comment, + selection: cloneSelection(comment.selection), + })) +} + +export function normalizePromptHistoryEntry(entry: PromptHistoryStoredEntry): PromptHistoryEntry { + if (Array.isArray(entry)) { + return { + prompt: clonePromptParts(entry), + comments: [], + } + } + return { + prompt: clonePromptParts(entry.prompt), + comments: clonePromptHistoryComments(entry.comments), + } +} + export function promptLength(prompt: Prompt) { return prompt.reduce((len, part) => len + ("content" in part ? part.content.length : 0), 0) } -export function prependHistoryEntry(entries: Prompt[], prompt: Prompt, max = MAX_HISTORY) { +export function prependHistoryEntry( + entries: PromptHistoryStoredEntry[], + prompt: Prompt, + comments: PromptHistoryComment[] = [], + max = MAX_HISTORY, +) { const text = prompt .map((part) => ("content" in part ? part.content : "")) .join("") .trim() const hasImages = prompt.some((part) => part.type === "image") - if (!text && !hasImages) return entries + const hasComments = comments.some((comment) => !!comment.comment.trim()) + if (!text && !hasImages && !hasComments) return entries - const entry = clonePromptParts(prompt) + const entry = { + prompt: clonePromptParts(prompt), + comments: clonePromptHistoryComments(comments), + } satisfies PromptHistoryEntry const last = entries[0] if (last && isPromptEqual(last, entry)) return entries return [entry, ...entries].slice(0, max) } -function isPromptEqual(promptA: Prompt, promptB: Prompt) { - if (promptA.length !== promptB.length) return false - for (let i = 0; i < promptA.length; i++) { - const partA = promptA[i] - const partB = promptB[i] +function isCommentEqual(commentA: PromptHistoryComment, commentB: PromptHistoryComment) { + return ( + commentA.path === commentB.path && + commentA.comment === commentB.comment && + commentA.origin === commentB.origin && + commentA.preview === commentB.preview && + commentA.selection.start === commentB.selection.start && + commentA.selection.end === commentB.selection.end && + commentA.selection.side === commentB.selection.side && + commentA.selection.endSide === commentB.selection.endSide + ) +} + +function isPromptEqual(promptA: PromptHistoryStoredEntry, promptB: PromptHistoryStoredEntry) { + const entryA = normalizePromptHistoryEntry(promptA) + const entryB = normalizePromptHistoryEntry(promptB) + if (entryA.prompt.length !== entryB.prompt.length) return false + for (let i = 0; i < entryA.prompt.length; i++) { + const partA = entryA.prompt[i] + const partB = entryB.prompt[i] if (partA.type !== partB.type) return false if (partA.type === "text" && partA.content !== (partB.type === "text" ? partB.content : "")) return false if (partA.type === "file") { @@ -67,28 +138,35 @@ function isPromptEqual(promptA: Prompt, promptB: Prompt) { if (partA.type === "agent" && partA.name !== (partB.type === "agent" ? partB.name : "")) return false if (partA.type === "image" && partA.id !== (partB.type === "image" ? partB.id : "")) return false } + if (entryA.comments.length !== entryB.comments.length) return false + for (let i = 0; i < entryA.comments.length; i++) { + const commentA = entryA.comments[i] + const commentB = entryB.comments[i] + if (!commentA || !commentB || !isCommentEqual(commentA, commentB)) return false + } return true } type HistoryNavInput = { direction: "up" | "down" - entries: Prompt[] + entries: PromptHistoryStoredEntry[] historyIndex: number currentPrompt: Prompt - savedPrompt: Prompt | null + currentComments: PromptHistoryComment[] + savedPrompt: PromptHistoryEntry | null } type HistoryNavResult = | { handled: false historyIndex: number - savedPrompt: Prompt | null + savedPrompt: PromptHistoryEntry | null } | { handled: true historyIndex: number - savedPrompt: Prompt | null - prompt: Prompt + savedPrompt: PromptHistoryEntry | null + entry: PromptHistoryEntry cursor: "start" | "end" } @@ -103,22 +181,27 @@ export function navigatePromptHistory(input: HistoryNavInput): HistoryNavResult } if (input.historyIndex === -1) { + const entry = normalizePromptHistoryEntry(input.entries[0]) return { handled: true, historyIndex: 0, - savedPrompt: clonePromptParts(input.currentPrompt), - prompt: input.entries[0], + savedPrompt: { + prompt: clonePromptParts(input.currentPrompt), + comments: clonePromptHistoryComments(input.currentComments), + }, + entry, cursor: "start", } } if (input.historyIndex < input.entries.length - 1) { const next = input.historyIndex + 1 + const entry = normalizePromptHistoryEntry(input.entries[next]) return { handled: true, historyIndex: next, savedPrompt: input.savedPrompt, - prompt: input.entries[next], + entry, cursor: "start", } } @@ -132,11 +215,12 @@ export function navigatePromptHistory(input: HistoryNavInput): HistoryNavResult if (input.historyIndex > 0) { const next = input.historyIndex - 1 + const entry = normalizePromptHistoryEntry(input.entries[next]) return { handled: true, historyIndex: next, savedPrompt: input.savedPrompt, - prompt: input.entries[next], + entry, cursor: "end", } } @@ -147,7 +231,7 @@ export function navigatePromptHistory(input: HistoryNavInput): HistoryNavResult handled: true, historyIndex: -1, savedPrompt: null, - prompt: input.savedPrompt, + entry: input.savedPrompt, cursor: "end", } } @@ -156,7 +240,10 @@ export function navigatePromptHistory(input: HistoryNavInput): HistoryNavResult handled: true, historyIndex: -1, savedPrompt: null, - prompt: DEFAULT_PROMPT, + entry: { + prompt: DEFAULT_PROMPT, + comments: [], + }, cursor: "end", } } diff --git a/packages/app/src/components/prompt-input/submit.test.ts b/packages/app/src/components/prompt-input/submit.test.ts index c3d6a92813..4109417d2b 100644 --- a/packages/app/src/components/prompt-input/submit.test.ts +++ b/packages/app/src/components/prompt-input/submit.test.ts @@ -5,10 +5,20 @@ let createPromptSubmit: typeof import("./submit").createPromptSubmit const createdClients: string[] = [] const createdSessions: string[] = [] +const enabledAutoAccept: Array<{ sessionID: string; directory: string }> = [] +const optimistic: Array<{ + message: { + agent: string + model: { providerID: string; modelID: string } + variant?: string + } +}> = [] const sentShell: string[] = [] const syncedDirectories: string[] = [] +let params: { id?: string } = {} let selected = "/repo/worktree-a" +let variant: string | undefined const promptValue: Prompt = [{ type: "text", content: "ls", start: 0, end: 2 }] @@ -25,6 +35,7 @@ const clientFor = (directory: string) => { return { data: undefined } }, prompt: async () => ({ data: undefined }), + promptAsync: async () => ({ data: undefined }), command: async () => ({ data: undefined }), abort: async () => ({ data: undefined }), }, @@ -39,7 +50,7 @@ beforeAll(async () => { mock.module("@solidjs/router", () => ({ useNavigate: () => () => undefined, - useParams: () => ({}), + useParams: () => params, })) mock.module("@opencode-ai/sdk/v2/client", () => ({ @@ -61,7 +72,7 @@ beforeAll(async () => { useLocal: () => ({ model: { current: () => ({ id: "model", provider: { id: "provider" } }), - variant: { current: () => undefined }, + variant: { current: () => variant }, }, agent: { current: () => ({ name: "agent" }), @@ -69,6 +80,14 @@ beforeAll(async () => { }), })) + mock.module("@/context/permission", () => ({ + usePermission: () => ({ + enableAutoAccept(sessionID: string, directory: string) { + enabledAutoAccept.push({ sessionID, directory }) + }, + }), + })) + mock.module("@/context/prompt", () => ({ usePrompt: () => ({ current: () => promptValue, @@ -109,7 +128,11 @@ beforeAll(async () => { data: { command: [] }, session: { optimistic: { - add: () => undefined, + add: (value: { + message: { agent: string; model: { providerID: string; modelID: string }; variant?: string } + }) => { + optimistic.push(value) + }, remove: () => undefined, }, }, @@ -145,9 +168,13 @@ beforeAll(async () => { beforeEach(() => { createdClients.length = 0 createdSessions.length = 0 + enabledAutoAccept.length = 0 + optimistic.length = 0 + params = {} sentShell.length = 0 syncedDirectories.length = 0 selected = "/repo/worktree-a" + variant = undefined }) describe("prompt submit worktree selection", () => { @@ -156,6 +183,7 @@ describe("prompt submit worktree selection", () => { info: () => undefined, imageAttachments: () => [], commentCount: () => 0, + autoAccept: () => false, mode: () => "shell", working: () => false, editor: () => undefined, @@ -181,4 +209,66 @@ describe("prompt submit worktree selection", () => { expect(sentShell).toEqual(["/repo/worktree-a", "/repo/worktree-b"]) expect(syncedDirectories).toEqual(["/repo/worktree-a", "/repo/worktree-b"]) }) + + test("applies auto-accept to newly created sessions", async () => { + const submit = createPromptSubmit({ + info: () => undefined, + imageAttachments: () => [], + commentCount: () => 0, + autoAccept: () => true, + mode: () => "shell", + working: () => false, + editor: () => undefined, + queueScroll: () => undefined, + promptLength: (value) => value.reduce((sum, part) => sum + ("content" in part ? part.content.length : 0), 0), + addToHistory: () => undefined, + resetHistoryNavigation: () => undefined, + setMode: () => undefined, + setPopover: () => undefined, + newSessionWorktree: () => selected, + onNewSessionWorktreeReset: () => undefined, + onSubmit: () => undefined, + }) + + const event = { preventDefault: () => undefined } as unknown as Event + + await submit.handleSubmit(event) + + expect(enabledAutoAccept).toEqual([{ sessionID: "session-1", directory: "/repo/worktree-a" }]) + }) + + test("includes the selected variant on optimistic prompts", async () => { + params = { id: "session-1" } + variant = "high" + + const submit = createPromptSubmit({ + info: () => ({ id: "session-1" }), + imageAttachments: () => [], + commentCount: () => 0, + autoAccept: () => false, + mode: () => "normal", + working: () => false, + editor: () => undefined, + queueScroll: () => undefined, + promptLength: (value) => value.reduce((sum, part) => sum + ("content" in part ? part.content.length : 0), 0), + addToHistory: () => undefined, + resetHistoryNavigation: () => undefined, + setMode: () => undefined, + setPopover: () => undefined, + onSubmit: () => undefined, + }) + + const event = { preventDefault: () => undefined } as unknown as Event + + await submit.handleSubmit(event) + + expect(optimistic).toHaveLength(1) + expect(optimistic[0]).toMatchObject({ + message: { + agent: "agent", + model: { providerID: "provider", modelID: "model" }, + variant: "high", + }, + }) + }) }) diff --git a/packages/app/src/components/prompt-input/submit.ts b/packages/app/src/components/prompt-input/submit.ts index a7ff39e091..fee6b070d9 100644 --- a/packages/app/src/components/prompt-input/submit.ts +++ b/packages/app/src/components/prompt-input/submit.ts @@ -8,6 +8,7 @@ import { useGlobalSync } from "@/context/global-sync" import { useLanguage } from "@/context/language" import { useLayout } from "@/context/layout" import { useLocal } from "@/context/local" +import { usePermission } from "@/context/permission" import { type ImageAttachmentPart, type Prompt, usePrompt } from "@/context/prompt" import { useSDK } from "@/context/sdk" import { useSync } from "@/context/sync" @@ -15,6 +16,7 @@ import { Identifier } from "@/utils/id" import { Worktree as WorktreeState } from "@/utils/worktree" import { buildRequestParts } from "./build-request-parts" import { setCursorPosition } from "./editor-dom" +import { formatServerError } from "@/utils/server-errors" type PendingPrompt = { abort: AbortController @@ -27,6 +29,7 @@ type PromptSubmitInput = { info: Accessor<{ id: string } | undefined> imageAttachments: Accessor commentCount: Accessor + autoAccept: Accessor mode: Accessor<"normal" | "shell"> working: Accessor editor: () => HTMLDivElement | undefined @@ -56,6 +59,7 @@ export function createPromptSubmit(input: PromptSubmitInput) { const sync = useSync() const globalSync = useGlobalSync() const local = useLocal() + const permission = usePermission() const prompt = usePrompt() const layout = useLayout() const language = useLanguage() @@ -140,6 +144,7 @@ export function createPromptSubmit(input: PromptSubmitInput) { const projectDirectory = sdk.directory const isNewSession = !params.id + const shouldAutoAccept = isNewSession && input.autoAccept() const worktreeSelection = input.newSessionWorktree?.() || "main" let sessionDirectory = projectDirectory @@ -197,6 +202,7 @@ export function createPromptSubmit(input: PromptSubmitInput) { return undefined }) if (session) { + if (shouldAutoAccept) permission.enableAutoAccept(session.id, sessionDirectory) layout.handoff.setTabs(base64Encode(sessionDirectory), session.id) navigate(`/${base64Encode(sessionDirectory)}/session/${session.id}`) } @@ -281,7 +287,7 @@ export function createPromptSubmit(input: PromptSubmitInput) { .catch((err) => { showToast({ title: language.t("prompt.toast.commandSendFailed.title"), - description: errorMessage(err), + description: formatServerError(err, language.t, language.t("common.requestFailed")), }) restoreInput() }) @@ -310,6 +316,7 @@ export function createPromptSubmit(input: PromptSubmitInput) { time: { created: Date.now() }, agent, model, + variant, } const addOptimisticMessage = () => diff --git a/packages/app/src/components/server/server-row.tsx b/packages/app/src/components/server/server-row.tsx index 12dcebfa97..5bb290ec30 100644 --- a/packages/app/src/components/server/server-row.tsx +++ b/packages/app/src/components/server/server-row.tsx @@ -1,5 +1,6 @@ import { Tooltip } from "@opencode-ai/ui/tooltip" import { + children, createEffect, createMemo, createSignal, @@ -9,7 +10,7 @@ import { type ParentProps, Show, } from "solid-js" -import { type ServerConnection, serverDisplayName } from "@/context/server" +import { type ServerConnection, serverName } from "@/context/server" import type { ServerHealth } from "@/utils/server-health" interface ServerRowProps extends ParentProps { @@ -20,13 +21,14 @@ interface ServerRowProps extends ParentProps { versionClass?: string dimmed?: boolean badge?: JSXElement + showCredentials?: boolean } export function ServerRow(props: ServerRowProps) { const [truncated, setTruncated] = createSignal(false) let nameRef: HTMLSpanElement | undefined let versionRef: HTMLSpanElement | undefined - const name = createMemo(() => serverDisplayName(props.conn)) + const name = createMemo(() => serverName(props.conn)) const check = () => { const nameTruncated = nameRef ? nameRef.scrollWidth > nameRef.clientWidth : false @@ -52,35 +54,71 @@ export function ServerRow(props: ServerRowProps) { const tooltipValue = () => ( - {name()} + {serverName(props.conn, true)} - {props.status?.version} + v{props.status?.version} ) + const badge = children(() => props.badge) + return ( - +
-
- - {name()} - - - - {props.status?.version} - - - {props.badge} +
+
+ + {name()} + + + + v{props.status?.version} + + + } + > + {(badge) => badge()} + +
+ + {(conn) => ( +
+ + {conn().http.username ? ( + {conn().http.username} + ) : ( + no username + )} + + {conn().http.password && ••••••••} +
+ )} +
+
{props.children}
) } + +export function ServerHealthIndicator(props: { health?: ServerHealth }) { + return ( +
+ ) +} diff --git a/packages/app/src/components/session-context-usage.tsx b/packages/app/src/components/session-context-usage.tsx index 47030aa177..08ae4d3194 100644 --- a/packages/app/src/components/session-context-usage.tsx +++ b/packages/app/src/components/session-context-usage.tsx @@ -39,7 +39,7 @@ export function SessionContextUsage(props: SessionContextUsageProps) { const usd = createMemo( () => - new Intl.NumberFormat(language.locale(), { + new Intl.NumberFormat(language.intl(), { style: "currency", currency: "USD", }), @@ -77,7 +77,7 @@ export function SessionContextUsage(props: SessionContextUsageProps) { {(ctx) => ( <>
- {ctx().total.toLocaleString(language.locale())} + {ctx().total.toLocaleString(language.intl())} {language.t("context.usage.tokens")}
diff --git a/packages/app/src/components/session/session-context-tab.tsx b/packages/app/src/components/session/session-context-tab.tsx index 1ea97c395c..39eb4b4c0e 100644 --- a/packages/app/src/components/session/session-context-tab.tsx +++ b/packages/app/src/components/session/session-context-tab.tsx @@ -9,7 +9,7 @@ import { same } from "@/utils/same" import { Icon } from "@opencode-ai/ui/icon" import { Accordion } from "@opencode-ai/ui/accordion" import { StickyAccordionHeader } from "@opencode-ai/ui/sticky-accordion-header" -import { Code } from "@opencode-ai/ui/code" +import { File } from "@opencode-ai/ui/file" import { Markdown } from "@opencode-ai/ui/markdown" import { ScrollView } from "@opencode-ai/ui/scroll-view" import type { Message, Part, UserMessage } from "@opencode-ai/sdk/v2/client" @@ -47,7 +47,8 @@ function RawMessageContent(props: { message: Message; getParts: (id: string) => }) return ( - - new Intl.NumberFormat(language.locale(), { + new Intl.NumberFormat(language.intl(), { style: "currency", currency: "USD", }), @@ -135,7 +136,7 @@ export function SessionContextTab() { const metrics = createMemo(() => getSessionContextMetrics(messages(), sync.data.provider.all)) const ctx = createMemo(() => metrics().context) - const formatter = createMemo(() => createSessionContextFormatter(language.locale())) + const formatter = createMemo(() => createSessionContextFormatter(language.intl())) const cost = createMemo(() => { return usd().format(metrics().totalCost) @@ -199,7 +200,7 @@ export function SessionContextTab() { const stats = [ { label: "context.stats.session", value: () => info()?.title ?? params.id ?? "—" }, - { label: "context.stats.messages", value: () => counts().all.toLocaleString(language.locale()) }, + { label: "context.stats.messages", value: () => counts().all.toLocaleString(language.intl()) }, { label: "context.stats.provider", value: providerLabel }, { label: "context.stats.model", value: modelLabel }, { label: "context.stats.limit", value: () => formatter().number(ctx()?.limit) }, @@ -212,8 +213,8 @@ export function SessionContextTab() { label: "context.stats.cacheTokens", value: () => `${formatter().number(ctx()?.cacheRead)} / ${formatter().number(ctx()?.cacheWrite)}`, }, - { label: "context.stats.userMessages", value: () => counts().user.toLocaleString(language.locale()) }, - { label: "context.stats.assistantMessages", value: () => counts().assistant.toLocaleString(language.locale()) }, + { label: "context.stats.userMessages", value: () => counts().user.toLocaleString(language.intl()) }, + { label: "context.stats.assistantMessages", value: () => counts().assistant.toLocaleString(language.intl()) }, { label: "context.stats.totalCost", value: cost }, { label: "context.stats.sessionCreated", value: () => formatter().time(info()?.time.created) }, { label: "context.stats.lastActivity", value: () => formatter().time(ctx()?.message.time.created) }, @@ -306,7 +307,7 @@ export function SessionContextTab() {
{breakdownLabel(segment.key)}
-
{segment.percent.toLocaleString(language.locale())}%
+
{segment.percent.toLocaleString(language.intl())}%
)} diff --git a/packages/app/src/components/session/session-header.tsx b/packages/app/src/components/session/session-header.tsx index ae8fc200f2..9b4551584c 100644 --- a/packages/app/src/components/session/session-header.tsx +++ b/packages/app/src/components/session/session-header.tsx @@ -1,28 +1,28 @@ +import { AppIcon } from "@opencode-ai/ui/app-icon" +import { Button } from "@opencode-ai/ui/button" +import { DropdownMenu } from "@opencode-ai/ui/dropdown-menu" +import { Icon } from "@opencode-ai/ui/icon" +import { IconButton } from "@opencode-ai/ui/icon-button" +import { Keybind } from "@opencode-ai/ui/keybind" +import { Popover } from "@opencode-ai/ui/popover" +import { Spinner } from "@opencode-ai/ui/spinner" +import { TextField } from "@opencode-ai/ui/text-field" +import { showToast } from "@opencode-ai/ui/toast" +import { Tooltip, TooltipKeybind } from "@opencode-ai/ui/tooltip" +import { getFilename } from "@opencode-ai/util/path" +import { useParams } from "@solidjs/router" import { createEffect, createMemo, For, onCleanup, Show } from "solid-js" import { createStore } from "solid-js/store" import { Portal } from "solid-js/web" -import { useParams } from "@solidjs/router" -import { useLayout } from "@/context/layout" import { useCommand } from "@/context/command" +import { useGlobalSDK } from "@/context/global-sdk" import { useLanguage } from "@/context/language" +import { useLayout } from "@/context/layout" import { usePlatform } from "@/context/platform" import { useServer } from "@/context/server" import { useSync } from "@/context/sync" -import { useGlobalSDK } from "@/context/global-sdk" -import { getFilename } from "@opencode-ai/util/path" import { decode64 } from "@/utils/base64" import { Persist, persisted } from "@/utils/persist" - -import { Icon } from "@opencode-ai/ui/icon" -import { IconButton } from "@opencode-ai/ui/icon-button" -import { Button } from "@opencode-ai/ui/button" -import { AppIcon } from "@opencode-ai/ui/app-icon" -import { DropdownMenu } from "@opencode-ai/ui/dropdown-menu" -import { Tooltip, TooltipKeybind } from "@opencode-ai/ui/tooltip" -import { Popover } from "@opencode-ai/ui/popover" -import { TextField } from "@opencode-ai/ui/text-field" -import { Keybind } from "@opencode-ai/ui/keybind" -import { showToast } from "@opencode-ai/ui/toast" import { StatusPopover } from "../status-popover" const OPEN_APPS = [ @@ -35,6 +35,7 @@ const OPEN_APPS = [ "terminal", "iterm2", "ghostty", + "warp", "xcode", "android-studio", "powershell", @@ -45,32 +46,68 @@ type OpenApp = (typeof OPEN_APPS)[number] type OS = "macos" | "windows" | "linux" | "unknown" const MAC_APPS = [ - { id: "vscode", label: "VS Code", icon: "vscode", openWith: "Visual Studio Code" }, + { + id: "vscode", + label: "VS Code", + icon: "vscode", + openWith: "Visual Studio Code", + }, { id: "cursor", label: "Cursor", icon: "cursor", openWith: "Cursor" }, { id: "zed", label: "Zed", icon: "zed", openWith: "Zed" }, { id: "textmate", label: "TextMate", icon: "textmate", openWith: "TextMate" }, - { id: "antigravity", label: "Antigravity", icon: "antigravity", openWith: "Antigravity" }, + { + id: "antigravity", + label: "Antigravity", + icon: "antigravity", + openWith: "Antigravity", + }, { id: "terminal", label: "Terminal", icon: "terminal", openWith: "Terminal" }, { id: "iterm2", label: "iTerm2", icon: "iterm2", openWith: "iTerm" }, { id: "ghostty", label: "Ghostty", icon: "ghostty", openWith: "Ghostty" }, + { id: "warp", label: "Warp", icon: "warp", openWith: "Warp" }, { id: "xcode", label: "Xcode", icon: "xcode", openWith: "Xcode" }, - { id: "android-studio", label: "Android Studio", icon: "android-studio", openWith: "Android Studio" }, - { id: "sublime-text", label: "Sublime Text", icon: "sublime-text", openWith: "Sublime Text" }, + { + id: "android-studio", + label: "Android Studio", + icon: "android-studio", + openWith: "Android Studio", + }, + { + id: "sublime-text", + label: "Sublime Text", + icon: "sublime-text", + openWith: "Sublime Text", + }, ] as const const WINDOWS_APPS = [ { id: "vscode", label: "VS Code", icon: "vscode", openWith: "code" }, { id: "cursor", label: "Cursor", icon: "cursor", openWith: "cursor" }, { id: "zed", label: "Zed", icon: "zed", openWith: "zed" }, - { id: "powershell", label: "PowerShell", icon: "powershell", openWith: "powershell" }, - { id: "sublime-text", label: "Sublime Text", icon: "sublime-text", openWith: "Sublime Text" }, + { + id: "powershell", + label: "PowerShell", + icon: "powershell", + openWith: "powershell", + }, + { + id: "sublime-text", + label: "Sublime Text", + icon: "sublime-text", + openWith: "Sublime Text", + }, ] as const const LINUX_APPS = [ { id: "vscode", label: "VS Code", icon: "vscode", openWith: "code" }, { id: "cursor", label: "Cursor", icon: "cursor", openWith: "cursor" }, { id: "zed", label: "Zed", icon: "zed", openWith: "zed" }, - { id: "sublime-text", label: "Sublime Text", icon: "sublime-text", openWith: "Sublime Text" }, + { + id: "sublime-text", + label: "Sublime Text", + icon: "sublime-text", + openWith: "Sublime Text", + }, ] as const type OpenOption = (typeof MAC_APPS)[number] | (typeof WINDOWS_APPS)[number] | (typeof LINUX_APPS)[number] @@ -101,12 +138,12 @@ function useSessionShare(args: { globalSDK: ReturnType currentSession: () => | { - id: string share?: { url?: string } } | undefined + sessionID: () => string | undefined projectDirectory: () => string platform: ReturnType }) { @@ -130,11 +167,11 @@ function useSessionShare(args: { }) const shareSession = () => { - const session = args.currentSession() - if (!session || state.share) return + const sessionID = args.sessionID() + if (!sessionID || state.share) return setState("share", true) args.globalSDK.client.session - .share({ sessionID: session.id, directory: args.projectDirectory() }) + .share({ sessionID, directory: args.projectDirectory() }) .catch((error) => { console.error("Failed to share session", error) }) @@ -144,11 +181,11 @@ function useSessionShare(args: { } const unshareSession = () => { - const session = args.currentSession() - if (!session || state.unshare) return + const sessionID = args.sessionID() + if (!sessionID || state.unshare) return setState("unshare", true) args.globalSDK.client.session - .unshare({ sessionID: session.id, directory: args.projectDirectory() }) + .unshare({ sessionID, directory: args.projectDirectory() }) .catch((error) => { console.error("Failed to unshare session", error) }) @@ -206,14 +243,16 @@ export function SessionHeader() { }) const hotkey = createMemo(() => command.keybind("file.open")) - const currentSession = createMemo(() => sync.data.session.find((s) => s.id === params.id)) + const currentSession = createMemo(() => (params.id ? sync.session.get(params.id) : undefined)) const shareEnabled = createMemo(() => sync.data.config.share !== "disabled") - const showShare = createMemo(() => shareEnabled() && !!currentSession()) + const showShare = createMemo(() => shareEnabled() && !!params.id) const sessionKey = createMemo(() => `${params.dir}${params.id ? "/" + params.id : ""}`) const view = createMemo(() => layout.view(sessionKey)) const os = createMemo(() => detectOS(platform)) - const [exists, setExists] = createStore>>({ finder: true }) + const [exists, setExists] = createStore>>({ + finder: true, + }) const apps = createMemo(() => { if (os() === "macos") return MAC_APPS @@ -259,18 +298,38 @@ export function SessionHeader() { const [prefs, setPrefs] = persisted(Persist.global("open.app"), createStore({ app: "finder" as OpenApp })) const [menu, setMenu] = createStore({ open: false }) + const [openRequest, setOpenRequest] = createStore({ + app: undefined as OpenApp | undefined, + }) const canOpen = createMemo(() => platform.platform === "desktop" && !!platform.openPath && server.isLocal()) - const current = createMemo(() => options().find((o) => o.id === prefs.app) ?? options()[0]) + const current = createMemo( + () => + options().find((o) => o.id === prefs.app) ?? + options()[0] ?? + ({ id: "finder", label: fileManager().label, icon: fileManager().icon } as const), + ) + const opening = createMemo(() => openRequest.app !== undefined) + + const selectApp = (app: OpenApp) => { + if (!options().some((item) => item.id === app)) return + setPrefs("app", app) + } const openDir = (app: OpenApp) => { + if (opening() || !canOpen() || !platform.openPath) return const directory = projectDirectory() if (!directory) return - if (!canOpen()) return const item = options().find((o) => o.id === app) const openWith = item && "openWith" in item ? item.openWith : undefined - Promise.resolve(platform.openPath?.(directory, openWith)).catch((err: unknown) => showRequestError(language, err)) + setOpenRequest("app", app) + platform + .openPath(directory, openWith) + .catch((err: unknown) => showRequestError(language, err)) + .finally(() => { + setOpenRequest("app", undefined) + }) } const copyPath = () => { @@ -292,6 +351,7 @@ export function SessionHeader() { const share = useSessionShare({ globalSDK, currentSession, + sessionID: () => params.id, projectDirectory, platform, }) @@ -315,7 +375,9 @@ export function SessionHeader() {
- {language.t("session.header.search.placeholder", { project: name() })} + {language.t("session.header.search.placeholder", { + project: name(), + })}
@@ -357,14 +419,23 @@ export function SessionHeader() {
@@ -388,13 +463,14 @@ export function SessionHeader() { value={current().id} onChange={(value) => { if (!OPEN_APPS.includes(value as OpenApp)) return - setPrefs("app", value as OpenApp) + selectApp(value as OpenApp) }} > {(o) => ( { setMenu("open", false) openDir(o.id) @@ -452,7 +528,10 @@ export function SessionHeader() { variant: "ghost", class: "rounded-md h-[24px] px-3 border border-border-weak-base bg-surface-panel shadow-none data-[expanded]:bg-surface-base-active", - classList: { "rounded-r-none": share.shareUrl() !== undefined }, + classList: { + "rounded-r-none": share.shareUrl() !== undefined, + "border-r-0": share.shareUrl() !== undefined, + }, style: { scale: 1 }, }} trigger={{language.t("session.share.action.share")}} diff --git a/packages/app/src/components/session/session-new-view.tsx b/packages/app/src/components/session/session-new-view.tsx index b7a544ba9a..52251dbb20 100644 --- a/packages/app/src/components/session/session-new-view.tsx +++ b/packages/app/src/components/session/session-new-view.tsx @@ -4,12 +4,12 @@ import { useSync } from "@/context/sync" import { useSDK } from "@/context/sdk" import { useLanguage } from "@/context/language" import { Icon } from "@opencode-ai/ui/icon" +import { Mark } from "@opencode-ai/ui/logo" import { getDirectory, getFilename } from "@opencode-ai/util/path" const MAIN_WORKTREE = "main" const CREATE_WORKTREE = "create" -const ROOT_CLASS = - "size-full flex flex-col justify-end items-start gap-4 flex-[1_0_0] self-stretch max-w-200 mx-auto 2xl:max-w-[1000px] px-6 pb-16" +const ROOT_CLASS = "size-full flex flex-col" interface NewSessionViewProps { worktree: string @@ -50,33 +50,43 @@ export function NewSessionView(props: NewSessionViewProps) { return (
-
{language.t("command.session.new")}
-
- -
- {getDirectory(projectRoot())} - {getFilename(projectRoot())} +
+
+
+
+ +
{language.t("session.new.title")}
+
+
+
+
+ {getDirectory(projectRoot())} + {getFilename(projectRoot())} +
+
+
+ +
+ {label(current())} +
+
+ + {(project) => ( +
+
+ {language.t("session.new.lastModified")}  + + {DateTime.fromMillis(project().time.updated ?? project().time.created) + .setLocale(language.intl()) + .toRelative()} + +
+
+ )} +
+
-
- -
{label(current())}
-
- - {(project) => ( -
- -
- {language.t("session.new.lastModified")}  - - {DateTime.fromMillis(project().time.updated ?? project().time.created) - .setLocale(language.locale()) - .toRelative()} - -
-
- )} -
) } diff --git a/packages/app/src/components/session/session-sortable-tab.tsx b/packages/app/src/components/session/session-sortable-tab.tsx index b94e7a8e96..dfda91c160 100644 --- a/packages/app/src/components/session/session-sortable-tab.tsx +++ b/packages/app/src/components/session/session-sortable-tab.tsx @@ -13,13 +13,15 @@ import { useCommand } from "@/context/command" export function FileVisual(props: { path: string; active?: boolean }): JSX.Element { return (
- + } + > + + + + + {getFilename(props.path)}
) @@ -37,8 +39,8 @@ export function SortableTab(props: { tab: string; onTabClose: (tab: string) => v return }) return ( -
-
+
+
v title={language.t("common.closeTab")} keybind={command.keybind("tab.close")} placement="bottom" + gutter={10} > { +const stopDemoSound = () => { if (demoSoundState.cleanup) { demoSoundState.cleanup() } - clearTimeout(demoSoundState.timeout) + demoSoundState.cleanup = undefined +} + +const playDemoSound = (src: string | undefined) => { + stopDemoSound() + if (!src) return demoSoundState.timeout = setTimeout(() => { demoSoundState.cleanup = playSound(src) @@ -132,11 +137,17 @@ export const SettingsGeneral: Component = () => { ] as const const fontOptionsList = [...fontOptions] - const soundOptions = [...SOUND_OPTIONS] + const noneSound = { id: "none", label: "sound.option.none", src: undefined } as const + const soundOptions = [noneSound, ...SOUND_OPTIONS] - const soundSelectProps = (current: () => string, set: (id: string) => void) => ({ + const soundSelectProps = ( + enabled: () => boolean, + current: () => string, + setEnabled: (value: boolean) => void, + set: (id: string) => void, + ) => ({ options: soundOptions, - current: soundOptions.find((o) => o.id === current()), + current: enabled() ? (soundOptions.find((o) => o.id === current()) ?? noneSound) : noneSound, value: (o: (typeof soundOptions)[number]) => o.id, label: (o: (typeof soundOptions)[number]) => language.t(o.label), onHighlight: (option: (typeof soundOptions)[number] | undefined) => { @@ -145,6 +156,12 @@ export const SettingsGeneral: Component = () => { }, onSelect: (option: (typeof soundOptions)[number] | undefined) => { if (!option) return + if (option.id === "none") { + setEnabled(false) + stopDemoSound() + return + } + setEnabled(true) set(option.id) playDemoSound(option.src) }, @@ -250,18 +267,50 @@ export const SettingsGeneral: Component = () => { )} +
+
+ ) + const FeedSection = () => ( +
+

{language.t("settings.general.section.feed")}

+ +
-
+
settings.general.setShowReasoningSummaries(checked)} />
+ + +
+ settings.general.setShellToolPartsExpanded(checked)} + /> +
+
+ + +
+ settings.general.setEditToolPartsExpanded(checked)} + /> +
+
) @@ -319,66 +368,45 @@ export const SettingsGeneral: Component = () => { title={language.t("settings.general.sounds.agent.title")} description={language.t("settings.general.sounds.agent.description")} > -
-
- settings.sounds.setAgentEnabled(checked)} - /> -
- settings.sounds.agentEnabled(), + () => settings.sounds.agent(), + (value) => settings.sounds.setAgentEnabled(value), + (id) => settings.sounds.setAgent(id), + )} + /> -
-
- settings.sounds.setPermissionsEnabled(checked)} - /> -
- settings.sounds.permissionsEnabled(), + () => settings.sounds.permissions(), + (value) => settings.sounds.setPermissionsEnabled(value), + (id) => settings.sounds.setPermissions(id), + )} + /> -
-
- settings.sounds.setErrorsEnabled(checked)} - /> -
- settings.sounds.errorsEnabled(), + () => settings.sounds.errors(), + (value) => settings.sounds.setErrorsEnabled(value), + (id) => settings.sounds.setErrors(id), + )} + />
@@ -439,6 +467,8 @@ export const SettingsGeneral: Component = () => {
+ + diff --git a/packages/app/src/components/settings-models.tsx b/packages/app/src/components/settings-models.tsx index 07f6d30e18..eff62cd6c9 100644 --- a/packages/app/src/components/settings-models.tsx +++ b/packages/app/src/components/settings-models.tsx @@ -4,7 +4,6 @@ import { Switch } from "@opencode-ai/ui/switch" import { Icon } from "@opencode-ai/ui/icon" import { IconButton } from "@opencode-ai/ui/icon-button" import { TextField } from "@opencode-ai/ui/text-field" -import type { IconName } from "@opencode-ai/ui/icons/provider" import { type Component, For, Show } from "solid-js" import { useLanguage } from "@/context/language" import { useModels } from "@/context/models" @@ -98,7 +97,7 @@ export const SettingsModels: Component = () => { {(group) => (
- + {group.items[0].provider.name}
diff --git a/packages/app/src/components/settings-providers.tsx b/packages/app/src/components/settings-providers.tsx index d1837ee607..a9839758b7 100644 --- a/packages/app/src/components/settings-providers.tsx +++ b/packages/app/src/components/settings-providers.tsx @@ -3,7 +3,6 @@ import { useDialog } from "@opencode-ai/ui/context/dialog" import { ProviderIcon } from "@opencode-ai/ui/provider-icon" import { Tag } from "@opencode-ai/ui/tag" import { showToast } from "@opencode-ai/ui/toast" -import { iconNames, type IconName } from "@opencode-ai/ui/icons/provider" import { popularProviders, useProviders } from "@/hooks/use-providers" import { createMemo, type Component, For, Show } from "solid-js" import { useLanguage } from "@/context/language" @@ -18,6 +17,7 @@ type ProviderItem = ReturnType["connected"]>[num const PROVIDER_NOTES = [ { match: (id: string) => id === "opencode", key: "dialog.provider.opencode.note" }, + { match: (id: string) => id === "opencode-go", key: "dialog.provider.opencodeGo.tagline" }, { match: (id: string) => id === "anthropic", key: "dialog.provider.anthropic.note" }, { match: (id: string) => id.startsWith("github-copilot"), key: "dialog.provider.copilot.note" }, { match: (id: string) => id === "openai", key: "dialog.provider.openai.note" }, @@ -33,11 +33,6 @@ export const SettingsProviders: Component = () => { const globalSync = useGlobalSync() const providers = useProviders() - const icon = (id: string): IconName => { - if (iconNames.includes(id as IconName)) return id as IconName - return "synthetic" - } - const connected = createMemo(() => { return providers .connected() @@ -154,7 +149,7 @@ export const SettingsProviders: Component = () => { {(item) => (
- + {item.name} {type(item)}
@@ -162,7 +157,7 @@ export const SettingsProviders: Component = () => { when={canDisconnect(item)} fallback={ - Connected from your environment variables + {language.t("settings.providers.connected.environmentDescription")} } > @@ -185,11 +180,14 @@ export const SettingsProviders: Component = () => {
- + {item.name} {language.t("dialog.provider.tag.recommended")} + + {language.t("dialog.provider.tag.recommended")} +
{(key) => {language.t(key())}} @@ -215,11 +213,13 @@ export const SettingsProviders: Component = () => { >
- - Custom provider + + {language.t("provider.custom.title")} {language.t("settings.providers.tag.custom")}
- Add an OpenAI-compatible provider by base URL. + + {language.t("settings.providers.custom.description")} +
- + {language.t("command.session.new")} +
<>
- - - +
0 && providers.paid().length === 0), + hidden: store.gettingStartedDismissed || !(providers.all().length > 0 && providers.paid().length === 0), }} > -
-
-
{language.t("sidebar.gettingStarted.title")}
-
{language.t("sidebar.gettingStarted.line1")}
-
{language.t("sidebar.gettingStarted.line2")}
+
+
+
+
{language.t("sidebar.gettingStarted.title")}
+
+ {language.t("sidebar.gettingStarted.line1")} +
+
+ {language.t("sidebar.gettingStarted.line2")} +
+
+
+ + +
-
@@ -1924,139 +2136,204 @@ export default function Layout(props: ParentProps) { } return ( -
+
-
- -
- }> - {props.children} - -
+
diff --git a/packages/app/src/pages/layout/deep-links.ts b/packages/app/src/pages/layout/deep-links.ts index 7bdb002a36..5dca421f74 100644 --- a/packages/app/src/pages/layout/deep-links.ts +++ b/packages/app/src/pages/layout/deep-links.ts @@ -1,15 +1,17 @@ export const deepLinkEvent = "opencode:deep-link" -export const parseDeepLink = (input: string) => { +const parseUrl = (input: string) => { if (!input.startsWith("opencode://")) return if (typeof URL.canParse === "function" && !URL.canParse(input)) return - const url = (() => { - try { - return new URL(input) - } catch { - return undefined - } - })() + try { + return new URL(input) + } catch { + return + } +} + +export const parseDeepLink = (input: string) => { + const url = parseUrl(input) if (!url) return if (url.hostname !== "open-project") return const directory = url.searchParams.get("directory") @@ -17,9 +19,23 @@ export const parseDeepLink = (input: string) => { return directory } +export const parseNewSessionDeepLink = (input: string) => { + const url = parseUrl(input) + if (!url) return + if (url.hostname !== "new-session") return + const directory = url.searchParams.get("directory") + if (!directory) return + const prompt = url.searchParams.get("prompt") || undefined + if (!prompt) return { directory } + return { directory, prompt } +} + export const collectOpenProjectDeepLinks = (urls: string[]) => urls.map(parseDeepLink).filter((directory): directory is string => !!directory) +export const collectNewSessionDeepLinks = (urls: string[]) => + urls.map(parseNewSessionDeepLink).filter((link): link is { directory: string; prompt?: string } => !!link) + type OpenCodeWindow = Window & { __OPENCODE__?: { deepLinks?: string[] diff --git a/packages/app/src/pages/layout/helpers.test.ts b/packages/app/src/pages/layout/helpers.test.ts index 83d8f4748a..d1569dbd9a 100644 --- a/packages/app/src/pages/layout/helpers.test.ts +++ b/packages/app/src/pages/layout/helpers.test.ts @@ -1,6 +1,25 @@ import { describe, expect, test } from "bun:test" -import { collectOpenProjectDeepLinks, drainPendingDeepLinks, parseDeepLink } from "./deep-links" +import { + collectNewSessionDeepLinks, + collectOpenProjectDeepLinks, + drainPendingDeepLinks, + parseDeepLink, + parseNewSessionDeepLink, +} from "./deep-links" import { displayName, errorMessage, getDraggableId, syncWorkspaceOrder, workspaceKey } from "./helpers" +import { type Session } from "@opencode-ai/sdk/v2/client" +import { hasProjectPermissions, latestRootSession } from "./helpers" + +const session = (input: Partial & Pick) => + ({ + title: "", + version: "v2", + parentID: undefined, + messageCount: 0, + permissions: { session: {}, share: {} }, + time: { created: 0, updated: 0, archived: undefined }, + ...input, + }) as Session describe("layout deep links", () => { test("parses open-project deep links", () => { @@ -42,6 +61,28 @@ describe("layout deep links", () => { expect(result).toEqual(["/a", "/c"]) }) + test("parses new-session deep links with optional prompt", () => { + expect(parseNewSessionDeepLink("opencode://new-session?directory=/tmp/demo")).toEqual({ directory: "/tmp/demo" }) + expect(parseNewSessionDeepLink("opencode://new-session?directory=/tmp/demo&prompt=hello%20world")).toEqual({ + directory: "/tmp/demo", + prompt: "hello world", + }) + }) + + test("ignores new-session deep links without directory", () => { + expect(parseNewSessionDeepLink("opencode://new-session")).toBeUndefined() + expect(parseNewSessionDeepLink("opencode://new-session?directory=")).toBeUndefined() + }) + + test("collects only valid new-session deep links", () => { + const result = collectNewSessionDeepLinks([ + "opencode://new-session?directory=/a", + "opencode://open-project?directory=/b", + "opencode://new-session?directory=/c&prompt=ship%20it", + ]) + expect(result).toEqual([{ directory: "/a" }, { directory: "/c", prompt: "ship it" }]) + }) + test("drains global deep links once", () => { const target = { __OPENCODE__: { @@ -73,6 +114,84 @@ describe("layout workspace helpers", () => { expect(result).toEqual(["/root", "/c", "/b"]) }) + test("finds the latest root session across workspaces", () => { + const result = latestRootSession( + [ + { + path: { directory: "/root" }, + session: [session({ id: "root", directory: "/root", time: { created: 1, updated: 1, archived: undefined } })], + }, + { + path: { directory: "/workspace" }, + session: [ + session({ + id: "workspace", + directory: "/workspace", + time: { created: 2, updated: 2, archived: undefined }, + }), + ], + }, + ], + 120_000, + ) + + expect(result?.id).toBe("workspace") + }) + + test("detects project permissions with a filter", () => { + const result = hasProjectPermissions( + { + root: [{ id: "perm-root" }, { id: "perm-hidden" }], + child: [{ id: "perm-child" }], + }, + (item) => item.id === "perm-child", + ) + + expect(result).toBe(true) + }) + + test("ignores project permissions filtered out", () => { + const result = hasProjectPermissions( + { + root: [{ id: "perm-root" }], + }, + () => false, + ) + + expect(result).toBe(false) + }) + + test("ignores archived and child sessions when finding latest root session", () => { + const result = latestRootSession( + [ + { + path: { directory: "/workspace" }, + session: [ + session({ + id: "archived", + directory: "/workspace", + time: { created: 10, updated: 10, archived: 10 }, + }), + session({ + id: "child", + directory: "/workspace", + parentID: "parent", + time: { created: 20, updated: 20, archived: undefined }, + }), + session({ + id: "root", + directory: "/workspace", + time: { created: 30, updated: 30, archived: undefined }, + }), + ], + }, + ], + 120_000, + ) + + expect(result?.id).toBe("root") + }) + test("extracts draggable id safely", () => { expect(getDraggableId({ draggable: { id: "x" } })).toBe("x") expect(getDraggableId({ draggable: { id: 42 } })).toBeUndefined() diff --git a/packages/app/src/pages/layout/helpers.ts b/packages/app/src/pages/layout/helpers.ts index 6a1e7c0123..42315e5893 100644 --- a/packages/app/src/pages/layout/helpers.ts +++ b/packages/app/src/pages/layout/helpers.ts @@ -28,6 +28,18 @@ export const isRootVisibleSession = (session: Session, directory: string) => export const sortedRootSessions = (store: { session: Session[]; path: { directory: string } }, now: number) => store.session.filter((session) => isRootVisibleSession(session, store.path.directory)).sort(sortSessions(now)) +export const latestRootSession = (stores: { session: Session[]; path: { directory: string } }[], now: number) => + stores + .flatMap((store) => store.session.filter((session) => isRootVisibleSession(session, store.path.directory))) + .sort(sortSessions(now))[0] + +export function hasProjectPermissions( + request: Record, + include: (item: T) => boolean = () => true, +) { + return Object.values(request).some((list) => list?.some(include)) +} + export const childMapByParent = (sessions: Session[]) => { const map = new Map() for (const session of sessions) { @@ -62,9 +74,29 @@ export const errorMessage = (err: unknown, fallback: string) => { return fallback } -export const syncWorkspaceOrder = (local: string, dirs: string[], existing?: string[]) => { - if (!existing) return dirs - const keep = existing.filter((d) => d !== local && dirs.includes(d)) - const missing = dirs.filter((d) => d !== local && !existing.includes(d)) - return [local, ...missing, ...keep] +export const effectiveWorkspaceOrder = (local: string, dirs: string[], persisted?: string[]) => { + const root = workspaceKey(local) + const live = new Map() + + for (const dir of dirs) { + const key = workspaceKey(dir) + if (key === root) continue + if (!live.has(key)) live.set(key, dir) + } + + if (!persisted?.length) return [local, ...live.values()] + + const result = [local] + for (const dir of persisted) { + const key = workspaceKey(dir) + if (key === root) continue + const match = live.get(key) + if (!match) continue + result.push(match) + live.delete(key) + } + + return [...result, ...live.values()] } + +export const syncWorkspaceOrder = effectiveWorkspaceOrder diff --git a/packages/app/src/pages/layout/sidebar-items.tsx b/packages/app/src/pages/layout/sidebar-items.tsx index 194f75f815..8dc03755e4 100644 --- a/packages/app/src/pages/layout/sidebar-items.tsx +++ b/packages/app/src/pages/layout/sidebar-items.tsx @@ -1,31 +1,42 @@ -import { A, useNavigate, useParams } from "@solidjs/router" -import { useGlobalSync } from "@/context/global-sync" -import { useLanguage } from "@/context/language" -import { useLayout, type LocalProject, getAvatarColors } from "@/context/layout" -import { useNotification } from "@/context/notification" -import { base64Encode } from "@opencode-ai/util/encode" +import type { Message, Session, TextPart, UserMessage } from "@opencode-ai/sdk/v2/client" import { Avatar } from "@opencode-ai/ui/avatar" -import { DiffChanges } from "@opencode-ai/ui/diff-changes" import { HoverCard } from "@opencode-ai/ui/hover-card" import { Icon } from "@opencode-ai/ui/icon" import { IconButton } from "@opencode-ai/ui/icon-button" import { MessageNav } from "@opencode-ai/ui/message-nav" import { Spinner } from "@opencode-ai/ui/spinner" import { Tooltip } from "@opencode-ai/ui/tooltip" +import { base64Encode } from "@opencode-ai/util/encode" import { getFilename } from "@opencode-ai/util/path" -import { type Message, type Session, type TextPart, type UserMessage } from "@opencode-ai/sdk/v2/client" -import { For, Match, Show, Switch, createMemo, onCleanup, type Accessor, type JSX } from "solid-js" +import { A, useNavigate, useParams } from "@solidjs/router" +import { type Accessor, createMemo, For, type JSX, Match, onCleanup, Show, Switch } from "solid-js" +import { useGlobalSync } from "@/context/global-sync" +import { useLanguage } from "@/context/language" +import { getAvatarColors, type LocalProject, useLayout } from "@/context/layout" +import { useNotification } from "@/context/notification" +import { usePermission } from "@/context/permission" import { agentColor } from "@/utils/agent" +import { sessionPermissionRequest } from "../session/composer/session-request-tree" +import { hasProjectPermissions } from "./helpers" const OPENCODE_PROJECT_ID = "4b0ea68d7af9a6031a7ffda7ad66e0cb83315750" export const ProjectIcon = (props: { project: LocalProject; class?: string; notify?: boolean }): JSX.Element => { + const globalSync = useGlobalSync() const notification = useNotification() + const permission = usePermission() const dirs = createMemo(() => [props.project.worktree, ...(props.project.sandboxes ?? [])]) const unseenCount = createMemo(() => dirs().reduce((total, directory) => total + notification.project.unseenCount(directory), 0), ) const hasError = createMemo(() => dirs().some((directory) => notification.project.unseenHasError(directory))) + const hasPermissions = createMemo(() => + dirs().some((directory) => { + const [store] = globalSync.child(directory, { bootstrap: false }) + return hasProjectPermissions(store.permission, (item) => !permission.autoResponds(item, directory)) + }), + ) + const notify = createMemo(() => props.notify && (hasPermissions() || unseenCount() > 0)) const name = createMemo(() => props.project.name || getFilename(props.project.worktree)) return (
@@ -37,15 +48,16 @@ export const ProjectIcon = (props: { project: LocalProject; class?: string; noti } {...getAvatarColors(props.project.icon?.color)} class="size-full rounded" - classList={{ "badge-mask": unseenCount() > 0 && props.notify }} + classList={{ "badge-mask": notify() }} />
- 0 && props.notify}> +
@@ -124,13 +136,6 @@ const SessionRow = (props: { {props.session.title} - - {(summary) => ( -
- -
- )} -
) @@ -158,7 +163,6 @@ const SessionHoverPreview = (props: { gutter={16} shift={-2} trigger={props.trigger} - mount={!props.mobile ? props.nav() : undefined} open={props.hoverSession() === props.session.id} onOpenChange={(open) => props.setHoverSession(open ? props.session.id : undefined)} > @@ -186,19 +190,15 @@ export const SessionItem = (props: SessionItemProps): JSX.Element => { const layout = useLayout() const language = useLanguage() const notification = useNotification() + const permission = usePermission() const globalSync = useGlobalSync() const unseenCount = createMemo(() => notification.session.unseenCount(props.session.id)) const hasError = createMemo(() => notification.session.unseenHasError(props.session.id)) const [sessionStore] = globalSync.child(props.session.directory) const hasPermissions = createMemo(() => { - const permissions = sessionStore.permission?.[props.session.id] ?? [] - if (permissions.length > 0) return true - - for (const id of props.children.get(props.session.id) ?? []) { - const childPermissions = sessionStore.permission?.[id] ?? [] - if (childPermissions.length > 0) return true - } - return false + return !!sessionPermissionRequest(sessionStore.session, sessionStore.permission, props.session.id, (item) => { + return !permission.autoResponds(item, props.session.directory) + }) }) const isWorking = createMemo(() => { if (hasPermissions()) return false @@ -230,7 +230,9 @@ export const SessionItem = (props: SessionItemProps): JSX.Element => { const hoverEnabled = createMemo(() => (props.popover ?? true) && hoverAllowed()) const isActive = createMemo(() => props.session.id === params.id) - const hoverPrefetch = { current: undefined as ReturnType | undefined } + const hoverPrefetch = { + current: undefined as ReturnType | undefined, + } const cancelHoverPrefetch = () => { if (hoverPrefetch.current === undefined) return clearTimeout(hoverPrefetch.current) @@ -299,17 +301,15 @@ export const SessionItem = (props: SessionItemProps): JSX.Element => { setHoverSession={props.setHoverSession} messageLabel={messageLabel} onMessageSelect={(message) => { - if (!isActive()) { + if (!isActive()) layout.pendingMessage.set(`${base64Encode(props.session.directory)}/${props.session.id}`, message.id) - navigate(`${props.slug}/session/${props.session.id}`) - return - } - window.history.replaceState(null, "", `#message-${message.id}`) - window.dispatchEvent(new HashChangeEvent("hashchange")) + + navigate(`${props.slug}/session/${props.session.id}#message-${message.id}`) }} trigger={item} />
+
active: Accessor overlay: Accessor + suppressHover: Accessor dirs: Accessor onProjectMouseEnter: (worktree: string, event: MouseEvent) => void onProjectMouseLeave: (worktree: string) => void @@ -71,9 +71,11 @@ const ProjectTile = (props: { closeProject: (directory: string) => void setMenu: (value: boolean) => void setOpen: (value: boolean) => void + setSuppressHover: (value: boolean) => void language: ReturnType }): JSX.Element => { const notification = useNotification() + const layout = useLayout() const unseenCount = createMemo(() => props.dirs().reduce((total, directory) => total + notification.project.unseenCount(directory), 0), ) @@ -89,6 +91,7 @@ const ProjectTile = (props: { modal={!props.sidebarHovering()} onOpenChange={(value) => { props.setMenu(value) + props.setSuppressHover(value) if (value) props.setOpen(false) }} > @@ -105,24 +108,41 @@ const ProjectTile = (props: { !props.selected() && !props.active(), "bg-surface-base-hover border border-border-weak-base": !props.selected() && props.active(), }} + onPointerDown={(event) => { + if (!props.overlay()) return + if (event.button !== 2 && !(event.button === 0 && event.ctrlKey)) return + props.setSuppressHover(true) + event.preventDefault() + }} onMouseEnter={(event: MouseEvent) => { if (!props.overlay()) return + if (props.suppressHover()) return props.onProjectMouseEnter(props.project.worktree, event) }} onMouseLeave={() => { + if (props.suppressHover()) props.setSuppressHover(false) if (!props.overlay()) return props.onProjectMouseLeave(props.project.worktree) }} onFocus={() => { if (!props.overlay()) return + if (props.suppressHover()) return props.onProjectFocus(props.project.worktree) }} - onClick={() => props.navigateToProject(props.project.worktree)} + onClick={() => { + if (props.selected()) { + props.setSuppressHover(true) + layout.sidebar.toggle() + return + } + props.setSuppressHover(false) + props.navigateToProject(props.project.worktree) + }} onBlur={() => props.setOpen(false)} > - + props.showEditProjectDialog(props.project)}> {props.language.t("common.edit")} @@ -179,21 +199,6 @@ const ProjectPreviewPanel = (props: {
{displayName(props.project)}
- - { - event.stopPropagation() - props.setOpen(false) - props.ctx.closeProject(props.project.worktree) - }} - /> -
{props.language.t("sidebar.project.recentSessions")}
@@ -278,16 +283,19 @@ export const SortableProject = (props: { const workspaces = createMemo(() => props.ctx.workspaceIds(props.project).slice(0, 2)) const workspaceEnabled = createMemo(() => props.ctx.workspacesEnabled(props.project)) const dirs = createMemo(() => props.ctx.workspaceIds(props.project)) - const [open, setOpen] = createSignal(false) - const [menu, setMenu] = createSignal(false) + const [state, setState] = createStore({ + open: false, + menu: false, + suppressHover: false, + }) const preview = createMemo(() => !props.mobile && props.ctx.sidebarOpened()) const overlay = createMemo(() => !props.mobile && !props.ctx.sidebarOpened()) const active = createMemo(() => projectTileActive({ - menu: menu(), + menu: state.menu, preview: preview(), - open: open(), + open: state.open, overlay: overlay(), hoverProject: props.ctx.hoverProject(), worktree: props.project.worktree, @@ -296,8 +304,14 @@ export const SortableProject = (props: { createEffect(() => { if (preview()) return - if (!open()) return - setOpen(false) + if (!state.open) return + setState("open", false) + }) + + createEffect(() => { + if (!selected()) return + if (!state.open) return + setState("open", false) }) const label = (directory: string) => { @@ -328,6 +342,7 @@ export const SortableProject = (props: { selected={selected} active={active} overlay={overlay} + suppressHover={() => state.suppressHover} dirs={dirs} onProjectMouseEnter={props.ctx.onProjectMouseEnter} onProjectMouseLeave={props.ctx.onProjectMouseLeave} @@ -337,8 +352,9 @@ export const SortableProject = (props: { toggleProjectWorkspaces={props.ctx.toggleProjectWorkspaces} workspacesEnabled={props.ctx.workspacesEnabled} closeProject={props.ctx.closeProject} - setMenu={setMenu} - setOpen={setOpen} + setMenu={(value) => setState("menu", value)} + setOpen={(value) => setState("open", value)} + setSuppressHover={(value) => setState("suppressHover", value)} language={language} /> ) @@ -346,17 +362,18 @@ export const SortableProject = (props: { return ( // @ts-ignore
- + { - if (menu()) return - setOpen(value) + if (state.menu) return + if (value && state.suppressHover) return + setState("open", value) if (value) props.ctx.setHoverSession(undefined) }} > @@ -371,7 +388,7 @@ export const SortableProject = (props: { projectChildren={projectChildren} workspaceSessions={workspaceSessions} workspaceChildren={workspaceChildren} - setOpen={setOpen} + setOpen={(value) => setState("open", value)} ctx={props.ctx} language={language} /> diff --git a/packages/app/src/pages/layout/sidebar-shell.tsx b/packages/app/src/pages/layout/sidebar-shell.tsx index d813ef3e11..d3070e3749 100644 --- a/packages/app/src/pages/layout/sidebar-shell.tsx +++ b/packages/app/src/pages/layout/sidebar-shell.tsx @@ -1,4 +1,4 @@ -import { createMemo, For, Show, type Accessor, type JSX } from "solid-js" +import { createEffect, createMemo, For, Show, type Accessor, type JSX } from "solid-js" import { DragDropProvider, DragDropSensors, @@ -35,10 +35,22 @@ export const SidebarContent = (props: { }): JSX.Element => { const expanded = createMemo(() => sidebarExpanded(props.mobile, props.opened())) const placement = () => (props.mobile ? "bottom" : "right") + let panel: HTMLDivElement | undefined + + createEffect(() => { + const el = panel + if (!el) return + if (expanded()) { + el.removeAttribute("inert") + return + } + el.setAttribute("inert", "") + }) return ( -
+
@@ -100,7 +112,15 @@ export const SidebarContent = (props: {
- {props.renderPanel()} +
{ + panel = el + }} + classList={{ "flex h-full min-h-0 min-w-0 overflow-hidden": true, "pointer-events-none": !expanded() }} + aria-hidden={!expanded()} + > + {props.renderPanel()} +
) } diff --git a/packages/app/src/pages/layout/sidebar-workspace.tsx b/packages/app/src/pages/layout/sidebar-workspace.tsx index 43d99cf895..c317b9c5ef 100644 --- a/packages/app/src/pages/layout/sidebar-workspace.tsx +++ b/packages/app/src/pages/layout/sidebar-workspace.tsx @@ -182,7 +182,7 @@ const WorkspaceActions = (props: { aria-label={props.language.t("common.moreOptions")} /> - + { if (!props.pendingRename()) return @@ -249,7 +249,7 @@ const WorkspaceSessionList = (props: { loadMore: () => Promise language: ReturnType }): JSX.Element => ( -
- ) - } - diffs={reviewDiffs} - view={view} - diffStyle={input.diffStyle} - onDiffStyleChange={input.onDiffStyleChange} - onScrollRef={(el) => setTree("reviewScroll", el)} - focusedFile={tree.activeDiff} - onLineComment={(comment) => addCommentToContext({ ...comment, origin: "review" })} - comments={comments.all()} - focusedComment={comments.focus()} - onFocusedCommentChange={comments.setFocus} - onViewFile={openReviewFile} - classes={input.classes} - /> - - + + + {language.t("session.review.loadingChanges")}
} + > + setTree("reviewScroll", el)} + focusedFile={tree.activeDiff} + onLineComment={(comment) => addCommentToContext({ ...comment, origin: "review" })} + onLineCommentUpdate={updateCommentInContext} + onLineCommentDelete={removeCommentFromContext} + lineCommentActions={reviewCommentActions()} + comments={comments.all()} + focusedComment={comments.focus()} + onFocusedCommentChange={comments.setFocus} + onViewFile={openReviewFile} + classes={input.classes} + /> + + + + +
+
Create a Git repository
+
+ Track, review, and undo changes in this project +
+
+ +
+ ) : ( +
+
{language.t(reviewEmptyKey())}
+
+ ) + } + diffs={reviewDiffs} + view={view} + diffStyle={input.diffStyle} + onDiffStyleChange={input.onDiffStyleChange} + onScrollRef={(el) => setTree("reviewScroll", el)} + focusedFile={tree.activeDiff} + onLineComment={(comment) => addCommentToContext({ ...comment, origin: "review" })} + onLineCommentUpdate={updateCommentInContext} + onLineCommentDelete={removeCommentFromContext} + lineCommentActions={reviewCommentActions()} + comments={comments.all()} + focusedComment={comments.focus()} + onFocusedCommentChange={comments.setFocus} + onViewFile={openReviewFile} + classes={input.classes} + /> + + + ) const reviewPanel = () => ( @@ -559,7 +967,7 @@ export default function Page() { diffStyle: layout.review.diffStyle(), onDiffStyleChange: layout.review.setDiffStyle, loadingClass: "px-6 py-4 text-text-weak", - emptyClass: "h-full pb-30 flex flex-col items-center justify-center text-center gap-6", + emptyClass: "h-full pb-64 -mt-4 flex flex-col items-center justify-center text-center gap-6", })}
@@ -683,44 +1091,6 @@ export default function Page() { tabs().setActive(next) }) - createEffect( - on( - () => layout.fileTree.opened(), - (opened, prev) => { - if (prev === undefined) return - if (!isDesktop()) return - - if (opened) { - const active = tabs().active() - const tab = active === "review" || (!active && hasReview()) ? "changes" : "all" - layout.fileTree.setTab(tab) - return - } - - if (fileTreeTab() !== "changes") return - tabs().setActive("review") - }, - { defer: true }, - ), - ) - - createEffect(() => { - if (!isDesktop()) return - if (!layout.fileTree.opened()) return - if (fileTreeTab() !== "all") return - - const active = tabs().active() - if (active && active !== "review") return - - const first = openedTabs()[0] - if (first) { - tabs().setActive(first) - return - } - - if (contextOpen()) tabs().setActive("context") - }) - createEffect(() => { const id = params.id if (!id) return @@ -771,12 +1141,6 @@ export default function Page() { let scrollStateFrame: number | undefined let scrollStateTarget: HTMLDivElement | undefined - const scrollSpy = createScrollSpy({ - onActive: (id) => { - if (id === store.messageId) return - setStore("messageId", id) - }, - }) const updateScrollState = (el: HTMLDivElement) => { const max = el.scrollHeight - el.clientHeight @@ -824,116 +1188,34 @@ export default function Page() { ), ) - createEffect( - on( - sessionKey, - () => { - scrollSpy.clear() - }, - { defer: true }, - ), - ) - - const anchor = (id: string) => `message-${id}` - const setScrollRef = (el: HTMLDivElement | undefined) => { scroller = el autoScroll.scrollRef(el) - scrollSpy.setContainer(el) if (el) scheduleScrollState(el) } + const markUserScroll = () => { + scrollMark += 1 + } + createResizeObserver( () => content, () => { const el = scroller if (el) scheduleScrollState(el) - scrollSpy.markDirty() }, ) - const turnInit = 20 - const turnBatch = 20 - let turnHandle: number | undefined - let turnIdle = false - - function cancelTurnBackfill() { - const handle = turnHandle - if (handle === undefined) return - turnHandle = undefined - - if (turnIdle && window.cancelIdleCallback) { - window.cancelIdleCallback(handle) - return - } - - clearTimeout(handle) - } - - function scheduleTurnBackfill() { - if (turnHandle !== undefined) return - if (store.turnStart <= 0) return - - if (window.requestIdleCallback) { - turnIdle = true - turnHandle = window.requestIdleCallback(() => { - turnHandle = undefined - backfillTurns() - }) - return - } - - turnIdle = false - turnHandle = window.setTimeout(() => { - turnHandle = undefined - backfillTurns() - }, 0) - } - - function backfillTurns() { - const start = store.turnStart - if (start <= 0) return - - const next = start - turnBatch - const nextStart = next > 0 ? next : 0 - - const el = scroller - if (!el) { - setStore("turnStart", nextStart) - scheduleTurnBackfill() - return - } - - const beforeTop = el.scrollTop - const beforeHeight = el.scrollHeight - - setStore("turnStart", nextStart) - - requestAnimationFrame(() => { - const delta = el.scrollHeight - beforeHeight - if (!delta) return - el.scrollTop = beforeTop + delta - }) - - scheduleTurnBackfill() - } - - createEffect( - on( - () => [params.id, messagesReady()] as const, - ([id, ready]) => { - cancelTurnBackfill() - setStore("turnStart", 0) - if (!id || !ready) return - - const len = visibleUserMessages().length - const start = len > turnInit ? len - turnInit : 0 - setStore("turnStart", start) - scheduleTurnBackfill() - }, - { defer: true }, - ), - ) + const historyWindow = createSessionHistoryWindow({ + sessionID: () => params.id, + messagesReady, + visibleUserMessages, + historyMore, + historyLoading, + loadMore: (sessionID) => sync.session.history.loadMore(sessionID), + userScrolled: autoScroll.userScrolled, + scroller: () => scroller, + }) createResizeObserver( () => promptDock, @@ -944,14 +1226,15 @@ export default function Page() { const el = scroller const delta = next - dockHeight - const stick = el ? el.scrollHeight - el.clientHeight - el.scrollTop < 10 + Math.max(0, delta) : false + const stick = el + ? !autoScroll.userScrolled() || el.scrollHeight - el.clientHeight - el.scrollTop < 10 + Math.max(0, delta) + : false dockHeight = next if (stick) autoScroll.forceScrollToBottom() if (el) scheduleScrollState(el) - scrollSpy.markDirty() }, ) @@ -960,13 +1243,12 @@ export default function Page() { sessionID: () => params.id, messagesReady, visibleUserMessages, - turnStart: () => store.turnStart, + turnStart: historyWindow.turnStart, currentMessageId: () => store.messageId, pendingMessage: () => ui.pendingMessage, setPendingMessage: (value) => setUi("pendingMessage", value), setActiveMessage, - setTurnStart: (value) => setStore("turnStart", value), - scheduleTurnBackfill, + setTurnStart: historyWindow.setTurnStart, autoScroll, scroller: () => scroller, anchor, @@ -979,9 +1261,8 @@ export default function Page() { }) onCleanup(() => { - cancelTurnBackfill() document.removeEventListener("keydown", handleKeyDown) - scrollSpy.destroy() + if (reviewFrame !== undefined) cancelAnimationFrame(reviewFrame) if (scrollStateFrame !== undefined) cancelAnimationFrame(scrollStateFrame) }) @@ -1001,9 +1282,9 @@ export default function Page() { {/* Session panel */}
- + { @@ -1043,21 +1324,14 @@ export default function Page() { const root = scroller if (root) scheduleScrollState(root) }} - turnStart={store.turnStart} - onRenderEarlier={() => setStore("turnStart", 0)} + turnStart={historyWindow.turnStart()} historyMore={historyMore()} historyLoading={historyLoading()} onLoadEarlier={() => { - const id = params.id - if (!id) return - setStore("turnStart", 0) - sync.session.history.loadMore(id) + void historyWindow.loadAndReveal() }} - renderedUserMessages={renderedUserMessages()} + renderedUserMessages={historyWindow.renderedUserMessages()} anchor={anchor} - onRegisterMessage={scrollSpy.register} - onUnregisterMessage={scrollSpy.unregister} - lastUserMessageID={lastUserMessage()?.id} /> @@ -1085,6 +1359,7 @@ export default function Page() { { inputRef = el @@ -1102,17 +1377,28 @@ export default function Page() { /> - +
size.start()}> + { + size.touch() + layout.session.resize(width) + }} + /> +
- +
diff --git a/packages/app/src/pages/session/composer/session-composer-region.tsx b/packages/app/src/pages/session/composer/session-composer-region.tsx index cfd78ece85..93ea3d465c 100644 --- a/packages/app/src/pages/session/composer/session-composer-region.tsx +++ b/packages/app/src/pages/session/composer/session-composer-region.tsx @@ -1,5 +1,7 @@ -import { Show, createEffect, createMemo } from "solid-js" +import { Show, createEffect, createMemo, createSignal, onCleanup } from "solid-js" +import { createStore } from "solid-js/store" import { useParams } from "@solidjs/router" +import { useSpring } from "@opencode-ai/ui/motion-spring" import { PromptInput } from "@/components/prompt-input" import { useLanguage } from "@/context/language" import { usePrompt } from "@/context/prompt" @@ -11,6 +13,7 @@ import { SessionTodoDock } from "@/pages/session/composer/session-todo-dock" export function SessionComposerRegion(props: { state: SessionComposerState + ready: boolean centered: boolean inputRef: (el: HTMLDivElement) => void newSessionWorktree: string @@ -18,6 +21,23 @@ export function SessionComposerRegion(props: { onSubmit: () => void onResponseSubmit: () => void setPromptDockRef: (el: HTMLDivElement) => void + visualDuration?: number + bounce?: number + dockOpenVisualDuration?: number + dockOpenBounce?: number + dockCloseVisualDuration?: number + dockCloseBounce?: number + drawerExpandVisualDuration?: number + drawerExpandBounce?: number + drawerCollapseVisualDuration?: number + drawerCollapseBounce?: number + subtitleDuration?: number + subtitleTravel?: number + subtitleEdge?: number + countDuration?: number + countMask?: number + countMaskHeight?: number + countWidthDuration?: number }) { const params = useParams() const prompt = usePrompt() @@ -43,6 +63,74 @@ export function SessionComposerRegion(props: { setSessionHandoff(sessionKey(), { prompt: previewPrompt() }) }) + const [gate, setGate] = createStore({ + ready: false, + }) + let timer: number | undefined + let frame: number | undefined + + const clear = () => { + if (timer !== undefined) { + window.clearTimeout(timer) + timer = undefined + } + if (frame !== undefined) { + cancelAnimationFrame(frame) + frame = undefined + } + } + + createEffect(() => { + sessionKey() + const ready = props.ready + const delay = 140 + + clear() + setGate("ready", false) + if (!ready) return + + frame = requestAnimationFrame(() => { + frame = undefined + timer = window.setTimeout(() => { + setGate("ready", true) + timer = undefined + }, delay) + }) + }) + + onCleanup(clear) + + const open = createMemo(() => gate.ready && props.state.dock() && !props.state.closing()) + const config = createMemo(() => + open() + ? { + visualDuration: props.dockOpenVisualDuration ?? props.visualDuration ?? 0.3, + bounce: props.dockOpenBounce ?? props.bounce ?? 0, + } + : { + visualDuration: props.dockCloseVisualDuration ?? props.visualDuration ?? 0.3, + bounce: props.dockCloseBounce ?? props.bounce ?? 0, + }, + ) + const progress = useSpring(() => (open() ? 1 : 0), config) + const value = createMemo(() => Math.max(0, Math.min(1, progress()))) + const [height, setHeight] = createSignal(320) + const dock = createMemo(() => (gate.ready && props.state.dock()) || value() > 0.001) + const full = createMemo(() => Math.max(78, height())) + const [contentRef, setContentRef] = createSignal() + + createEffect(() => { + const el = contentRef() + if (!el) return + const update = () => { + setHeight(el.getBoundingClientRect().height) + } + update() + const observer = new ResizeObserver(update) + observer.observe(el) + onCleanup(() => observer.disconnect()) + }) + return (
} > - +
- +
+ +
+ ({ + id: input.id, + parentID: input.parentID, + }) as Session + +const permission = (id: string, sessionID: string) => + ({ + id, + sessionID, + }) as PermissionRequest + +const question = (id: string, sessionID: string) => + ({ + id, + sessionID, + questions: [], + }) as QuestionRequest + +describe("sessionPermissionRequest", () => { + test("prefers the current session permission", () => { + const sessions = [session({ id: "root" }), session({ id: "child", parentID: "root" })] + const permissions = { + root: [permission("perm-root", "root")], + child: [permission("perm-child", "child")], + } + + expect(sessionPermissionRequest(sessions, permissions, "root")?.id).toBe("perm-root") + }) + + test("returns a nested child permission", () => { + const sessions = [ + session({ id: "root" }), + session({ id: "child", parentID: "root" }), + session({ id: "grand", parentID: "child" }), + session({ id: "other" }), + ] + const permissions = { + grand: [permission("perm-grand", "grand")], + other: [permission("perm-other", "other")], + } + + expect(sessionPermissionRequest(sessions, permissions, "root")?.id).toBe("perm-grand") + }) + + test("returns undefined without a matching tree permission", () => { + const sessions = [session({ id: "root" }), session({ id: "child", parentID: "root" })] + const permissions = { + other: [permission("perm-other", "other")], + } + + expect(sessionPermissionRequest(sessions, permissions, "root")).toBeUndefined() + }) + + test("skips filtered permissions in the current tree", () => { + const sessions = [session({ id: "root" }), session({ id: "child", parentID: "root" })] + const permissions = { + root: [permission("perm-root", "root")], + child: [permission("perm-child", "child")], + } + + expect(sessionPermissionRequest(sessions, permissions, "root", (item) => item.id !== "perm-root"))?.toMatchObject({ + id: "perm-child", + }) + }) + + test("returns undefined when all tree permissions are filtered out", () => { + const sessions = [session({ id: "root" }), session({ id: "child", parentID: "root" })] + const permissions = { + root: [permission("perm-root", "root")], + child: [permission("perm-child", "child")], + } + + expect(sessionPermissionRequest(sessions, permissions, "root", () => false)).toBeUndefined() + }) +}) + +describe("sessionQuestionRequest", () => { + test("prefers the current session question", () => { + const sessions = [session({ id: "root" }), session({ id: "child", parentID: "root" })] + const questions = { + root: [question("q-root", "root")], + child: [question("q-child", "child")], + } + + expect(sessionQuestionRequest(sessions, questions, "root")?.id).toBe("q-root") + }) + + test("returns a nested child question", () => { + const sessions = [ + session({ id: "root" }), + session({ id: "child", parentID: "root" }), + session({ id: "grand", parentID: "child" }), + ] + const questions = { + grand: [question("q-grand", "grand")], + } + + expect(sessionQuestionRequest(sessions, questions, "root")?.id).toBe("q-grand") + }) +}) diff --git a/packages/app/src/pages/session/composer/session-composer-state.ts b/packages/app/src/pages/session/composer/session-composer-state.ts index 04c6f7e692..f70bc4bbdd 100644 --- a/packages/app/src/pages/session/composer/session-composer-state.ts +++ b/packages/app/src/pages/session/composer/session-composer-state.ts @@ -5,39 +5,53 @@ import { useParams } from "@solidjs/router" import { showToast } from "@opencode-ai/ui/toast" import { useGlobalSync } from "@/context/global-sync" import { useLanguage } from "@/context/language" +import { usePermission } from "@/context/permission" import { useSDK } from "@/context/sdk" import { useSync } from "@/context/sync" +import { sessionPermissionRequest, sessionQuestionRequest } from "./session-request-tree" export function createSessionComposerBlocked() { const params = useParams() + const permission = usePermission() + const sdk = useSDK() const sync = useSync() + const permissionRequest = createMemo(() => + sessionPermissionRequest(sync.data.session, sync.data.permission, params.id, (item) => { + return !permission.autoResponds(item, sdk.directory) + }), + ) + const questionRequest = createMemo(() => sessionQuestionRequest(sync.data.session, sync.data.question, params.id)) + return createMemo(() => { const id = params.id if (!id) return false - return !!sync.data.permission[id]?.[0] || !!sync.data.question[id]?.[0] + return !!permissionRequest() || !!questionRequest() }) } -export function createSessionComposerState() { +export function createSessionComposerState(options?: { closeMs?: number | (() => number) }) { const params = useParams() const sdk = useSDK() const sync = useSync() const globalSync = useGlobalSync() const language = useLanguage() + const permission = usePermission() const questionRequest = createMemo((): QuestionRequest | undefined => { - const id = params.id - if (!id) return - return sync.data.question[id]?.[0] + return sessionQuestionRequest(sync.data.session, sync.data.question, params.id) }) const permissionRequest = createMemo((): PermissionRequest | undefined => { - const id = params.id - if (!id) return - return sync.data.permission[id]?.[0] + return sessionPermissionRequest(sync.data.session, sync.data.permission, params.id, (item) => { + return !permission.autoResponds(item, sdk.directory) + }) }) - const blocked = createSessionComposerBlocked() + const blocked = createMemo(() => { + const id = params.id + if (!id) return false + return !!permissionRequest() || !!questionRequest() + }) const todos = createMemo((): Todo[] => { const id = params.id @@ -82,12 +96,19 @@ export function createSessionComposerState() { let timer: number | undefined let raf: number | undefined + const closeMs = () => { + const value = options?.closeMs + if (typeof value === "function") return Math.max(0, value()) + if (typeof value === "number") return Math.max(0, value) + return 400 + } + const scheduleClose = () => { if (timer) window.clearTimeout(timer) timer = window.setTimeout(() => { setStore({ dock: false, closing: false }) timer = undefined - }, 400) + }, closeMs()) } createEffect( diff --git a/packages/app/src/pages/session/composer/session-question-dock.tsx b/packages/app/src/pages/session/composer/session-question-dock.tsx index fd2ced3dc8..b22a92eb0a 100644 --- a/packages/app/src/pages/session/composer/session-question-dock.tsx +++ b/packages/app/src/pages/session/composer/session-question-dock.tsx @@ -8,6 +8,8 @@ import type { QuestionAnswer, QuestionRequest } from "@opencode-ai/sdk/v2" import { useLanguage } from "@/context/language" import { useSDK } from "@/context/sdk" +const cache = new Map() + export const SessionQuestionDock: Component<{ request: QuestionRequest; onSubmit: () => void }> = (props) => { const sdk = useSDK() const language = useLanguage() @@ -15,16 +17,18 @@ export const SessionQuestionDock: Component<{ request: QuestionRequest; onSubmit const questions = createMemo(() => props.request.questions) const total = createMemo(() => questions().length) + const cached = cache.get(props.request.id) const [store, setStore] = createStore({ - tab: 0, - answers: [] as QuestionAnswer[], - custom: [] as string[], - customOn: [] as boolean[], + tab: cached?.tab ?? 0, + answers: cached?.answers ?? ([] as QuestionAnswer[]), + custom: cached?.custom ?? ([] as string[]), + customOn: cached?.customOn ?? ([] as boolean[]), editing: false, sending: false, }) let root: HTMLDivElement | undefined + let replied = false const question = createMemo(() => questions()[store.tab]) const options = createMemo(() => question()?.options ?? []) @@ -107,6 +111,16 @@ export const SessionQuestionDock: Component<{ request: QuestionRequest; onSubmit }) }) + onCleanup(() => { + if (replied) return + cache.set(props.request.id, { + tab: store.tab, + answers: store.answers.map((a) => (a ? [...a] : [])), + custom: store.custom.map((s) => s ?? ""), + customOn: store.customOn.map((b) => b ?? false), + }) + }) + const fail = (err: unknown) => { const message = err instanceof Error ? err.message : String(err) showToast({ title: language.t("common.requestFailed"), description: message }) @@ -119,6 +133,8 @@ export const SessionQuestionDock: Component<{ request: QuestionRequest; onSubmit setStore("sending", true) try { await sdk.client.question.reply({ requestID: props.request.id, answers }) + replied = true + cache.delete(props.request.id) } catch (err) { fail(err) } finally { @@ -133,6 +149,8 @@ export const SessionQuestionDock: Component<{ request: QuestionRequest; onSubmit setStore("sending", true) try { await sdk.client.question.reject({ requestID: props.request.id }) + replied = true + cache.delete(props.request.id) } catch (err) { fail(err) } finally { diff --git a/packages/app/src/pages/session/composer/session-request-tree.ts b/packages/app/src/pages/session/composer/session-request-tree.ts new file mode 100644 index 0000000000..03872c091c --- /dev/null +++ b/packages/app/src/pages/session/composer/session-request-tree.ts @@ -0,0 +1,52 @@ +import type { PermissionRequest, QuestionRequest, Session } from "@opencode-ai/sdk/v2/client" + +function sessionTreeRequest( + session: Session[], + request: Record, + sessionID?: string, + include: (item: T) => boolean = () => true, +) { + if (!sessionID) return + + const map = session.reduce((acc, item) => { + if (!item.parentID) return acc + const list = acc.get(item.parentID) + if (list) list.push(item.id) + if (!list) acc.set(item.parentID, [item.id]) + return acc + }, new Map()) + + const seen = new Set([sessionID]) + const ids = [sessionID] + for (const id of ids) { + const list = map.get(id) + if (!list) continue + for (const child of list) { + if (seen.has(child)) continue + seen.add(child) + ids.push(child) + } + } + + const id = ids.find((id) => request[id]?.some(include)) + if (!id) return + return request[id]?.find(include) +} + +export function sessionPermissionRequest( + session: Session[], + request: Record, + sessionID?: string, + include?: (item: PermissionRequest) => boolean, +) { + return sessionTreeRequest(session, request, sessionID, include) +} + +export function sessionQuestionRequest( + session: Session[], + request: Record, + sessionID?: string, + include?: (item: QuestionRequest) => boolean, +) { + return sessionTreeRequest(session, request, sessionID, include) +} diff --git a/packages/app/src/pages/session/composer/session-todo-dock.tsx b/packages/app/src/pages/session/composer/session-todo-dock.tsx index ca7a5abd15..da2b8c8da1 100644 --- a/packages/app/src/pages/session/composer/session-todo-dock.tsx +++ b/packages/app/src/pages/session/composer/session-todo-dock.tsx @@ -1,8 +1,12 @@ import type { Todo } from "@opencode-ai/sdk/v2" +import { AnimatedNumber } from "@opencode-ai/ui/animated-number" import { Checkbox } from "@opencode-ai/ui/checkbox" import { DockTray } from "@opencode-ai/ui/dock-surface" import { IconButton } from "@opencode-ai/ui/icon-button" -import { For, Show, createEffect, createMemo, createSignal, on, onCleanup } from "solid-js" +import { useSpring } from "@opencode-ai/ui/motion-spring" +import { TextReveal } from "@opencode-ai/ui/text-reveal" +import { TextStrikethrough } from "@opencode-ai/ui/text-strikethrough" +import { Index, createEffect, createMemo, createSignal, on, onCleanup } from "solid-js" import { createStore } from "solid-js/store" function dot(status: Todo["status"]) { @@ -30,19 +34,35 @@ function dot(status: Todo["status"]) { ) } -export function SessionTodoDock(props: { todos: Todo[]; title: string; collapseLabel: string; expandLabel: string }) { +export function SessionTodoDock(props: { + todos: Todo[] + title: string + collapseLabel: string + expandLabel: string + dockProgress?: number + visualDuration?: number + bounce?: number + expandVisualDuration?: number + expandBounce?: number + collapseVisualDuration?: number + collapseBounce?: number + subtitleDuration?: number + subtitleTravel?: number + subtitleEdge?: number + countDuration?: number + countMask?: number + countMaskHeight?: number + countWidthDuration?: number +}) { const [store, setStore] = createStore({ collapsed: false, }) const toggle = () => setStore("collapsed", (value) => !value) - const summary = createMemo(() => { - const total = props.todos.length - if (total === 0) return "" - const completed = props.todos.filter((todo) => todo.status === "completed").length - return `${completed} of ${total} ${props.title.toLowerCase()} completed` - }) + const total = createMemo(() => props.todos.length) + const done = createMemo(() => props.todos.filter((todo) => todo.status === "completed").length) + const label = createMemo(() => `${done()} of ${total()} ${props.title.toLowerCase()} completed`) const active = createMemo( () => @@ -53,56 +73,134 @@ export function SessionTodoDock(props: { todos: Todo[]; title: string; collapseL ) const preview = createMemo(() => active()?.content ?? "") + const config = createMemo(() => + store.collapsed + ? { + visualDuration: props.collapseVisualDuration ?? props.visualDuration ?? 0.3, + bounce: props.collapseBounce ?? props.bounce ?? 0, + } + : { + visualDuration: props.expandVisualDuration ?? props.visualDuration ?? 0.3, + bounce: props.expandBounce ?? props.bounce ?? 0, + }, + ) + const collapse = useSpring(() => (store.collapsed ? 1 : 0), config) + const dock = createMemo(() => Math.max(0, Math.min(1, props.dockProgress ?? 1))) + const shut = createMemo(() => 1 - dock()) + const value = createMemo(() => Math.max(0, Math.min(1, collapse()))) + const hide = createMemo(() => Math.max(value(), shut())) + const off = createMemo(() => hide() > 0.98) + const turn = createMemo(() => Math.max(0, Math.min(1, value()))) + const [height, setHeight] = createSignal(320) + const full = createMemo(() => Math.max(78, height())) + let contentRef: HTMLDivElement | undefined + + createEffect(() => { + const el = contentRef + if (!el) return + const update = () => { + setHeight(el.getBoundingClientRect().height) + } + update() + const observer = new ResizeObserver(update) + observer.observe(el) + onCleanup(() => observer.disconnect()) + }) return ( -
{ - if (event.key !== "Enter" && event.key !== " ") return - event.preventDefault() - toggle() - }} - > - {summary()} - -
- -
{preview()}
-
+
+
{ + if (event.key !== "Enter" && event.key !== " ") return + event.preventDefault() + toggle() + }} + > + + + of + +  {props.title.toLowerCase()} completed + +
+ +
+
+ { + event.preventDefault() + event.stopPropagation() + }} + onClick={(event) => { + event.stopPropagation() + toggle() + }} + aria-label={store.collapsed ? props.expandLabel : props.collapseLabel} + />
- -
- { - event.preventDefault() - event.stopPropagation() - }} - onClick={(event) => { - event.stopPropagation() - toggle() - }} - aria-label={store.collapsed ? props.expandLabel : props.collapseLabel} - />
-
- ) @@ -171,33 +269,40 @@ function TodoList(props: { todos: Todo[]; open: boolean }) { }, 250) }} > - + {(todo) => ( - - {todo.content} - + /> )} - +
{ - const start = Math.min(range.start, range.end) - const end = Math.max(range.start, range.end) - if (start === end) return `line ${start}` - return `lines ${start}-${end}` +function FileCommentMenu(props: { + moreLabel: string + editLabel: string + deleteLabel: string + onEdit: VoidFunction + onDelete: VoidFunction +}) { + return ( +
event.stopPropagation()} onClick={(event) => event.stopPropagation()}> + + + + + + {props.editLabel} + + + {props.deleteLabel} + + + + +
+ ) } export function FileTabContent(props: { tab: string }) { @@ -31,7 +59,7 @@ export function FileTabContent(props: { tab: string }) { const comments = useComments() const language = useLanguage() const prompt = usePrompt() - const codeComponent = useCodeComponent() + const fileComponent = useFileComponent() const sessionKey = createMemo(() => `${params.dir}${params.id ? "/" + params.id : ""}`) const tabs = createMemo(() => layout.tabs(sessionKey)) @@ -39,8 +67,16 @@ export function FileTabContent(props: { tab: string }) { let scroll: HTMLDivElement | undefined let scrollFrame: number | undefined + let restoreFrame: number | undefined let pending: { x: number; y: number } | undefined let codeScroll: HTMLElement[] = [] + let find: FileSearchHandle | null = null + + const search = { + register: (handle: FileSearchHandle | null) => { + find = handle + }, + } const path = createMemo(() => file.pathFromTab(props.tab)) const state = createMemo(() => { @@ -50,66 +86,18 @@ export function FileTabContent(props: { tab: string }) { }) const contents = createMemo(() => state()?.content?.content ?? "") const cacheKey = createMemo(() => sampledChecksum(contents())) - const isImage = createMemo(() => { - const c = state()?.content - return c?.encoding === "base64" && c?.mimeType?.startsWith("image/") && c?.mimeType !== "image/svg+xml" - }) - const isSvg = createMemo(() => { - const c = state()?.content - return c?.mimeType === "image/svg+xml" - }) - const isBinary = createMemo(() => state()?.content?.type === "binary") - const svgContent = createMemo(() => { - if (!isSvg()) return - const c = state()?.content - if (!c) return - if (c.encoding !== "base64") return c.content - return decode64(c.content) - }) - - const svgDecodeFailed = createMemo(() => { - if (!isSvg()) return false - const c = state()?.content - if (!c) return false - if (c.encoding !== "base64") return false - return svgContent() === undefined - }) - - const svgToast = { shown: false } - createEffect(() => { - if (!svgDecodeFailed()) return - if (svgToast.shown) return - svgToast.shown = true - showToast({ - variant: "error", - title: language.t("toast.file.loadFailed.title"), - }) - }) - const svgPreviewUrl = createMemo(() => { - if (!isSvg()) return - const c = state()?.content - if (!c) return - if (c.encoding === "base64") return `data:image/svg+xml;base64,${c.content}` - return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(c.content)}` - }) - const imageDataUrl = createMemo(() => { - if (!isImage()) return - const c = state()?.content - return `data:${c?.mimeType};base64,${c?.content}` - }) - const selectedLines = createMemo(() => { + const selectedLines = createMemo(() => { const p = path() if (!p) return null - if (file.ready()) return file.selectedLines(p) ?? null - return getSessionHandoff(sessionKey())?.files[p] ?? null + if (file.ready()) return (file.selectedLines(p) as SelectedLineRange | undefined) ?? null + return (getSessionHandoff(sessionKey())?.files[p] as SelectedLineRange | undefined) ?? null }) const selectionPreview = (source: string, selection: FileSelection) => { - const start = Math.max(1, Math.min(selection.startLine, selection.endLine)) - const end = Math.max(selection.startLine, selection.endLine) - const lines = source.split("\n").slice(start - 1, end) - if (lines.length === 0) return undefined - return lines.slice(0, 2).join("\n") + return previewSelectedLines(source, { + start: selection.startLine, + end: selection.endLine, + }) } const addCommentToContext = (input: { @@ -145,7 +133,25 @@ export function FileTabContent(props: { tab: string }) { }) } - let wrap: HTMLDivElement | undefined + const updateCommentInContext = (input: { + id: string + file: string + selection: SelectedLineRange + comment: string + }) => { + comments.update(input.file, input.id, input.comment) + const preview = + input.file === path() ? selectionPreview(contents(), selectionFromLines(input.selection)) : undefined + prompt.context.updateComment(input.file, input.id, { + comment: input.comment, + ...(preview ? { preview } : {}), + }) + } + + const removeCommentFromContext = (input: { id: string; file: string }) => { + comments.remove(input.file, input.id) + prompt.context.removeComment(input.file, input.id) + } const fileComments = createMemo(() => { const p = path() @@ -153,121 +159,104 @@ export function FileTabContent(props: { tab: string }) { return comments.list(p) }) - const commentLayout = createMemo(() => { - return fileComments() - .map((comment) => `${comment.id}:${comment.selection.start}:${comment.selection.end}`) - .join("|") - }) - const commentedLines = createMemo(() => fileComments().map((comment) => comment.selection)) const [note, setNote] = createStore({ openedComment: null as string | null, commenting: null as SelectedLineRange | null, - draft: "", - positions: {} as Record, - draftTop: undefined as number | undefined, + selected: null as SelectedLineRange | null, }) - const setCommenting = (range: SelectedLineRange | null) => { - setNote("commenting", range) - scheduleComments() - if (!range) return - setNote("draft", "") + const syncSelected = (range: SelectedLineRange | null) => { + const p = path() + if (!p) return + file.setSelectedLines(p, range ? cloneSelectedLineRange(range) : null) } - const getRoot = () => { - const el = wrap - if (!el) return + const activeSelection = () => note.selected ?? selectedLines() - const host = el.querySelector("diffs-container") - if (!(host instanceof HTMLElement)) return + const commentsUi = createLineCommentController({ + comments: fileComments, + label: language.t("ui.lineComment.submit"), + draftKey: () => path() ?? props.tab, + state: { + opened: () => note.openedComment, + setOpened: (id) => setNote("openedComment", id), + selected: () => note.selected, + setSelected: (range) => setNote("selected", range), + commenting: () => note.commenting, + setCommenting: (range) => setNote("commenting", range), + syncSelected, + hoverSelected: syncSelected, + }, + getHoverSelectedRange: activeSelection, + cancelDraftOnCommentToggle: true, + clearSelectionOnSelectionEndNull: true, + onSubmit: ({ comment, selection }) => { + const p = path() + if (!p) return + addCommentToContext({ file: p, selection, comment, origin: "file" }) + }, + onUpdate: ({ id, comment, selection }) => { + const p = path() + if (!p) return + updateCommentInContext({ id, file: p, selection, comment }) + }, + onDelete: (comment) => { + const p = path() + if (!p) return + removeCommentFromContext({ id: comment.id, file: p }) + }, + editSubmitLabel: language.t("common.save"), + renderCommentActions: (_, controls) => ( + + ), + onDraftPopoverFocusOut: (e: FocusEvent) => { + const current = e.currentTarget as HTMLDivElement + const target = e.relatedTarget + if (target instanceof Node && current.contains(target)) return - const root = host.shadowRoot - if (!root) return - - return root - } - - const findMarker = (root: ShadowRoot, range: SelectedLineRange) => { - const line = Math.max(range.start, range.end) - const node = root.querySelector(`[data-line="${line}"]`) - if (!(node instanceof HTMLElement)) return - return node - } - - const markerTop = (wrapper: HTMLElement, marker: HTMLElement) => { - const wrapperRect = wrapper.getBoundingClientRect() - const rect = marker.getBoundingClientRect() - return rect.top - wrapperRect.top + Math.max(0, (rect.height - 20) / 2) - } - - const updateComments = () => { - const el = wrap - const root = getRoot() - if (!el || !root) { - setNote("positions", {}) - setNote("draftTop", undefined) - return - } - - const estimateTop = (range: SelectedLineRange) => { - const line = Math.max(range.start, range.end) - const height = 24 - const offset = 2 - return Math.max(0, (line - 1) * height + offset) - } - - const large = contents().length > 500_000 - - const next: Record = {} - for (const comment of fileComments()) { - const marker = findMarker(root, comment.selection) - if (marker) next[comment.id] = markerTop(el, marker) - else if (large) next[comment.id] = estimateTop(comment.selection) - } - - const removed = Object.keys(note.positions).filter((id) => next[id] === undefined) - const changed = Object.entries(next).filter(([id, top]) => note.positions[id] !== top) - if (removed.length > 0 || changed.length > 0) { - setNote( - "positions", - produce((draft) => { - for (const id of removed) { - delete draft[id] - } - - for (const [id, top] of changed) { - draft[id] = top - } - }), - ) - } - - const range = note.commenting - if (!range) { - setNote("draftTop", undefined) - return - } - - const marker = findMarker(root, range) - if (marker) { - setNote("draftTop", markerTop(el, marker)) - return - } - - setNote("draftTop", large ? estimateTop(range) : undefined) - } - - const scheduleComments = () => { - requestAnimationFrame(updateComments) - } + setTimeout(() => { + if (!document.activeElement || !current.contains(document.activeElement)) { + setNote("commenting", null) + } + }, 0) + }, + }) createEffect(() => { - commentLayout() - scheduleComments() + if (typeof window === "undefined") return + + const onKeyDown = (event: KeyboardEvent) => { + if (tabs().active() !== props.tab) return + if (!(event.metaKey || event.ctrlKey) || event.altKey || event.shiftKey) return + if (event.key.toLowerCase() !== "f") return + + event.preventDefault() + event.stopPropagation() + find?.focus() + } + + window.addEventListener("keydown", onKeyDown, { capture: true }) + onCleanup(() => window.removeEventListener("keydown", onKeyDown, { capture: true })) }) + createEffect( + on( + path, + () => { + commentsUi.note.reset() + }, + { defer: true }, + ), + ) + createEffect(() => { const focus = comments.focus() const p = path() @@ -278,9 +267,7 @@ export function FileTabContent(props: { tab: string }) { const target = fileComments().find((comment) => comment.id === focus.id) if (!target) return - setNote("openedComment", target.id) - setCommenting(null) - file.setSelectedLines(p, target.selection) + commentsUi.note.openComment(target.id, target.selection, { cancelDraft: true }) requestAnimationFrame(() => comments.clearFocus()) }) @@ -362,6 +349,15 @@ export function FileTabContent(props: { tab: string }) { if (el.scrollLeft !== s.x) el.scrollLeft = s.x } + const queueRestore = () => { + if (restoreFrame !== undefined) return + + restoreFrame = requestAnimationFrame(() => { + restoreFrame = undefined + restoreScroll() + }) + } + const handleScroll = (event: Event & { currentTarget: HTMLDivElement }) => { if (codeScroll.length === 0) syncCodeScroll() @@ -371,141 +367,81 @@ export function FileTabContent(props: { tab: string }) { }) } - createEffect( - on( - () => state()?.loaded, - (loaded) => { - if (!loaded) return - requestAnimationFrame(restoreScroll) - }, - { defer: true }, - ), - ) + const cancelCommenting = () => { + const p = path() + if (p) file.setSelectedLines(p, null) + setNote("commenting", null) + } - createEffect( - on( - () => file.ready(), - (ready) => { - if (!ready) return - requestAnimationFrame(restoreScroll) - }, - { defer: true }, - ), - ) + let prev = { + loaded: false, + ready: false, + active: false, + } - createEffect( - on( - () => tabs().active() === props.tab, - (active) => { - if (!active) return - if (!state()?.loaded) return - requestAnimationFrame(restoreScroll) - }, - ), - ) + createEffect(() => { + const loaded = !!state()?.loaded + const ready = file.ready() + const active = tabs().active() === props.tab + const restore = (loaded && !prev.loaded) || (ready && !prev.ready) || (active && loaded && !prev.active) + prev = { loaded, ready, active } + if (!restore) return + queueRestore() + }) onCleanup(() => { for (const item of codeScroll) { item.removeEventListener("scroll", handleCodeScroll) } - if (scrollFrame === undefined) return - cancelAnimationFrame(scrollFrame) + if (scrollFrame !== undefined) cancelAnimationFrame(scrollFrame) + if (restoreFrame !== undefined) cancelAnimationFrame(restoreFrame) }) - const renderCode = (source: string, wrapperClass: string) => ( -
{ - wrap = el - scheduleComments() - }} - class={`relative overflow-hidden ${wrapperClass}`} - > + const renderFile = (source: string) => ( +
{ - requestAnimationFrame(restoreScroll) - requestAnimationFrame(scheduleComments) + queueRestore() }} + annotations={commentsUi.annotations()} + renderAnnotation={commentsUi.renderAnnotation} + renderHoverUtility={commentsUi.renderHoverUtility} onLineSelected={(range: SelectedLineRange | null) => { - const p = path() - if (!p) return - file.setSelectedLines(p, range) - if (!range) setCommenting(null) + commentsUi.onLineSelected(range) }} + onLineNumberSelectionEnd={commentsUi.onLineNumberSelectionEnd} onLineSelectionEnd={(range: SelectedLineRange | null) => { - if (!range) { - setCommenting(null) - return - } - - setNote("openedComment", null) - setCommenting(range) + commentsUi.onLineSelectionEnd(range) }} + search={search} overflow="scroll" class="select-text" + media={{ + mode: "auto", + path: path(), + current: state()?.content, + onLoad: queueRestore, + onError: (args: { kind: "image" | "audio" | "svg" }) => { + if (args.kind !== "svg") return + showToast({ + variant: "error", + title: language.t("toast.file.loadFailed.title"), + }) + }, + }} /> - - {(comment) => ( - { - const p = path() - if (!p) return - file.setSelectedLines(p, comment.selection) - }} - onClick={() => { - const p = path() - if (!p) return - setCommenting(null) - setNote("openedComment", (current) => (current === comment.id ? null : comment.id)) - file.setSelectedLines(p, comment.selection) - }} - /> - )} - - - {(range) => ( - - setNote("draft", value)} - onCancel={() => setCommenting(null)} - onSubmit={(value) => { - const p = path() - if (!p) return - addCommentToContext({ file: p, selection: range(), comment: value, origin: "file" }) - setCommenting(null) - }} - onPopoverFocusOut={(e: FocusEvent) => { - const current = e.currentTarget as HTMLDivElement - const target = e.relatedTarget - if (target instanceof Node && current.contains(target)) return - - setTimeout(() => { - if (!document.activeElement || !current.contains(document.activeElement)) { - setCommenting(null) - } - }, 0) - }} - /> - - )} -
) @@ -520,36 +456,7 @@ export function FileTabContent(props: { tab: string }) { onScroll={handleScroll as any} > - -
- {path()} requestAnimationFrame(restoreScroll)} - /> -
-
- -
- {renderCode(svgContent() ?? "", "")} - -
- {path()} -
-
-
-
- -
- -
-
{path()?.split("/").pop()}
-
{language.t("session.files.binaryContent")}
-
-
-
- {renderCode(contents(), "pb-40")} + {renderFile(contents())}
{language.t("common.loading")}...
diff --git a/packages/app/src/pages/session/helpers.test.ts b/packages/app/src/pages/session/helpers.test.ts index 7d357e6572..9c77c34af4 100644 --- a/packages/app/src/pages/session/helpers.test.ts +++ b/packages/app/src/pages/session/helpers.test.ts @@ -11,12 +11,13 @@ describe("createOpenReviewFile", () => { return `file://${path}` }, openTab: (tab) => calls.push(`open:${tab}`), + setActive: (tab) => calls.push(`active:${tab}`), loadFile: (path) => calls.push(`load:${path}`), }) openReviewFile("src/a.ts") - expect(calls).toEqual(["show", "tab:src/a.ts", "open:file://src/a.ts", "load:src/a.ts"]) + expect(calls).toEqual(["show", "load:src/a.ts", "tab:src/a.ts", "open:file://src/a.ts", "active:file://src/a.ts"]) }) }) diff --git a/packages/app/src/pages/session/helpers.ts b/packages/app/src/pages/session/helpers.ts index 995f6eb191..be9656900d 100644 --- a/packages/app/src/pages/session/helpers.ts +++ b/packages/app/src/pages/session/helpers.ts @@ -1,4 +1,5 @@ -import { batch } from "solid-js" +import { batch, createEffect, on, onCleanup, onMount, type Accessor } from "solid-js" +import { createStore } from "solid-js/store" export const focusTerminalById = (id: string) => { const wrapper = document.getElementById(`terminal-wrapper-${id}`) @@ -24,13 +25,20 @@ export const createOpenReviewFile = (input: { showAllFiles: () => void tabForPath: (path: string) => string openTab: (tab: string) => void - loadFile: (path: string) => void + setActive: (tab: string) => void + loadFile: (path: string) => any | Promise }) => { return (path: string) => { batch(() => { input.showAllFiles() - input.openTab(input.tabForPath(path)) - input.loadFile(path) + const maybePromise = input.loadFile(path) + const open = () => { + const tab = input.tabForPath(path) + input.openTab(tab) + input.setActive(tab) + } + if (maybePromise instanceof Promise) maybePromise.then(open) + else open() }) } } @@ -62,3 +70,104 @@ export const getTabReorderIndex = (tabs: readonly string[], from: string, to: st if (fromIndex === -1 || toIndex === -1 || fromIndex === toIndex) return undefined return toIndex } + +export const createSizing = () => { + const [state, setState] = createStore({ active: false }) + let t: number | undefined + + const stop = () => { + if (t !== undefined) { + clearTimeout(t) + t = undefined + } + setState("active", false) + } + + const start = () => { + if (t !== undefined) { + clearTimeout(t) + t = undefined + } + setState("active", true) + } + + onMount(() => { + window.addEventListener("pointerup", stop) + window.addEventListener("pointercancel", stop) + window.addEventListener("blur", stop) + onCleanup(() => { + window.removeEventListener("pointerup", stop) + window.removeEventListener("pointercancel", stop) + window.removeEventListener("blur", stop) + }) + }) + + onCleanup(() => { + if (t !== undefined) clearTimeout(t) + }) + + return { + active: () => state.active, + start, + touch() { + start() + t = window.setTimeout(stop, 120) + }, + } +} + +export type Sizing = ReturnType + +export const createPresence = (open: Accessor, wait = 200) => { + const [state, setState] = createStore({ + show: open(), + open: open(), + }) + let frame: number | undefined + let t: number | undefined + + const clear = () => { + if (frame !== undefined) { + cancelAnimationFrame(frame) + frame = undefined + } + if (t !== undefined) { + clearTimeout(t) + t = undefined + } + } + + createEffect( + on(open, (next) => { + clear() + + if (next) { + if (state.show) { + setState("open", true) + return + } + + setState({ show: true, open: false }) + frame = requestAnimationFrame(() => { + frame = undefined + setState("open", true) + }) + return + } + + if (!state.show) return + setState("open", false) + t = window.setTimeout(() => { + t = undefined + setState("show", false) + }, wait) + }), + ) + + onCleanup(clear) + + return { + show: () => state.show, + open: () => state.open, + } +} diff --git a/packages/app/src/pages/session/message-id-from-hash.ts b/packages/app/src/pages/session/message-id-from-hash.ts new file mode 100644 index 0000000000..2857f4b01d --- /dev/null +++ b/packages/app/src/pages/session/message-id-from-hash.ts @@ -0,0 +1,6 @@ +export const messageIdFromHash = (hash: string) => { + const value = hash.startsWith("#") ? hash.slice(1) : hash + const match = value.match(/^message-(.+)$/) + if (!match) return + return match[1] +} diff --git a/packages/app/src/pages/session/message-timeline.tsx b/packages/app/src/pages/session/message-timeline.tsx index b13ccb474a..6463e7cbbe 100644 --- a/packages/app/src/pages/session/message-timeline.tsx +++ b/packages/app/src/pages/session/message-timeline.tsx @@ -1,16 +1,20 @@ -import { For, createEffect, createMemo, on, onCleanup, Show, type JSX } from "solid-js" +import { For, createEffect, createMemo, on, onCleanup, Show, Index, type JSX } from "solid-js" import { createStore, produce } from "solid-js/store" import { useNavigate, useParams } from "@solidjs/router" import { Button } from "@opencode-ai/ui/button" +import { FileIcon } from "@opencode-ai/ui/file-icon" import { Icon } from "@opencode-ai/ui/icon" import { IconButton } from "@opencode-ai/ui/icon-button" import { DropdownMenu } from "@opencode-ai/ui/dropdown-menu" import { Dialog } from "@opencode-ai/ui/dialog" import { InlineInput } from "@opencode-ai/ui/inline-input" +import { Spinner } from "@opencode-ai/ui/spinner" import { SessionTurn } from "@opencode-ai/ui/session-turn" import { ScrollView } from "@opencode-ai/ui/scroll-view" -import type { UserMessage } from "@opencode-ai/sdk/v2" +import type { AssistantMessage, Message as MessageType, Part, TextPart, UserMessage } from "@opencode-ai/sdk/v2" import { showToast } from "@opencode-ai/ui/toast" +import { Binary } from "@opencode-ai/util/binary" +import { getFilename } from "@opencode-ai/util/path" import { shouldMarkBoundaryGesture, normalizeWheelDelta } from "@/pages/session/message-gesture" import { SessionContextUsage } from "@/components/session-context-usage" import { useDialog } from "@opencode-ai/ui/context/dialog" @@ -18,6 +22,38 @@ import { useLanguage } from "@/context/language" import { useSettings } from "@/context/settings" import { useSDK } from "@/context/sdk" import { useSync } from "@/context/sync" +import { parseCommentNote, readCommentMetadata } from "@/utils/comment-note" + +type MessageComment = { + path: string + comment: string + selection?: { + startLine: number + endLine: number + } +} + +const emptyMessages: MessageType[] = [] +const idle = { type: "idle" as const } + +const messageComments = (parts: Part[]): MessageComment[] => + parts.flatMap((part) => { + if (part.type !== "text" || !(part as TextPart).synthetic) return [] + const next = readCommentMetadata(part.metadata) ?? parseCommentNote(part.text) + if (!next) return [] + return [ + { + path: next.path, + comment: next.comment, + selection: next.selection + ? { + startLine: next.selection.startLine, + endLine: next.selection.endLine, + } + : undefined, + }, + ] + }) const boundaryTarget = (root: HTMLElement, target: EventTarget | null) => { const current = target instanceof Element ? target : undefined @@ -50,6 +86,103 @@ const markBoundaryGesture = (input: { } } +type StageConfig = { + init: number + batch: number +} + +type TimelineStageInput = { + sessionKey: () => string + turnStart: () => number + messages: () => UserMessage[] + config: StageConfig +} + +/** + * Defer-mounts small timeline windows so revealing older turns does not + * block first paint with a large DOM mount. + * + * Once staging completes for a session it never re-stages — backfill and + * new messages render immediately. + */ +function createTimelineStaging(input: TimelineStageInput) { + const [state, setState] = createStore({ + activeSession: "", + completedSession: "", + count: 0, + }) + + const stagedCount = createMemo(() => { + const total = input.messages().length + if (input.turnStart() <= 0) return total + if (state.completedSession === input.sessionKey()) return total + const init = Math.min(total, input.config.init) + if (state.count <= init) return init + if (state.count >= total) return total + return state.count + }) + + const stagedUserMessages = createMemo(() => { + const list = input.messages() + const count = stagedCount() + if (count >= list.length) return list + return list.slice(Math.max(0, list.length - count)) + }) + + let frame: number | undefined + const cancel = () => { + if (frame === undefined) return + cancelAnimationFrame(frame) + frame = undefined + } + + createEffect( + on( + () => [input.sessionKey(), input.turnStart() > 0, input.messages().length] as const, + ([sessionKey, isWindowed, total]) => { + cancel() + const shouldStage = + isWindowed && + total > input.config.init && + state.completedSession !== sessionKey && + state.activeSession !== sessionKey + if (!shouldStage) { + setState({ activeSession: "", count: total }) + return + } + + let count = Math.min(total, input.config.init) + setState({ activeSession: sessionKey, count }) + + const step = () => { + if (input.sessionKey() !== sessionKey) { + frame = undefined + return + } + const currentTotal = input.messages().length + count = Math.min(currentTotal, count + input.config.batch) + setState("count", count) + if (count >= currentTotal) { + setState({ completedSession: sessionKey, activeSession: "" }) + frame = undefined + return + } + frame = requestAnimationFrame(step) + } + frame = requestAnimationFrame(step) + }, + ), + ) + + const isStaging = createMemo(() => { + const key = input.sessionKey() + return state.activeSession === key && state.completedSession !== key + }) + + onCleanup(cancel) + return { messages: stagedUserMessages, isStaging } +} + export function MessageTimeline(props: { mobileChanges: boolean mobileFallback: JSX.Element @@ -60,21 +193,17 @@ export function MessageTimeline(props: { onAutoScrollHandleScroll: () => void onMarkScrollGesture: (target?: EventTarget | null) => void hasScrollGesture: () => boolean - isDesktop: boolean - onScrollSpyScroll: () => void + onUserScroll: () => void + onTurnBackfillScroll: () => void onAutoScrollInteraction: (event: MouseEvent) => void centered: boolean setContentRef: (el: HTMLDivElement) => void turnStart: number - onRenderEarlier: () => void historyMore: boolean historyLoading: boolean onLoadEarlier: () => void renderedUserMessages: UserMessage[] anchor: (id: string) => string - onRegisterMessage: (el: HTMLDivElement, id: string) => void - onUnregisterMessage: (id: string) => void - lastUserMessageID?: string }) { let touchGesture: number | undefined @@ -86,8 +215,77 @@ export function MessageTimeline(props: { const dialog = useDialog() const language = useLanguage() + const rendered = createMemo(() => props.renderedUserMessages.map((message) => message.id)) const sessionKey = createMemo(() => `${params.dir}${params.id ? "/" + params.id : ""}`) const sessionID = createMemo(() => params.id) + const sessionMessages = createMemo(() => { + const id = sessionID() + if (!id) return emptyMessages + return sync.data.message[id] ?? emptyMessages + }) + const pending = createMemo(() => + sessionMessages().findLast( + (item): item is AssistantMessage => item.role === "assistant" && typeof item.time.completed !== "number", + ), + ) + const sessionStatus = createMemo(() => { + const id = sessionID() + if (!id) return idle + return sync.data.session_status[id] ?? idle + }) + const working = createMemo(() => !!pending() || sessionStatus().type !== "idle") + + const [slot, setSlot] = createStore({ + open: false, + show: false, + fade: false, + }) + + let f: number | undefined + const clear = () => { + if (f !== undefined) window.clearTimeout(f) + f = undefined + } + + onCleanup(clear) + createEffect( + on( + working, + (on, prev) => { + clear() + if (on) { + setSlot({ open: true, show: true, fade: false }) + return + } + if (prev) { + setSlot({ open: false, show: true, fade: true }) + f = window.setTimeout(() => setSlot({ show: false, fade: false }), 260) + return + } + setSlot({ open: false, show: false, fade: false }) + }, + { defer: true }, + ), + ) + const activeMessageID = createMemo(() => { + const parentID = pending()?.parentID + if (parentID) { + const messages = sessionMessages() + const result = Binary.search(messages, parentID, (message) => message.id) + const message = result.found ? messages[result.index] : messages.find((item) => item.id === parentID) + if (message && message.role === "user") return message.id + } + + const status = sessionStatus() + if (status.type !== "idle") { + const messages = sessionMessages() + for (let i = messages.length - 1; i >= 0; i--) { + if (messages[i].role === "user") return messages[i].id + } + } + + return undefined + }) const info = createMemo(() => { const id = sessionID() if (!id) return @@ -96,6 +294,13 @@ export function MessageTimeline(props: { const titleValue = createMemo(() => info()?.title) const parentID = createMemo(() => info()?.parentID) const showHeader = createMemo(() => !!(titleValue() || parentID())) + const stageCfg = { init: 1, batch: 3 } + const staging = createTimelineStaging({ + sessionKey, + turnStart: () => props.turnStart, + messages: () => props.renderedUserMessages, + config: stageCfg, + }) const [title, setTitle] = createStore({ draft: "", @@ -312,8 +517,10 @@ export function MessageTimeline(props: {
-
- - -
- -
-
- - {(message) => ( -
{ - props.onRegisterMessage(el, message.id) - onCleanup(() => props.onUnregisterMessage(message.id)) - }} - classList={{ - "min-w-0 w-full max-w-full": true, - "md:max-w-200 2xl:max-w-[1000px]": props.centered, - }} - > - + { + setTitle("pendingRename", true) + setTitle("menuOpen", false) + }} + > + {language.t("common.rename")} + + void archiveSession(id())}> + {language.t("common.archive")} + + + dialog.show(() => )} + > + {language.t("common.delete")} + + + + +
+ )} +
- )} - +
+ + +
+ 0 || props.historyMore}> +
+ +
+
+ + {(messageID) => { + const active = createMemo(() => activeMessageID() === messageID) + const queued = createMemo(() => { + if (active()) return false + const activeID = activeMessageID() + if (activeID) return messageID > activeID + return false + }) + const comments = createMemo(() => messageComments(sync.data.part[messageID] ?? []), [], { + equals: (a, b) => JSON.stringify(a) === JSON.stringify(b), + }) + const commentCount = createMemo(() => comments().length) + return ( +
+ 0}> +
+
+
+ + {(commentAccessor: () => MessageComment) => { + const comment = createMemo(() => commentAccessor()) + return ( +
+
+ + {getFilename(comment().path)} + + {(selection) => ( + + {selection().startLine === selection().endLine + ? `:${selection().startLine}` + : `:${selection().startLine}-${selection().endLine}`} + + )} + +
+
+ {comment().comment} +
+
+ ) + }} +
+
+
+
+
+ +
+ ) + }} +
+
diff --git a/packages/app/src/pages/session/review-tab.tsx b/packages/app/src/pages/session/review-tab.tsx index 9349e99376..142ee7ad92 100644 --- a/packages/app/src/pages/session/review-tab.tsx +++ b/packages/app/src/pages/session/review-tab.tsx @@ -1,7 +1,11 @@ -import { createEffect, on, onCleanup, type JSX } from "solid-js" -import { createStore } from "solid-js/store" +import { createEffect, onCleanup, type JSX } from "solid-js" import type { FileDiff } from "@opencode-ai/sdk/v2" import { SessionReview } from "@opencode-ai/ui/session-review" +import type { + SessionReviewCommentActions, + SessionReviewCommentDelete, + SessionReviewCommentUpdate, +} from "@opencode-ai/ui/session-review" import type { SelectedLineRange } from "@/context/file" import { useSDK } from "@/context/sdk" import { useLayout } from "@/context/layout" @@ -18,6 +22,9 @@ export interface SessionReviewTabProps { onDiffStyleChange?: (style: DiffStyle) => void onViewFile?: (file: string) => void onLineComment?: (comment: { file: string; selection: SelectedLineRange; comment: string; preview?: string }) => void + onLineCommentUpdate?: (comment: SessionReviewCommentUpdate) => void + onLineCommentDelete?: (comment: SessionReviewCommentDelete) => void + lineCommentActions?: SessionReviewCommentActions comments?: LineComment[] focusedComment?: { file: string; id: string } | null onFocusedCommentChange?: (focus: { file: string; id: string } | null) => void @@ -31,38 +38,8 @@ export interface SessionReviewTabProps { } export function StickyAddButton(props: { children: JSX.Element }) { - const [state, setState] = createStore({ stuck: false }) - let button: HTMLDivElement | undefined - - createEffect(() => { - const node = button - if (!node) return - - const scroll = node.parentElement - if (!scroll) return - - const handler = () => { - const rect = node.getBoundingClientRect() - const scrollRect = scroll.getBoundingClientRect() - setState("stuck", rect.right >= scrollRect.right && scroll.scrollWidth > scroll.clientWidth) - } - - scroll.addEventListener("scroll", handler, { passive: true }) - const observer = new ResizeObserver(handler) - observer.observe(scroll) - handler() - onCleanup(() => { - scroll.removeEventListener("scroll", handler) - observer.disconnect() - }) - }) - return ( -
+
{props.children}
) @@ -70,10 +47,12 @@ export function StickyAddButton(props: { children: JSX.Element }) { export function SessionReviewTab(props: SessionReviewTabProps) { let scroll: HTMLDivElement | undefined - let frame: number | undefined - let pending: { x: number; y: number } | undefined + let restoreFrame: number | undefined + let userInteracted = false + let restored: { x: number; y: number } | undefined const sdk = useSDK() + const layout = useLayout() const readFile = async (path: string) => { return sdk.client.file @@ -85,48 +64,77 @@ export function SessionReviewTab(props: SessionReviewTabProps) { }) } - const restoreScroll = () => { + const handleInteraction = () => { + userInteracted = true + + if (restoreFrame !== undefined) { + cancelAnimationFrame(restoreFrame) + restoreFrame = undefined + } + } + + const doRestore = () => { + restoreFrame = undefined const el = scroll - if (!el) return + if (!el || !layout.ready() || userInteracted) return + if (el.clientHeight === 0 || el.clientWidth === 0) return const s = props.view().scroll("review") - if (!s) return + if (!s || (s.x === 0 && s.y === 0)) return - if (el.scrollTop !== s.y) el.scrollTop = s.y - if (el.scrollLeft !== s.x) el.scrollLeft = s.x + const maxY = Math.max(0, el.scrollHeight - el.clientHeight) + const maxX = Math.max(0, el.scrollWidth - el.clientWidth) + + const targetY = Math.min(s.y, maxY) + const targetX = Math.min(s.x, maxX) + + if (el.scrollTop === targetY && el.scrollLeft === targetX) return + + if (el.scrollTop !== targetY) el.scrollTop = targetY + if (el.scrollLeft !== targetX) el.scrollLeft = targetX + restored = { x: el.scrollLeft, y: el.scrollTop } + } + + const queueRestore = () => { + if (userInteracted || restoreFrame !== undefined) return + restoreFrame = requestAnimationFrame(doRestore) } const handleScroll = (event: Event & { currentTarget: HTMLDivElement }) => { - pending = { - x: event.currentTarget.scrollLeft, - y: event.currentTarget.scrollTop, + const el = event.currentTarget + const prev = restored + if (prev && el.scrollTop === prev.y && el.scrollLeft === prev.x) { + restored = undefined + return } - if (frame !== undefined) return - frame = requestAnimationFrame(() => { - frame = undefined + restored = undefined + handleInteraction() + if (!layout.ready()) return + if (el.clientHeight === 0 || el.clientWidth === 0) return - const next = pending - pending = undefined - if (!next) return - - props.view().setScroll("review", next) + props.view().setScroll("review", { + x: el.scrollLeft, + y: el.scrollTop, }) } - createEffect( - on( - () => props.diffs().length, - () => { - requestAnimationFrame(restoreScroll) - }, - { defer: true }, - ), - ) + createEffect(() => { + props.diffs().length + props.diffStyle + if (!layout.ready()) return + queueRestore() + }) onCleanup(() => { - if (frame === undefined) return - cancelAnimationFrame(frame) + if (restoreFrame !== undefined) cancelAnimationFrame(restoreFrame) + if (scroll) { + scroll.removeEventListener("wheel", handleInteraction, { capture: true }) + scroll.removeEventListener("mousewheel", handleInteraction, { capture: true }) + scroll.removeEventListener("pointerdown", handleInteraction, { capture: true }) + scroll.removeEventListener("touchstart", handleInteraction, { capture: true }) + scroll.removeEventListener("keydown", handleInteraction, { capture: true }) + } }) return ( @@ -135,15 +143,20 @@ export function SessionReviewTab(props: SessionReviewTabProps) { empty={props.empty} scrollRef={(el) => { scroll = el + el.addEventListener("wheel", handleInteraction, { passive: true, capture: true }) + el.addEventListener("mousewheel", handleInteraction, { passive: true, capture: true }) + el.addEventListener("pointerdown", handleInteraction, { passive: true, capture: true }) + el.addEventListener("touchstart", handleInteraction, { passive: true, capture: true }) + el.addEventListener("keydown", handleInteraction, { passive: true, capture: true }) props.onScrollRef?.(el) - restoreScroll() + queueRestore() }} onScroll={handleScroll} - onDiffRendered={() => requestAnimationFrame(restoreScroll)} + onDiffRendered={queueRestore} open={props.view().review.open()} onOpenChange={props.view().review.setOpen} classes={{ - root: props.classes?.root ?? "pb-6 pr-3", + root: props.classes?.root ?? "pr-3", header: props.classes?.header ?? "px-3", container: props.classes?.container ?? "pl-3", }} @@ -154,6 +167,9 @@ export function SessionReviewTab(props: SessionReviewTabProps) { focusedFile={props.focusedFile} readFile={readFile} onLineComment={props.onLineComment} + onLineCommentUpdate={props.onLineCommentUpdate} + onLineCommentDelete={props.onLineCommentDelete} + lineCommentActions={props.lineCommentActions} comments={props.comments} focusedComment={props.focusedComment} onFocusedCommentChange={props.onFocusedCommentChange} diff --git a/packages/app/src/pages/session/scroll-spy.test.ts b/packages/app/src/pages/session/scroll-spy.test.ts deleted file mode 100644 index f3e6775cb4..0000000000 --- a/packages/app/src/pages/session/scroll-spy.test.ts +++ /dev/null @@ -1,127 +0,0 @@ -import { describe, expect, test } from "bun:test" -import { createScrollSpy, pickOffsetId, pickVisibleId } from "./scroll-spy" - -const rect = (top: number, height = 80): DOMRect => - ({ - x: 0, - y: top, - top, - left: 0, - right: 800, - bottom: top + height, - width: 800, - height, - toJSON: () => ({}), - }) as DOMRect - -const setRect = (el: Element, top: number, height = 80) => { - Object.defineProperty(el, "getBoundingClientRect", { - configurable: true, - value: () => rect(top, height), - }) -} - -describe("pickVisibleId", () => { - test("prefers higher intersection ratio", () => { - const id = pickVisibleId( - [ - { id: "a", ratio: 0.2, top: 100 }, - { id: "b", ratio: 0.8, top: 300 }, - ], - 120, - ) - - expect(id).toBe("b") - }) - - test("breaks ratio ties by nearest line", () => { - const id = pickVisibleId( - [ - { id: "a", ratio: 0.5, top: 90 }, - { id: "b", ratio: 0.5, top: 140 }, - ], - 130, - ) - - expect(id).toBe("b") - }) -}) - -describe("pickOffsetId", () => { - test("uses binary search cutoff", () => { - const id = pickOffsetId( - [ - { id: "a", top: 0 }, - { id: "b", top: 200 }, - { id: "c", top: 400 }, - ], - 350, - ) - - expect(id).toBe("b") - }) -}) - -describe("createScrollSpy fallback", () => { - test("tracks active id from offsets and dirty refresh", () => { - const active: string[] = [] - const root = document.createElement("div") as HTMLDivElement - const one = document.createElement("div") - const two = document.createElement("div") - const three = document.createElement("div") - - root.append(one, two, three) - document.body.append(root) - - Object.defineProperty(root, "scrollTop", { configurable: true, writable: true, value: 250 }) - setRect(root, 0, 800) - setRect(one, -250) - setRect(two, -50) - setRect(three, 150) - - const queue: FrameRequestCallback[] = [] - const flush = () => { - const run = [...queue] - queue.length = 0 - for (const cb of run) cb(0) - } - - const spy = createScrollSpy({ - onActive: (id) => active.push(id), - raf: (cb) => (queue.push(cb), queue.length), - caf: () => {}, - IntersectionObserver: undefined, - ResizeObserver: undefined, - MutationObserver: undefined, - }) - - spy.setContainer(root) - spy.register(one, "a") - spy.register(two, "b") - spy.register(three, "c") - spy.onScroll() - flush() - - expect(spy.getActiveId()).toBe("b") - expect(active.at(-1)).toBe("b") - - root.scrollTop = 450 - setRect(one, -450) - setRect(two, -250) - setRect(three, -50) - spy.onScroll() - flush() - expect(spy.getActiveId()).toBe("c") - - root.scrollTop = 250 - setRect(one, -250) - setRect(two, 250) - setRect(three, 150) - spy.markDirty() - spy.onScroll() - flush() - expect(spy.getActiveId()).toBe("a") - - spy.destroy() - }) -}) diff --git a/packages/app/src/pages/session/scroll-spy.ts b/packages/app/src/pages/session/scroll-spy.ts deleted file mode 100644 index 6ef4c844c4..0000000000 --- a/packages/app/src/pages/session/scroll-spy.ts +++ /dev/null @@ -1,275 +0,0 @@ -type Visible = { - id: string - ratio: number - top: number -} - -type Offset = { - id: string - top: number -} - -type Input = { - onActive: (id: string) => void - raf?: (cb: FrameRequestCallback) => number - caf?: (id: number) => void - IntersectionObserver?: typeof globalThis.IntersectionObserver - ResizeObserver?: typeof globalThis.ResizeObserver - MutationObserver?: typeof globalThis.MutationObserver -} - -export const pickVisibleId = (list: Visible[], line: number) => { - if (list.length === 0) return - - const sorted = [...list].sort((a, b) => { - if (b.ratio !== a.ratio) return b.ratio - a.ratio - - const da = Math.abs(a.top - line) - const db = Math.abs(b.top - line) - if (da !== db) return da - db - - return a.top - b.top - }) - - return sorted[0]?.id -} - -export const pickOffsetId = (list: Offset[], cutoff: number) => { - if (list.length === 0) return - - let lo = 0 - let hi = list.length - 1 - let out = 0 - - while (lo <= hi) { - const mid = (lo + hi) >> 1 - const top = list[mid]?.top - if (top === undefined) break - - if (top <= cutoff) { - out = mid - lo = mid + 1 - continue - } - - hi = mid - 1 - } - - return list[out]?.id -} - -export const createScrollSpy = (input: Input) => { - const raf = input.raf ?? requestAnimationFrame - const caf = input.caf ?? cancelAnimationFrame - const CtorIO = input.IntersectionObserver ?? globalThis.IntersectionObserver - const CtorRO = input.ResizeObserver ?? globalThis.ResizeObserver - const CtorMO = input.MutationObserver ?? globalThis.MutationObserver - - let root: HTMLDivElement | undefined - let io: IntersectionObserver | undefined - let ro: ResizeObserver | undefined - let mo: MutationObserver | undefined - let frame: number | undefined - let active: string | undefined - let dirty = true - - const node = new Map() - const id = new WeakMap() - const visible = new Map() - let offset: Offset[] = [] - - const schedule = () => { - if (frame !== undefined) return - frame = raf(() => { - frame = undefined - update() - }) - } - - const refreshOffset = () => { - const el = root - if (!el) { - offset = [] - dirty = false - return - } - - const base = el.getBoundingClientRect().top - offset = [...node].map(([next, item]) => ({ - id: next, - top: item.getBoundingClientRect().top - base + el.scrollTop, - })) - offset.sort((a, b) => a.top - b.top) - dirty = false - } - - const update = () => { - const el = root - if (!el) return - - const line = el.getBoundingClientRect().top + 100 - const next = - pickVisibleId( - [...visible].map(([k, v]) => ({ - id: k, - ratio: v.ratio, - top: v.top, - })), - line, - ) ?? - (() => { - if (dirty) refreshOffset() - return pickOffsetId(offset, el.scrollTop + 100) - })() - - if (!next || next === active) return - active = next - input.onActive(next) - } - - const observe = () => { - const el = root - if (!el) return - - io?.disconnect() - io = undefined - if (CtorIO) { - try { - io = new CtorIO( - (entries) => { - for (const entry of entries) { - const item = entry.target - if (!(item instanceof HTMLElement)) continue - const key = id.get(item) - if (!key) continue - - if (!entry.isIntersecting || entry.intersectionRatio <= 0) { - visible.delete(key) - continue - } - - visible.set(key, { - ratio: entry.intersectionRatio, - top: entry.boundingClientRect.top, - }) - } - - schedule() - }, - { - root: el, - threshold: [0, 0.25, 0.5, 0.75, 1], - }, - ) - } catch { - io = undefined - } - } - - if (io) { - for (const item of node.values()) io.observe(item) - } - - ro?.disconnect() - ro = undefined - if (CtorRO) { - ro = new CtorRO(() => { - dirty = true - schedule() - }) - ro.observe(el) - for (const item of node.values()) ro.observe(item) - } - - mo?.disconnect() - mo = undefined - if (CtorMO) { - mo = new CtorMO(() => { - dirty = true - schedule() - }) - mo.observe(el, { subtree: true, childList: true, characterData: true }) - } - - dirty = true - schedule() - } - - const setContainer = (el?: HTMLDivElement) => { - if (root === el) return - - root = el - visible.clear() - active = undefined - observe() - } - - const register = (el: HTMLElement, key: string) => { - const prev = node.get(key) - if (prev && prev !== el) { - io?.unobserve(prev) - ro?.unobserve(prev) - } - - node.set(key, el) - id.set(el, key) - if (io) io.observe(el) - if (ro) ro.observe(el) - dirty = true - schedule() - } - - const unregister = (key: string) => { - const item = node.get(key) - if (!item) return - - io?.unobserve(item) - ro?.unobserve(item) - node.delete(key) - visible.delete(key) - dirty = true - schedule() - } - - const markDirty = () => { - dirty = true - schedule() - } - - const clear = () => { - for (const item of node.values()) { - io?.unobserve(item) - ro?.unobserve(item) - } - - node.clear() - visible.clear() - offset = [] - active = undefined - dirty = true - } - - const destroy = () => { - if (frame !== undefined) caf(frame) - frame = undefined - clear() - io?.disconnect() - ro?.disconnect() - mo?.disconnect() - io = undefined - ro = undefined - mo = undefined - root = undefined - } - - return { - setContainer, - register, - unregister, - onScroll: schedule, - markDirty, - clear, - destroy, - getActiveId: () => active, - } -} diff --git a/packages/app/src/pages/session/session-model-helpers.test.ts b/packages/app/src/pages/session/session-model-helpers.test.ts new file mode 100644 index 0000000000..5f554dcd36 --- /dev/null +++ b/packages/app/src/pages/session/session-model-helpers.test.ts @@ -0,0 +1,158 @@ +import { describe, expect, test } from "bun:test" +import type { UserMessage } from "@opencode-ai/sdk/v2" +import { resetSessionModel, syncSessionModel } from "./session-model-helpers" + +const message = (input?: Partial>) => + ({ + id: "msg", + sessionID: "session", + role: "user", + time: { created: 1 }, + agent: input?.agent ?? "build", + model: input?.model ?? { providerID: "anthropic", modelID: "claude-sonnet-4" }, + variant: input?.variant, + }) as UserMessage + +describe("syncSessionModel", () => { + test("restores the last message model and variant", () => { + const calls: unknown[] = [] + + syncSessionModel( + { + agent: { + current() { + return undefined + }, + set(value) { + calls.push(["agent", value]) + }, + }, + model: { + set(value) { + calls.push(["model", value]) + }, + current() { + return { id: "claude-sonnet-4", provider: { id: "anthropic" } } + }, + variant: { + set(value) { + calls.push(["variant", value]) + }, + }, + }, + }, + message({ variant: "high" }), + ) + + expect(calls).toEqual([ + ["agent", "build"], + ["model", { providerID: "anthropic", modelID: "claude-sonnet-4" }], + ["variant", "high"], + ]) + }) + + test("skips variant when the model falls back", () => { + const calls: unknown[] = [] + + syncSessionModel( + { + agent: { + current() { + return undefined + }, + set(value) { + calls.push(["agent", value]) + }, + }, + model: { + set(value) { + calls.push(["model", value]) + }, + current() { + return { id: "gpt-5", provider: { id: "openai" } } + }, + variant: { + set(value) { + calls.push(["variant", value]) + }, + }, + }, + }, + message({ variant: "high" }), + ) + + expect(calls).toEqual([ + ["agent", "build"], + ["model", { providerID: "anthropic", modelID: "claude-sonnet-4" }], + ]) + }) +}) + +describe("resetSessionModel", () => { + test("restores the current agent defaults", () => { + const calls: unknown[] = [] + + resetSessionModel({ + agent: { + current() { + return { + model: { providerID: "anthropic", modelID: "claude-sonnet-4" }, + variant: "high", + } + }, + set() {}, + }, + model: { + set(value) { + calls.push(["model", value]) + }, + current() { + return undefined + }, + variant: { + set(value) { + calls.push(["variant", value]) + }, + }, + }, + }) + + expect(calls).toEqual([ + ["model", { providerID: "anthropic", modelID: "claude-sonnet-4" }], + ["variant", "high"], + ]) + }) + + test("clears the variant when the agent has none", () => { + const calls: unknown[] = [] + + resetSessionModel({ + agent: { + current() { + return { + model: { providerID: "anthropic", modelID: "claude-sonnet-4" }, + } + }, + set() {}, + }, + model: { + set(value) { + calls.push(["model", value]) + }, + current() { + return undefined + }, + variant: { + set(value) { + calls.push(["variant", value]) + }, + }, + }, + }) + + expect(calls).toEqual([ + ["model", { providerID: "anthropic", modelID: "claude-sonnet-4" }], + ["variant", undefined], + ]) + }) +}) diff --git a/packages/app/src/pages/session/session-model-helpers.ts b/packages/app/src/pages/session/session-model-helpers.ts new file mode 100644 index 0000000000..7600f16d5c --- /dev/null +++ b/packages/app/src/pages/session/session-model-helpers.ts @@ -0,0 +1,48 @@ +import type { UserMessage } from "@opencode-ai/sdk/v2" +import { batch } from "solid-js" + +type Local = { + agent: { + current(): + | { + model?: UserMessage["model"] + variant?: string + } + | undefined + set(name: string | undefined): void + } + model: { + set(model: UserMessage["model"] | undefined): void + current(): + | { + id: string + provider: { id: string } + } + | undefined + variant: { + set(value: string | undefined): void + } + } +} + +export const resetSessionModel = (local: Local) => { + const agent = local.agent.current() + if (!agent) return + batch(() => { + local.model.set(agent.model) + local.model.variant.set(agent.variant) + }) +} + +export const syncSessionModel = (local: Local, msg: UserMessage) => { + batch(() => { + local.agent.set(msg.agent) + local.model.set(msg.model) + }) + + const model = local.model.current() + if (!model) return + if (model.provider.id !== msg.model.providerID) return + if (model.id !== msg.model.modelID) return + local.model.variant.set(msg.variant) +} diff --git a/packages/app/src/pages/session/session-side-panel.tsx b/packages/app/src/pages/session/session-side-panel.tsx index 07b18f3146..590f5b6d9b 100644 --- a/packages/app/src/pages/session/session-side-panel.tsx +++ b/packages/app/src/pages/session/session-side-panel.tsx @@ -4,7 +4,7 @@ import { createMediaQuery } from "@solid-primitives/media" import { useParams } from "@solidjs/router" import { Tabs } from "@opencode-ai/ui/tabs" import { IconButton } from "@opencode-ai/ui/icon-button" -import { Tooltip, TooltipKeybind } from "@opencode-ai/ui/tooltip" +import { TooltipKeybind } from "@opencode-ai/ui/tooltip" import { ResizeHandle } from "@opencode-ai/ui/resize-handle" import { Mark } from "@opencode-ai/ui/logo" import { DragDropProvider, DragDropSensors, DragOverlay, SortableProvider, closestCenter } from "@thisbeyond/solid-dnd" @@ -23,7 +23,7 @@ import { useLayout } from "@/context/layout" import { useSync } from "@/context/sync" import { createFileTabListSync } from "@/pages/session/file-tab-scroll" import { FileTabContent } from "@/pages/session/file-tabs" -import { createOpenSessionFileTab, getTabReorderIndex } from "@/pages/session/helpers" +import { createOpenSessionFileTab, getTabReorderIndex, type Sizing } from "@/pages/session/helpers" import { StickyAddButton } from "@/pages/session/review-tab" import { setSessionHandoff } from "@/pages/session/handoff" @@ -31,6 +31,8 @@ export function SessionSidePanel(props: { reviewPanel: () => JSX.Element activeDiff?: string focusReviewDiff: (path: string) => void + reviewSnap: boolean + size: Sizing }) { const params = useParams() const layout = useLayout() @@ -46,8 +48,15 @@ export function SessionSidePanel(props: { const view = createMemo(() => layout.view(sessionKey)) const reviewOpen = createMemo(() => isDesktop() && view().reviewPanel.opened()) - const open = createMemo(() => isDesktop() && (view().reviewPanel.opened() || layout.fileTree.opened())) - const reviewTab = createMemo(() => isDesktop() && !layout.fileTree.opened()) + const fileOpen = createMemo(() => isDesktop() && layout.fileTree.opened()) + const open = createMemo(() => reviewOpen() || fileOpen()) + const reviewTab = createMemo(() => isDesktop()) + const panelWidth = createMemo(() => { + if (!open()) return "0px" + if (reviewOpen()) return `calc(100% - ${layout.session.width()}px)` + return `${layout.fileTree.width()}px` + }) + const treeWidth = createMemo(() => (fileOpen() ? `${layout.fileTree.width()}px` : "0px")) const info = createMemo(() => (params.id ? sync.session.get(params.id) : undefined)) const diffs = createMemo(() => (params.id ? (sync.data.session_diff[params.id] ?? []) : [])) @@ -60,6 +69,12 @@ export function SessionSidePanel(props: { return sync.data.session_diff[id] !== undefined }) + const reviewEmptyKey = createMemo(() => { + if (sync.project && !sync.project.vcs) return "session.review.noVcs" + if (sync.data.config.snapshot === false) return "session.review.noSnapshot" + return "session.review.noChanges" + }) + const diffFiles = createMemo(() => diffs().map((d) => d.file)) const kinds = createMemo(() => { const merge = (a: "add" | "del" | "mix" | undefined, b: "add" | "del" | "mix") => { @@ -87,6 +102,21 @@ export function SessionSidePanel(props: { return out }) + const empty = (msg: string) => ( +
+
+
+
{msg}
+
+
+ ) + + const nofiles = createMemo(() => { + const state = file.tree.state("") + if (!state?.loaded) return false + return file.tree.children("").length === 0 + }) + const normalizeTab = (tab: string) => { if (!tab.startsWith("file://")) return tab return file.tab(tab) @@ -189,154 +219,172 @@ export function SessionSidePanel(props: { }) return ( - + ) diff --git a/packages/app/src/pages/session/terminal-panel.tsx b/packages/app/src/pages/session/terminal-panel.tsx index 27ea4e6f31..8fd652e903 100644 --- a/packages/app/src/pages/session/terminal-panel.tsx +++ b/packages/app/src/pages/session/terminal-panel.tsx @@ -17,7 +17,7 @@ import { useLanguage } from "@/context/language" import { useLayout } from "@/context/layout" import { useTerminal, type LocalPTY } from "@/context/terminal" import { terminalTabLabel } from "@/pages/session/terminal-label" -import { focusTerminalById } from "@/pages/session/helpers" +import { createPresence, createSizing, focusTerminalById } from "@/pages/session/helpers" import { getTerminalHandoff, setTerminalHandoff } from "@/pages/session/handoff" export function TerminalPanel() { @@ -33,8 +33,11 @@ export function TerminalPanel() { const opened = createMemo(() => view().terminal.opened()) const open = createMemo(() => isDesktop() && opened()) + const panel = createPresence(open) + const size = createSizing() const height = createMemo(() => layout.terminal.height()) const close = () => view().terminal.close() + let root: HTMLDivElement | undefined const [store, setStore] = createStore({ autoCreated: false, @@ -56,9 +59,9 @@ export function TerminalPanel() { on( () => terminal.all().length, (count, prevCount) => { - if (prevCount !== undefined && prevCount > 0 && count === 0) { - if (opened()) view().terminal.toggle() - } + if (prevCount === undefined || prevCount <= 0 || count !== 0) return + if (!opened()) return + close() }, ), ) @@ -67,7 +70,7 @@ export function TerminalPanel() { on( () => terminal.active(), (activeId) => { - if (!activeId || !open()) return + if (!activeId || !panel.open()) return if (document.activeElement instanceof HTMLElement) { document.activeElement.blur() } @@ -76,6 +79,14 @@ export function TerminalPanel() { ), ) + createEffect(() => { + if (panel.open()) return + const active = document.activeElement + if (!(active instanceof HTMLElement)) return + if (!root?.contains(active)) return + active.blur() + }) + createEffect(() => { const dir = params.dir if (!dir) return @@ -102,7 +113,7 @@ export function TerminalPanel() { const all = createMemo(() => terminal.all()) const ids = createMemo(() => all().map((pty) => pty.id)) - const byId = createMemo(() => new Map(all().map((pty) => [pty.id, pty]))) + const byId = createMemo(() => new Map(all().map((pty) => [pty.id, { ...pty }]))) const handleTerminalDragStart = (event: unknown) => { const id = getDraggableId(event) @@ -133,114 +144,143 @@ export function TerminalPanel() { } return ( - +
- - -
- - {(title) => ( -
- {title} -
- )} -
-
-
- {language.t("common.loading")} - {language.t("common.loading.ellipsis")} +
+
size.start()}> + { + size.touch() + layout.terminal.resize(next) + }} + onCollapse={close} + /> +
+ +
+ + {(title) => ( +
+ {title} +
+ )} +
+
+
+ {language.t("common.loading")} + {language.t("common.loading.ellipsis")} +
+
+
+ {language.t("terminal.loading")}
-
{language.t("terminal.loading")}
-
- } - > - - - -
- terminal.open(id)} - class="!h-auto !flex-none" - > - - - {(pty) => } - -
- - - -
-
-
-
- - {(id) => ( - - {(pty) => ( -
- terminal.clone(id)} /> + + + +
+ terminal.open(id)} + class="!h-auto !flex-none" + > + + + + {(id) => ( + + {(pty) => } + + )} + + +
+ + + +
+
+
+
+ + {(id) => ( + + {(pty) => ( +
+ terminal.trim(id)} + onCleanup={terminal.update} + onConnectError={() => terminal.clone(id)} + /> +
+ )} +
+ )} +
+
+
+ + + {(draggedId) => ( + + {(t) => ( +
+ {terminalTabLabel({ + title: t().title, + titleNumber: t().titleNumber, + t: language.t as (key: string, vars?: Record) => string, + })}
)}
)}
-
-
- - - {(draggedId) => ( - - {(t) => ( -
- {terminalTabLabel({ - title: t().title, - titleNumber: t().titleNumber, - t: language.t as (key: string, vars?: Record) => string, - })} -
- )} -
- )} -
-
- - + + + +
) diff --git a/packages/app/src/pages/session/use-session-commands.tsx b/packages/app/src/pages/session/use-session-commands.tsx index 461351878b..b8ddeda823 100644 --- a/packages/app/src/pages/session/use-session-commands.tsx +++ b/packages/app/src/pages/session/use-session-commands.tsx @@ -261,24 +261,35 @@ export const useSessionCommands = (actions: SessionCommandContext) => { }), ]) + const isAutoAcceptActive = () => { + const sessionID = params.id + if (sessionID) return permission.isAutoAccepting(sessionID, sdk.directory) + return permission.isAutoAcceptingDirectory(sdk.directory) + } + const permissionCommands = createMemo(() => [ permissionsCommand({ id: "permissions.autoaccept", - title: - params.id && permission.isAutoAccepting(params.id, sdk.directory) - ? language.t("command.permissions.autoaccept.disable") - : language.t("command.permissions.autoaccept.enable"), + title: isAutoAcceptActive() + ? language.t("command.permissions.autoaccept.disable") + : language.t("command.permissions.autoaccept.enable"), keybind: "mod+shift+a", - disabled: !params.id || !permission.permissionsEnabled(), + disabled: false, onSelect: () => { const sessionID = params.id - if (!sessionID) return - permission.toggleAutoAccept(sessionID, sdk.directory) + if (sessionID) { + permission.toggleAutoAccept(sessionID, sdk.directory) + } else { + permission.toggleAutoAcceptDirectory(sdk.directory) + } + const active = sessionID + ? permission.isAutoAccepting(sessionID, sdk.directory) + : permission.isAutoAcceptingDirectory(sdk.directory) showToast({ - title: permission.isAutoAccepting(sessionID, sdk.directory) + title: active ? language.t("toast.permissions.autoaccept.on.title") : language.t("toast.permissions.autoaccept.off.title"), - description: permission.isAutoAccepting(sessionID, sdk.directory) + description: active ? language.t("toast.permissions.autoaccept.on.description") : language.t("toast.permissions.autoaccept.off.description"), }) diff --git a/packages/app/src/pages/session/use-session-hash-scroll.test.ts b/packages/app/src/pages/session/use-session-hash-scroll.test.ts index 844f5451e3..7f3389baaa 100644 --- a/packages/app/src/pages/session/use-session-hash-scroll.test.ts +++ b/packages/app/src/pages/session/use-session-hash-scroll.test.ts @@ -1,5 +1,5 @@ import { describe, expect, test } from "bun:test" -import { messageIdFromHash } from "./use-session-hash-scroll" +import { messageIdFromHash } from "./message-id-from-hash" describe("messageIdFromHash", () => { test("parses hash with leading #", () => { diff --git a/packages/app/src/pages/session/use-session-hash-scroll.ts b/packages/app/src/pages/session/use-session-hash-scroll.ts index 555761ad1e..1ea6a302b9 100644 --- a/packages/app/src/pages/session/use-session-hash-scroll.ts +++ b/packages/app/src/pages/session/use-session-hash-scroll.ts @@ -1,12 +1,9 @@ -import { createEffect, createMemo, on, onCleanup } from "solid-js" -import { UserMessage } from "@opencode-ai/sdk/v2" +import type { UserMessage } from "@opencode-ai/sdk/v2" +import { useLocation, useNavigate } from "@solidjs/router" +import { createEffect, createMemo, onCleanup, onMount } from "solid-js" +import { messageIdFromHash } from "./message-id-from-hash" -export const messageIdFromHash = (hash: string) => { - const value = hash.startsWith("#") ? hash.slice(1) : hash - const match = value.match(/^message-(.+)$/) - if (!match) return - return match[1] -} +export { messageIdFromHash } from "./message-id-from-hash" export const useSessionHashScroll = (input: { sessionKey: () => string @@ -19,7 +16,6 @@ export const useSessionHashScroll = (input: { setPendingMessage: (value: string | undefined) => void setActiveMessage: (message: UserMessage | undefined) => void setTurnStart: (value: number) => void - scheduleTurnBackfill: () => void autoScroll: { pause: () => void; forceScrollToBottom: () => void } scroller: () => HTMLDivElement | undefined anchor: (id: string) => string @@ -29,14 +25,41 @@ export const useSessionHashScroll = (input: { const visibleUserMessages = createMemo(() => input.visibleUserMessages()) const messageById = createMemo(() => new Map(visibleUserMessages().map((m) => [m.id, m]))) const messageIndex = createMemo(() => new Map(visibleUserMessages().map((m, i) => [m.id, i]))) + let pendingKey = "" + let clearing = false + + const location = useLocation() + const navigate = useNavigate() + + const frames = new Set() + const queue = (fn: () => void) => { + const id = requestAnimationFrame(() => { + frames.delete(id) + fn() + }) + frames.add(id) + } + const cancel = () => { + for (const id of frames) cancelAnimationFrame(id) + frames.clear() + } const clearMessageHash = () => { - if (!window.location.hash) return - window.history.replaceState(null, "", window.location.href.replace(/#.*$/, "")) + cancel() + input.consumePendingMessage(input.sessionKey()) + if (input.pendingMessage()) input.setPendingMessage(undefined) + if (!location.hash) return + clearing = true + navigate(location.pathname + location.search, { replace: true }) } const updateHash = (id: string) => { - window.history.replaceState(null, "", `#${input.anchor(id)}`) + const hash = `#${input.anchor(id)}` + if (location.hash === hash) return + clearing = false + navigate(location.pathname + location.search + hash, { + replace: true, + }) } const scrollToElement = (el: HTMLElement, behavior: ScrollBehavior) => { @@ -45,61 +68,49 @@ export const useSessionHashScroll = (input: { const a = el.getBoundingClientRect() const b = root.getBoundingClientRect() - const top = a.top - b.top + root.scrollTop + const sticky = root.querySelector("[data-session-title]") + const inset = sticky instanceof HTMLElement ? sticky.offsetHeight : 0 + const top = Math.max(0, a.top - b.top + root.scrollTop - inset) root.scrollTo({ top, behavior }) return true } + const seek = (id: string, behavior: ScrollBehavior, left = 4): boolean => { + const el = document.getElementById(input.anchor(id)) + if (el) return scrollToElement(el, behavior) + if (left <= 0) return false + queue(() => { + seek(id, behavior, left - 1) + }) + return false + } + const scrollToMessage = (message: UserMessage, behavior: ScrollBehavior = "smooth") => { + cancel() if (input.currentMessageId() !== message.id) input.setActiveMessage(message) const index = messageIndex().get(message.id) ?? -1 if (index !== -1 && index < input.turnStart()) { input.setTurnStart(index) - input.scheduleTurnBackfill() - requestAnimationFrame(() => { - const el = document.getElementById(input.anchor(message.id)) - if (!el) { - requestAnimationFrame(() => { - const next = document.getElementById(input.anchor(message.id)) - if (!next) return - scrollToElement(next, behavior) - }) - return - } - scrollToElement(el, behavior) + queue(() => { + seek(message.id, behavior) }) updateHash(message.id) return } - const el = document.getElementById(input.anchor(message.id)) - if (!el) { - updateHash(message.id) - requestAnimationFrame(() => { - const next = document.getElementById(input.anchor(message.id)) - if (!next) return - if (!scrollToElement(next, behavior)) return - }) - return - } - if (scrollToElement(el, behavior)) { + if (seek(message.id, behavior)) { updateHash(message.id) return } - requestAnimationFrame(() => { - const next = document.getElementById(input.anchor(message.id)) - if (!next) return - if (!scrollToElement(next, behavior)) return - }) updateHash(message.id) } const applyHash = (behavior: ScrollBehavior) => { - const hash = window.location.hash.slice(1) + const hash = location.hash.slice(1) if (!hash) { input.autoScroll.forceScrollToBottom() const el = input.scroller() @@ -130,18 +141,12 @@ export const useSessionHashScroll = (input: { if (el) input.scheduleScrollState(el) } - createEffect( - on(input.sessionKey, (key) => { - if (!input.sessionID()) return - const messageID = input.consumePendingMessage(key) - if (!messageID) return - input.setPendingMessage(messageID) - }), - ) - createEffect(() => { + const hash = location.hash + if (!hash) clearing = false if (!input.sessionID() || !input.messagesReady()) return - requestAnimationFrame(() => applyHash("auto")) + cancel() + queue(() => applyHash("auto")) }) createEffect(() => { @@ -150,25 +155,42 @@ export const useSessionHashScroll = (input: { visibleUserMessages() input.turnStart() - const targetId = input.pendingMessage() ?? messageIdFromHash(window.location.hash) - if (!targetId) return - if (input.currentMessageId() === targetId) return + let targetId = input.pendingMessage() + if (!targetId) { + const key = input.sessionKey() + if (pendingKey !== key) { + pendingKey = key + const next = input.consumePendingMessage(key) + if (next) { + input.setPendingMessage(next) + targetId = next + } + } + } + if (!targetId && !clearing) targetId = messageIdFromHash(location.hash) + if (!targetId) return + + const pending = input.pendingMessage() === targetId const msg = messageById().get(targetId) if (!msg) return - if (input.pendingMessage() === targetId) input.setPendingMessage(undefined) + if (pending) input.setPendingMessage(undefined) + if (input.currentMessageId() === targetId && !pending) return + input.autoScroll.pause() - requestAnimationFrame(() => scrollToMessage(msg, "auto")) + cancel() + queue(() => scrollToMessage(msg, "auto")) }) - createEffect(() => { - if (!input.sessionID() || !input.messagesReady()) return - const handler = () => requestAnimationFrame(() => applyHash("auto")) - window.addEventListener("hashchange", handler) - onCleanup(() => window.removeEventListener("hashchange", handler)) + onMount(() => { + if (typeof window !== "undefined" && "scrollRestoration" in window.history) { + window.history.scrollRestoration = "manual" + } }) + onCleanup(cancel) + return { clearMessageHash, scrollToMessage, diff --git a/packages/app/src/theme-preload.test.ts b/packages/app/src/theme-preload.test.ts new file mode 100644 index 0000000000..00d7da2394 --- /dev/null +++ b/packages/app/src/theme-preload.test.ts @@ -0,0 +1,46 @@ +import { beforeEach, describe, expect, test } from "bun:test" + +const src = await Bun.file(new URL("../public/oc-theme-preload.js", import.meta.url)).text() + +const run = () => Function(src)() + +beforeEach(() => { + document.head.innerHTML = "" + document.documentElement.removeAttribute("data-theme") + document.documentElement.removeAttribute("data-color-scheme") + localStorage.clear() + Object.defineProperty(window, "matchMedia", { + value: () => + ({ + matches: false, + }) as MediaQueryList, + configurable: true, + }) +}) + +describe("theme preload", () => { + test("migrates legacy oc-1 to oc-2 before mount", () => { + localStorage.setItem("opencode-theme-id", "oc-1") + localStorage.setItem("opencode-theme-css-light", "--background-base:#fff;") + localStorage.setItem("opencode-theme-css-dark", "--background-base:#000;") + + run() + + expect(document.documentElement.dataset.theme).toBe("oc-2") + expect(document.documentElement.dataset.colorScheme).toBe("light") + expect(localStorage.getItem("opencode-theme-id")).toBe("oc-2") + expect(localStorage.getItem("opencode-theme-css-light")).toBeNull() + expect(localStorage.getItem("opencode-theme-css-dark")).toBeNull() + expect(document.getElementById("oc-theme-preload")).toBeNull() + }) + + test("keeps cached css for non-default themes", () => { + localStorage.setItem("opencode-theme-id", "nightowl") + localStorage.setItem("opencode-theme-css-light", "--background-base:#fff;") + + run() + + expect(document.documentElement.dataset.theme).toBe("nightowl") + expect(document.getElementById("oc-theme-preload")?.textContent).toContain("--background-base:#fff;") + }) +}) diff --git a/packages/app/src/utils/comment-note.ts b/packages/app/src/utils/comment-note.ts new file mode 100644 index 0000000000..99e87fc81c --- /dev/null +++ b/packages/app/src/utils/comment-note.ts @@ -0,0 +1,88 @@ +import type { FileSelection } from "@/context/file" + +export type PromptComment = { + path: string + selection?: FileSelection + comment: string + preview?: string + origin?: "review" | "file" +} + +function selection(selection: unknown) { + if (!selection || typeof selection !== "object") return undefined + const startLine = Number((selection as FileSelection).startLine) + const startChar = Number((selection as FileSelection).startChar) + const endLine = Number((selection as FileSelection).endLine) + const endChar = Number((selection as FileSelection).endChar) + if (![startLine, startChar, endLine, endChar].every(Number.isFinite)) return undefined + return { + startLine, + startChar, + endLine, + endChar, + } satisfies FileSelection +} + +export function createCommentMetadata(input: PromptComment) { + return { + opencodeComment: { + path: input.path, + selection: input.selection, + comment: input.comment, + preview: input.preview, + origin: input.origin, + }, + } +} + +export function readCommentMetadata(value: unknown) { + if (!value || typeof value !== "object") return + const meta = (value as { opencodeComment?: unknown }).opencodeComment + if (!meta || typeof meta !== "object") return + const path = (meta as { path?: unknown }).path + const comment = (meta as { comment?: unknown }).comment + if (typeof path !== "string" || typeof comment !== "string") return + const preview = (meta as { preview?: unknown }).preview + const origin = (meta as { origin?: unknown }).origin + return { + path, + selection: selection((meta as { selection?: unknown }).selection), + comment, + preview: typeof preview === "string" ? preview : undefined, + origin: origin === "review" || origin === "file" ? origin : undefined, + } satisfies PromptComment +} + +export function formatCommentNote(input: { path: string; selection?: FileSelection; comment: string }) { + const start = input.selection ? Math.min(input.selection.startLine, input.selection.endLine) : undefined + const end = input.selection ? Math.max(input.selection.startLine, input.selection.endLine) : undefined + const range = + start === undefined || end === undefined + ? "this file" + : start === end + ? `line ${start}` + : `lines ${start} through ${end}` + return `The user made the following comment regarding ${range} of ${input.path}: ${input.comment}` +} + +export function parseCommentNote(text: string) { + const match = text.match( + /^The user made the following comment regarding (this file|line (\d+)|lines (\d+) through (\d+)) of (.+?): ([\s\S]+)$/, + ) + if (!match) return + const start = match[2] ? Number(match[2]) : match[3] ? Number(match[3]) : undefined + const end = match[2] ? Number(match[2]) : match[4] ? Number(match[4]) : undefined + return { + path: match[5], + selection: + start !== undefined && end !== undefined + ? { + startLine: start, + startChar: 0, + endLine: end, + endChar: 0, + } + : undefined, + comment: match[6], + } satisfies PromptComment +} diff --git a/packages/app/src/utils/notification-click.test.ts b/packages/app/src/utils/notification-click.test.ts index 76535f83a8..fa81b0e025 100644 --- a/packages/app/src/utils/notification-click.test.ts +++ b/packages/app/src/utils/notification-click.test.ts @@ -1,26 +1,27 @@ -import { describe, expect, test } from "bun:test" -import { handleNotificationClick } from "./notification-click" +import { afterEach, describe, expect, test } from "bun:test" +import { handleNotificationClick, setNavigate } from "./notification-click" describe("notification click", () => { - test("focuses and navigates when href exists", () => { - const calls: string[] = [] - handleNotificationClick("/abc/session/123", { - focus: () => calls.push("focus"), - location: { - assign: (href) => calls.push(href), - }, - }) - expect(calls).toEqual(["focus", "/abc/session/123"]) + afterEach(() => { + setNavigate(undefined as any) }) - test("only focuses when href is missing", () => { + test("navigates via registered navigate function", () => { const calls: string[] = [] - handleNotificationClick(undefined, { - focus: () => calls.push("focus"), - location: { - assign: (href) => calls.push(href), - }, - }) - expect(calls).toEqual(["focus"]) + setNavigate((href) => calls.push(href)) + handleNotificationClick("/abc/session/123") + expect(calls).toEqual(["/abc/session/123"]) + }) + + test("does not navigate when href is missing", () => { + const calls: string[] = [] + setNavigate((href) => calls.push(href)) + handleNotificationClick(undefined) + expect(calls).toEqual([]) + }) + + test("falls back to location.assign without registered navigate", () => { + handleNotificationClick("/abc/session/123") + // falls back to window.location.assign — no error thrown }) }) diff --git a/packages/app/src/utils/notification-click.ts b/packages/app/src/utils/notification-click.ts index 1234cd1d62..316b278206 100644 --- a/packages/app/src/utils/notification-click.ts +++ b/packages/app/src/utils/notification-click.ts @@ -1,12 +1,13 @@ -type WindowTarget = { - focus: () => void - location: { - assign: (href: string) => void - } +let nav: ((href: string) => void) | undefined + +export const setNavigate = (fn: (href: string) => void) => { + nav = fn } -export const handleNotificationClick = (href?: string, target: WindowTarget = window) => { - target.focus() +export const handleNotificationClick = (href?: string) => { + window.focus() if (!href) return - target.location.assign(href) + if (nav) return nav(href) + console.warn("notification-click: navigate function not set, falling back to window.location.assign") + window.location.assign(href) } diff --git a/packages/app/src/utils/persist.test.ts b/packages/app/src/utils/persist.test.ts index 2a2c349b75..673acd224d 100644 --- a/packages/app/src/utils/persist.test.ts +++ b/packages/app/src/utils/persist.test.ts @@ -104,4 +104,12 @@ describe("persist localStorage resilience", () => { const result = persistTesting.normalize({ value: "ok" }, '{"value":"\\x"}') expect(result).toBeUndefined() }) + + test("workspace storage sanitizes Windows filename characters", () => { + const result = persistTesting.workspaceStorage("C:\\Users\\foo") + + expect(result).toStartWith("opencode.workspace.") + expect(result.endsWith(".dat")).toBeTrue() + expect(/[:\\/]/.test(result)).toBeFalse() + }) }) diff --git a/packages/app/src/utils/persist.ts b/packages/app/src/utils/persist.ts index 91c504742a..bee2f3e7d1 100644 --- a/packages/app/src/utils/persist.ts +++ b/packages/app/src/utils/persist.ts @@ -204,7 +204,7 @@ function normalize(defaults: unknown, raw: string, migrate?: (value: unknown) => } function workspaceStorage(dir: string) { - const head = dir.slice(0, 12) || "workspace" + const head = (dir.slice(0, 12) || "workspace").replace(/[^a-zA-Z0-9._-]/g, "-") const sum = checksum(dir) ?? "0" return `opencode.workspace.${head}.${sum}.dat` } @@ -300,6 +300,7 @@ export const PersistTesting = { localStorageDirect, localStorageWithPrefix, normalize, + workspaceStorage, } export const Persist = { diff --git a/packages/app/src/utils/server-errors.test.ts b/packages/app/src/utils/server-errors.test.ts new file mode 100644 index 0000000000..1f53bb8cf6 --- /dev/null +++ b/packages/app/src/utils/server-errors.test.ts @@ -0,0 +1,131 @@ +import { describe, expect, test } from "bun:test" +import type { ConfigInvalidError, ProviderModelNotFoundError } from "./server-errors" +import { formatServerError, parseReadableConfigInvalidError } from "./server-errors" + +function fill(text: string, vars?: Record) { + if (!vars) return text + return text.replace(/{{\s*(\w+)\s*}}/g, (_, key: string) => { + const value = vars[key] + if (value === undefined) return "" + return String(value) + }) +} + +function useLanguageMock() { + const dict: Record = { + "error.chain.unknown": "Erro desconhecido", + "error.chain.configInvalid": "Arquivo de config em {{path}} invalido", + "error.chain.configInvalidWithMessage": "Arquivo de config em {{path}} invalido: {{message}}", + "error.chain.modelNotFound": "Modelo nao encontrado: {{provider}}/{{model}}", + "error.chain.didYouMean": "Voce quis dizer: {{suggestions}}", + "error.chain.checkConfig": "Revise provider/model no config", + } + return { + t(key: string, vars?: Record) { + const text = dict[key] + if (!text) return key + return fill(text, vars) + }, + } +} + +const language = useLanguageMock() + +describe("parseReadableConfigInvalidError", () => { + test("formats issues with file path", () => { + const error = { + name: "ConfigInvalidError", + data: { + path: "opencode.config.ts", + issues: [ + { path: ["settings", "host"], message: "Required" }, + { path: ["mode"], message: "Invalid" }, + ], + }, + } satisfies ConfigInvalidError + + const result = parseReadableConfigInvalidError(error, language.t) + + expect(result).toBe( + ["Arquivo de config em opencode.config.ts invalido: settings.host: Required", "mode: Invalid"].join("\n"), + ) + }) + + test("uses trimmed message when issues are missing", () => { + const error = { + name: "ConfigInvalidError", + data: { + path: "config", + message: " Bad value ", + }, + } satisfies ConfigInvalidError + + const result = parseReadableConfigInvalidError(error, language.t) + + expect(result).toBe("Arquivo de config em config invalido: Bad value") + }) +}) + +describe("formatServerError", () => { + test("formats config invalid errors", () => { + const error = { + name: "ConfigInvalidError", + data: { + message: "Missing host", + }, + } satisfies ConfigInvalidError + + const result = formatServerError(error, language.t) + + expect(result).toBe("Arquivo de config em config invalido: Missing host") + }) + + test("returns error messages", () => { + expect(formatServerError(new Error("Request failed with status 503"), language.t)).toBe( + "Request failed with status 503", + ) + }) + + test("returns provided string errors", () => { + expect(formatServerError("Failed to connect to server", language.t)).toBe("Failed to connect to server") + }) + + test("uses translated unknown fallback", () => { + expect(formatServerError(0, language.t)).toBe("Erro desconhecido") + }) + + test("falls back for unknown error objects and names", () => { + expect(formatServerError({ name: "ServerTimeoutError", data: { seconds: 30 } }, language.t)).toBe( + "Erro desconhecido", + ) + }) + + test("formats provider model errors using provider/model", () => { + const error = { + name: "ProviderModelNotFoundError", + data: { + providerID: "openai", + modelID: "gpt-4.1", + }, + } satisfies ProviderModelNotFoundError + + expect(formatServerError(error, language.t)).toBe( + ["Modelo nao encontrado: openai/gpt-4.1", "Revise provider/model no config"].join("\n"), + ) + }) + + test("formats provider model suggestions", () => { + const error = { + name: "ProviderModelNotFoundError", + data: { + providerID: "x", + modelID: "y", + suggestions: ["x/y2", "x/y3"], + }, + } satisfies ProviderModelNotFoundError + + expect(formatServerError(error, language.t)).toBe( + ["Modelo nao encontrado: x/y", "Voce quis dizer: x/y2, x/y3", "Revise provider/model no config"].join("\n"), + ) + }) +}) diff --git a/packages/app/src/utils/server-errors.ts b/packages/app/src/utils/server-errors.ts new file mode 100644 index 0000000000..2c3a8c54db --- /dev/null +++ b/packages/app/src/utils/server-errors.ts @@ -0,0 +1,80 @@ +export type ConfigInvalidError = { + name: "ConfigInvalidError" + data: { + path?: string + message?: string + issues?: Array<{ message: string; path: string[] }> + } +} + +export type ProviderModelNotFoundError = { + name: "ProviderModelNotFoundError" + data: { + providerID: string + modelID: string + suggestions?: string[] + } +} + +type Translator = (key: string, vars?: Record) => string + +function tr(translator: Translator | undefined, key: string, text: string, vars?: Record) { + if (!translator) return text + const out = translator(key, vars) + if (!out || out === key) return text + return out +} + +export function formatServerError(error: unknown, translate?: Translator, fallback?: string) { + if (isConfigInvalidErrorLike(error)) return parseReadableConfigInvalidError(error, translate) + if (isProviderModelNotFoundErrorLike(error)) return parseReadableProviderModelNotFoundError(error, translate) + if (error instanceof Error && error.message) return error.message + if (typeof error === "string" && error) return error + if (fallback) return fallback + return tr(translate, "error.chain.unknown", "Unknown error") +} + +function isConfigInvalidErrorLike(error: unknown): error is ConfigInvalidError { + if (typeof error !== "object" || error === null) return false + const o = error as Record + return o.name === "ConfigInvalidError" && typeof o.data === "object" && o.data !== null +} + +function isProviderModelNotFoundErrorLike(error: unknown): error is ProviderModelNotFoundError { + if (typeof error !== "object" || error === null) return false + const o = error as Record + return o.name === "ProviderModelNotFoundError" && typeof o.data === "object" && o.data !== null +} + +export function parseReadableConfigInvalidError(errorInput: ConfigInvalidError, translator?: Translator) { + const file = errorInput.data.path && errorInput.data.path !== "config" ? errorInput.data.path : "config" + const detail = errorInput.data.message?.trim() ?? "" + const issues = (errorInput.data.issues ?? []) + .map((issue) => { + const msg = issue.message.trim() + if (!issue.path.length) return msg + return `${issue.path.join(".")}: ${msg}` + }) + .filter(Boolean) + const msg = issues.length ? issues.join("\n") : detail + if (!msg) return tr(translator, "error.chain.configInvalid", `Config file at ${file} is invalid`, { path: file }) + return tr(translator, "error.chain.configInvalidWithMessage", `Config file at ${file} is invalid: ${msg}`, { + path: file, + message: msg, + }) +} + +function parseReadableProviderModelNotFoundError(errorInput: ProviderModelNotFoundError, translator?: Translator) { + const p = errorInput.data.providerID.trim() + const m = errorInput.data.modelID.trim() + const list = (errorInput.data.suggestions ?? []).map((v) => v.trim()).filter(Boolean) + const body = tr(translator, "error.chain.modelNotFound", `Model not found: ${p}/${m}`, { provider: p, model: m }) + const tail = tr(translator, "error.chain.checkConfig", "Check your config (opencode.json) provider/model names") + if (list.length) { + const suggestions = list.slice(0, 5).join(", ") + return [body, tr(translator, "error.chain.didYouMean", `Did you mean: ${suggestions}`, { suggestions }), tail].join( + "\n", + ) + } + return [body, tail].join("\n") +} diff --git a/packages/app/src/utils/time.ts b/packages/app/src/utils/time.ts index ac709d86dd..d183e10807 100644 --- a/packages/app/src/utils/time.ts +++ b/packages/app/src/utils/time.ts @@ -1,4 +1,12 @@ -export function getRelativeTime(dateString: string): string { +type TimeKey = + | "common.time.justNow" + | "common.time.minutesAgo.short" + | "common.time.hoursAgo.short" + | "common.time.daysAgo.short" + +type Translate = (key: TimeKey, params?: Record) => string + +export function getRelativeTime(dateString: string, t: Translate): string { const date = new Date(dateString) const now = new Date() const diffMs = now.getTime() - date.getTime() @@ -7,8 +15,8 @@ export function getRelativeTime(dateString: string): string { const diffHours = Math.floor(diffMinutes / 60) const diffDays = Math.floor(diffHours / 24) - if (diffSeconds < 60) return "Just now" - if (diffMinutes < 60) return `${diffMinutes}m ago` - if (diffHours < 24) return `${diffHours}h ago` - return `${diffDays}d ago` + if (diffSeconds < 60) return t("common.time.justNow") + if (diffMinutes < 60) return t("common.time.minutesAgo.short", { count: diffMinutes }) + if (diffHours < 24) return t("common.time.hoursAgo.short", { count: diffHours }) + return t("common.time.daysAgo.short", { count: diffDays }) } diff --git a/packages/app/tsconfig.json b/packages/app/tsconfig.json index bfd45ff85e..e2a27dd5d8 100644 --- a/packages/app/tsconfig.json +++ b/packages/app/tsconfig.json @@ -22,6 +22,5 @@ } }, "include": ["src", "package.json"], - "exclude": ["dist", "ts-dist"], - "references": [{ "path": "../sdk/js" }] + "exclude": ["dist", "ts-dist"] } diff --git a/packages/console/app/package.json b/packages/console/app/package.json index 904aeadd8e..2cbc8f7575 100644 --- a/packages/console/app/package.json +++ b/packages/console/app/package.json @@ -1,13 +1,13 @@ { "name": "@opencode-ai/console-app", - "version": "1.2.10", + "version": "1.2.24", "type": "module", "license": "MIT", "scripts": { "typecheck": "tsgo --noEmit", "dev": "vite dev --host 0.0.0.0", "dev:remote": "VITE_AUTH_URL=https://auth.dev.opencode.ai VITE_STRIPE_PUBLISHABLE_KEY=pk_test_51RtuLNE7fOCwHSD4mewwzFejyytjdGoSDK7CAvhbffwaZnPbNb2rwJICw6LTOXCmWO320fSNXvb5NzI08RZVkAxd00syfqrW7t bun sst shell --stage=dev bun dev", - "build": "./script/generate-sitemap.ts && vite build && ../../opencode/script/schema.ts ./.output/public/config.json", + "build": "bun ./script/generate-sitemap.ts && vite build && bun ../../opencode/script/schema.ts ./.output/public/config.json ./.output/public/tui.json", "start": "vite start" }, "dependencies": { diff --git a/packages/console/app/script/generate-sitemap.ts b/packages/console/app/script/generate-sitemap.ts index bdce205b90..89bca6bac5 100755 --- a/packages/console/app/script/generate-sitemap.ts +++ b/packages/console/app/script/generate-sitemap.ts @@ -26,6 +26,7 @@ async function getMainRoutes(): Promise { { path: "/enterprise", priority: 0.8, changefreq: "weekly" }, { path: "/brand", priority: 0.6, changefreq: "monthly" }, { path: "/zen", priority: 0.8, changefreq: "weekly" }, + { path: "/go", priority: 0.8, changefreq: "weekly" }, ] for (const item of staticRoutes) { diff --git a/packages/console/app/src/app.tsx b/packages/console/app/src/app.tsx index 3eb70606a4..1f1d0066ec 100644 --- a/packages/console/app/src/app.tsx +++ b/packages/console/app/src/app.tsx @@ -7,9 +7,21 @@ import { Font } from "@opencode-ai/ui/font" import "@ibm/plex/css/ibm-plex.css" import "./app.css" import { LanguageProvider } from "~/context/language" -import { I18nProvider } from "~/context/i18n" +import { I18nProvider, useI18n } from "~/context/i18n" import { strip } from "~/lib/language" +function AppMeta() { + const i18n = useI18n() + return ( + <> + opencode + + + + + ) +} + export default function App() { return ( - opencode - - - + {props.children} diff --git a/packages/console/app/src/asset/go-ornate-dark.svg b/packages/console/app/src/asset/go-ornate-dark.svg new file mode 100644 index 0000000000..9b617c6777 --- /dev/null +++ b/packages/console/app/src/asset/go-ornate-dark.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/packages/console/app/src/asset/go-ornate-light.svg b/packages/console/app/src/asset/go-ornate-light.svg new file mode 100644 index 0000000000..79991973d6 --- /dev/null +++ b/packages/console/app/src/asset/go-ornate-light.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/packages/console/app/src/component/header.tsx b/packages/console/app/src/component/header.tsx index 6fa0f43ad8..24d5a897ce 100644 --- a/packages/console/app/src/component/header.tsx +++ b/packages/console/app/src/component/header.tsx @@ -36,7 +36,7 @@ const fetchSvgContent = async (svgPath: string): Promise => { } } -export function Header(props: { zen?: boolean; hideGetStarted?: boolean }) { +export function Header(props: { zen?: boolean; go?: boolean; hideGetStarted?: boolean }) { const navigate = useNavigate() const i18n = useI18n() const language = useLanguage() @@ -124,8 +124,8 @@ export function Header(props: { zen?: boolean; hideGetStarted?: boolean }) {
@@ -161,19 +161,24 @@ export function Header(props: { zen?: boolean; hideGetStarted?: boolean }) {
  • {i18n.t("nav.docs")}
  • + +
  • + {i18n.t("nav.zen")} +
  • +
    + +
  • + {i18n.t("nav.go")} +
  • +
  • {i18n.t("nav.enterprise")}
  • -
  • - - - {i18n.t("nav.login")} - - - {i18n.t("nav.zen")} - - -
  • + +
  • + {i18n.t("nav.login")} +
  • +
  • @@ -257,19 +262,24 @@ export function Header(props: { zen?: boolean; hideGetStarted?: boolean }) {
  • {i18n.t("nav.docs")}
  • + +
  • + {i18n.t("nav.zen")} +
  • +
    + +
  • + {i18n.t("nav.go")} +
  • +
  • {i18n.t("nav.enterprise")}
  • -
  • - - - {i18n.t("nav.login")} - - - {i18n.t("nav.zen")} - - -
  • + +
  • + {i18n.t("nav.login")} +
  • +
  • diff --git a/packages/console/app/src/config.ts b/packages/console/app/src/config.ts index e64d364620..19e331c39a 100644 --- a/packages/console/app/src/config.ts +++ b/packages/console/app/src/config.ts @@ -9,8 +9,8 @@ export const config = { github: { repoUrl: "https://github.com/anomalyco/opencode", starsFormatted: { - compact: "100K", - full: "100,000", + compact: "120K", + full: "120,000", }, }, @@ -22,8 +22,8 @@ export const config = { // Static stats (used on landing page) stats: { - contributors: "700", - commits: "9,000", - monthlyUsers: "2.5M", + contributors: "800", + commits: "10,000", + monthlyUsers: "5M", }, } as const diff --git a/packages/console/app/src/i18n/ar.ts b/packages/console/app/src/i18n/ar.ts index bf22ec157f..86d51226a6 100644 --- a/packages/console/app/src/i18n/ar.ts +++ b/packages/console/app/src/i18n/ar.ts @@ -15,6 +15,7 @@ export const dict = { "nav.home": "الرئيسية", "nav.openMenu": "فتح القائمة", "nav.getStartedFree": "ابدأ مجانا", + "nav.logoAlt": "OpenCode", "nav.context.copyLogo": "نسخ الشعار كـ SVG", "nav.context.copyWordmark": "نسخ اسم العلامة كـ SVG", @@ -42,9 +43,13 @@ export const dict = { "notFound.docs": "الوثائق", "notFound.github": "GitHub", "notFound.discord": "Discord", + "notFound.logoLightAlt": "شعار opencode الفاتح", + "notFound.logoDarkAlt": "شعار opencode الداكن", "user.logout": "تسجيل الخروج", + "auth.callback.error.codeMissing": "لم يتم العثور على رمز التفويض.", + "workspace.select": "اختر مساحة العمل", "workspace.createNew": "+ إنشاء مساحة عمل جديدة", "workspace.modal.title": "إنشاء مساحة عمل جديدة", @@ -76,6 +81,8 @@ export const dict = { "error.reloadAmountMin": "يجب أن يكون مبلغ الشحن ${{amount}} على الأقل", "error.reloadTriggerMin": "يجب أن يكون حد الرصيد ${{amount}} على الأقل", + "app.meta.description": "OpenCode - وكيل البرمجة مفتوح المصدر.", + "home.title": "OpenCode | وكيل برمجة بالذكاء الاصطناعي مفتوح المصدر", "temp.title": "opencode | وكيل برمجة بالذكاء الاصطناعي مبني للطرفية", @@ -91,6 +98,8 @@ export const dict = { "temp.feature.models.afterLink": "، بما في ذلك النماذج المحلية", "temp.screenshot.caption": "واجهة OpenCode الطرفية مع سمة tokyonight", "temp.screenshot.alt": "واجهة OpenCode الطرفية بسمة tokyonight", + "temp.logoLightAlt": "شعار opencode الفاتح", + "temp.logoDarkAlt": "شعار opencode الداكن", "home.banner.badge": "جديد", "home.banner.text": "تطبيق سطح المكتب متاح بنسخة تجريبية", @@ -238,11 +247,128 @@ export const dict = { "تتم استضافة جميع نماذج Zen في الولايات المتحدة. يتبع المزودون سياسة عدم الاحتفاظ بالبيانات ولا يستخدمون بياناتك لتدريب النماذج، مع", "zen.privacy.exceptionsLink": "الاستثناءات التالية", + "go.title": "OpenCode Go | نماذج برمجة منخفضة التكلفة للجميع", + "go.meta.description": + "Go هو اشتراك بقيمة 10 دولارات شهريًا مع حدود سخية تبلغ 5 ساعات للطلبات لنماذج GLM-5 وKimi K2.5 وMiniMax M2.5.", + "go.hero.title": "نماذج برمجة منخفضة التكلفة للجميع", + "go.hero.body": + "يجلب Go البرمجة الوكيلة للمبرمجين حول العالم. يوفر حدودًا سخية ووصولًا موثوقًا إلى أقوى النماذج مفتوحة المصدر، حتى تتمكن من البناء باستخدام وكلاء أقوياء دون القلق بشأن التكلفة أو التوفر.", + + "go.cta.start": "اشترك في Go", + "go.cta.template": "{{text}} {{price}}", + "go.cta.text": "اشترك في Go", + "go.cta.price": "$10/شهر", + "go.pricing.body": "استخدمه مع أي وكيل. اشحن الرصيد إذا لزم الأمر. ألغِ في أي وقت.", + "go.graph.free": "مجاني", + "go.graph.freePill": "Big Pickle ونماذج مجانية", + "go.graph.go": "Go", + "go.graph.label": "الطلبات كل 5 ساعات", + "go.graph.usageLimits": "حدود الاستخدام", + "go.graph.tick": "{{n}}x", + "go.graph.aria": "الطلبات كل 5 ساعات: {{free}} مقابل {{go}}", + + "go.testimonials.brand.zen": "Zen", + "go.testimonials.brand.go": "Go", + "go.testimonials.handle": "@OpenCode", + "go.testimonials.dax.name": "Dax Raad", + "go.testimonials.dax.title": "الرئيس التنفيذي السابق، منتجات Terminal", + "go.testimonials.dax.quoteAfter": "كان تغييرًا جذريًا في الحياة، إنه قرار لا يحتاج لتفكير.", + "go.testimonials.jay.name": "Jay V", + "go.testimonials.jay.title": "مؤسس سابق، SEED، PM، Melt، Pop، Dapt، Cadmus، وViewPoint", + "go.testimonials.jay.quoteBefore": "4 من كل 5 أشخاص في فريقنا يحبون استخدام", + "go.testimonials.jay.quoteAfter": ".", + "go.testimonials.adam.name": "Adam Elmore", + "go.testimonials.adam.title": "بطل سابق، AWS", + "go.testimonials.adam.quoteBefore": "لا أستطيع التوصية بـ", + "go.testimonials.adam.quoteAfter": "بما فيه الكفاية. بجدية، إنه جيد حقًا.", + "go.testimonials.david.name": "David Hill", + "go.testimonials.david.title": "رئيس التصميم السابق، Laravel", + "go.testimonials.david.quoteBefore": "مع", + "go.testimonials.david.quoteAfter": "أعلم أن جميع النماذج مختبرة ومثالية لوكلاء البرمجة.", + "go.testimonials.frank.name": "Frank Wang", + "go.testimonials.frank.title": "متدرب سابق، Nvidia (4 مرات)", + "go.testimonials.frank.quote": "أتمنى لو كنت لا أزال في Nvidia.", + "go.problem.title": "ما المشكلة التي يحلها Go؟", + "go.problem.body": + "نحن نركز على جلب تجربة OpenCode لأكبر عدد ممكن من الناس. OpenCode Go هو اشتراك منخفض التكلفة (10 دولارات شهريًا) مصمم لجلب البرمجة الوكيلة للمبرمجين حول العالم. يوفر حدودًا سخية ووصولًا موثوقًا إلى أقوى النماذج مفتوحة المصدر.", + "go.problem.subtitle": " ", + "go.problem.item1": "أسعار اشتراك منخفضة التكلفة", + "go.problem.item2": "حدود سخية ووصول موثوق", + "go.problem.item3": "مصمم لأكبر عدد ممكن من المبرمجين", + "go.problem.item4": "يتضمن GLM-5 وKimi K2.5 وMiniMax M2.5", + "go.how.title": "كيف يعمل Go", + "go.how.body": "Go هو اشتراك بقيمة 10 دولارات شهريًا يمكنك استخدامه مع OpenCode أو أي وكيل.", + "go.how.step1.title": "أنشئ حسابًا", + "go.how.step1.beforeLink": "اتبع", + "go.how.step1.link": "تعليمات الإعداد", + "go.how.step2.title": "اشترك في Go", + "go.how.step2.link": "$10/شهر", + "go.how.step2.afterLink": "مع حدود سخية", + "go.how.step3.title": "ابدأ البرمجة", + "go.how.step3.body": "مع وصول موثوق لنماذج مفتوحة المصدر", + "go.privacy.title": "خصوصيتك مهمة بالنسبة لنا", + "go.privacy.body": + "تم تصميم الخطة بشكل أساسي للمستخدمين الدوليين، مع استضافة النماذج في الولايات المتحدة والاتحاد الأوروبي وسنغافورة للحصول على وصول عالمي مستقر.", + "go.privacy.contactAfter": "إذا كان لديك أي أسئلة.", + "go.privacy.beforeExceptions": + "تتم استضافة نماذج Go في الولايات المتحدة. يتبع المزودون سياسة عدم الاحتفاظ بالبيانات ولا يستخدمون بياناتك لتدريب النماذج، مع", + "go.privacy.exceptionsLink": "الاستثناءات التالية", + "go.faq.q1": "ما هو OpenCode Go؟", + "go.faq.a1": "Go هو اشتراك منخفض التكلفة يمنحك وصولًا موثوقًا إلى نماذج مفتوحة المصدر قادرة على البرمجة الوكيلة.", + "go.faq.q2": "ما النماذج التي يتضمنها Go؟", + "go.faq.a2": "يتضمن Go نماذج GLM-5 وKimi K2.5 وMiniMax M2.5، مع حدود سخية ووصول موثوق.", + "go.faq.q3": "هل Go هو نفسه Zen؟", + "go.faq.a3": + "لا. Zen هو نظام الدفع حسب الاستخدام، بينما Go هو اشتراك بقيمة 10 دولارات شهريًا مع حدود سخية ووصول موثوق لنماذج مفتوحة المصدر GLM-5 وKimi K2.5 وMiniMax M2.5.", + "go.faq.q4": "كم تكلفة Go؟", + "go.faq.a4.p1.beforePricing": "تكلفة Go", + "go.faq.a4.p1.pricingLink": "$10/شهر", + "go.faq.a4.p1.afterPricing": "مع حدود سخية.", + "go.faq.a4.p2.beforeAccount": "يمكنك إدارة اشتراكك في", + "go.faq.a4.p2.accountLink": "حسابك", + "go.faq.a4.p3": "ألغِ في أي وقت.", + "go.faq.q5": "ماذا عن البيانات والخصوصية؟", + "go.faq.a5.body": + "تم تصميم الخطة بشكل أساسي للمستخدمين الدوليين، مع استضافة النماذج في الولايات المتحدة والاتحاد الأوروبي وسنغافورة للحصول على وصول عالمي مستقر.", + "go.faq.a5.contactAfter": "إذا كان لديك أي أسئلة.", + "go.faq.a5.beforeExceptions": + "تتم استضافة نماذج Go في الولايات المتحدة. يتبع المزودون سياسة عدم الاحتفاظ بالبيانات ولا يستخدمون بياناتك لتدريب النماذج، مع", + "go.faq.a5.exceptionsLink": "الاستثناءات التالية", + "go.faq.q6": "هل يمكنني شحن رصيد إضافي؟", + "go.faq.a6": "إذا كنت بحاجة إلى مزيد من الاستخدام، يمكنك شحن رصيد في حسابك.", + "go.faq.q7": "هل يمكنني الإلغاء؟", + "go.faq.a7": "نعم، يمكنك الإلغاء في أي وقت.", + "go.faq.q8": "هل يمكنني استخدام Go مع وكلاء برمجة آخرين؟", + "go.faq.a8": "نعم، يمكنك استخدام Go مع أي وكيل. اتبع تعليمات الإعداد في وكيل البرمجة المفضل لديك.", + + "go.faq.q9": "ما الفرق بين النماذج المجانية وGo؟", + "go.faq.a9": + "تشمل النماذج المجانية Big Pickle بالإضافة إلى النماذج الترويجية المتاحة في ذلك الوقت، مع حصة 200 طلب/يوم. يتضمن Go نماذج GLM-5 وKimi K2.5 وMiniMax M2.5 مع حصص طلبات أعلى مطبقة عبر نوافذ متجددة (5 ساعات، أسبوعيًا، وشهريًا)، تعادل تقريبًا 12 دولارًا كل 5 ساعات، و30 دولارًا في الأسبوع، و60 دولارًا في الشهر (تختلف أعداد الطلبات الفعلية حسب النموذج والاستخدام).", + + "zen.api.error.rateLimitExceeded": "تم تجاوز حد الطلبات. يرجى المحاولة مرة أخرى لاحقًا.", + "zen.api.error.modelNotSupported": "النموذج {{model}} غير مدعوم", + "zen.api.error.modelFormatNotSupported": "النموذج {{model}} غير مدعوم للتنسيق {{format}}", + "zen.api.error.noProviderAvailable": "لا يوجد مزود متاح", + "zen.api.error.providerNotSupported": "المزود {{provider}} غير مدعوم", + "zen.api.error.missingApiKey": "مفتاح API مفقود.", + "zen.api.error.invalidApiKey": "مفتاح API غير صالح.", + "zen.api.error.subscriptionQuotaExceeded": "تم تجاوز حصة الاشتراك. أعد المحاولة خلال {{retryIn}}.", + "zen.api.error.subscriptionQuotaExceededUseFreeModels": + "تم تجاوز حصة الاشتراك. يمكنك الاستمرار في استخدام النماذج المجانية.", + "zen.api.error.noPaymentMethod": "لا توجد طريقة دفع. أضف طريقة دفع هنا: {{billingUrl}}", + "zen.api.error.insufficientBalance": "رصيد غير كاف. إدارة فواتيرك هنا: {{billingUrl}}", + "zen.api.error.workspaceMonthlyLimitReached": + "وصلت مساحة العمل الخاصة بك إلى حد الإنفاق الشهري البالغ ${{amount}}. إدارة حدودك هنا: {{billingUrl}}", + "zen.api.error.userMonthlyLimitReached": + "لقد وصلت إلى حد الإنفاق الشهري البالغ ${{amount}}. إدارة حدودك هنا: {{membersUrl}}", + "zen.api.error.modelDisabled": "النموذج معطل", + "black.meta.title": "OpenCode Black | الوصول إلى أفضل نماذج البرمجة في العالم", "black.meta.description": "احصل على وصول إلى Claude، GPT، Gemini والمزيد مع خطط اشتراك OpenCode Black.", "black.hero.title": "الوصول إلى أفضل نماذج البرمجة في العالم", "black.hero.subtitle": "بما في ذلك Claude، GPT، Gemini والمزيد", "black.title": "OpenCode Black | الأسعار", + "black.paused": "التسجيل في خطة Black متوقف مؤقتًا.", "black.plan.icon20": "خطة Black 20", "black.plan.icon100": "خطة Black 100", "black.plan.icon200": "خطة Black 200", @@ -337,12 +463,15 @@ export const dict = { "workspace.usage.table.input": "الدخل", "workspace.usage.table.output": "الخرج", "workspace.usage.table.cost": "التكلفة", + "workspace.usage.table.session": "الجلسة", "workspace.usage.breakdown.input": "الدخل", "workspace.usage.breakdown.cacheRead": "قراءة الكاش", "workspace.usage.breakdown.cacheWrite": "كتابة الكاش", "workspace.usage.breakdown.output": "الخرج", "workspace.usage.breakdown.reasoning": "المنطق", - "workspace.usage.subscription": "الاشتراك (${{amount}})", + "workspace.usage.subscription": "Black (${{amount}})", + "workspace.usage.lite": "Go (${{amount}})", + "workspace.usage.byok": "BYOK (${{amount}})", "workspace.cost.title": "التكلفة", "workspace.cost.subtitle": "تكاليف الاستخدام مقسمة حسب النموذج.", @@ -441,6 +570,7 @@ export const dict = { "workspace.reload.updatePaymentMethod": "يرجى تحديث طريقة الدفع والمحاولة مرة أخرى.", "workspace.reload.retrying": "جارٍ إعادة المحاولة...", "workspace.reload.retry": "أعد المحاولة", + "workspace.reload.error.paymentFailed": "فشلت عملية الدفع.", "workspace.payments.title": "سجل المدفوعات", "workspace.payments.subtitle": "معاملات الدفع الأخيرة.", @@ -478,6 +608,36 @@ export const dict = { "workspace.black.waitlist.enrolled": "مسجل", "workspace.black.waitlist.enrollNote": 'عند النقر فوق "تسجيل"، يبدأ اشتراكك على الفور وسيتم خصم الرسوم من بطاقتك.', + "workspace.lite.loading": "جارٍ التحميل...", + "workspace.lite.time.day": "يوم", + "workspace.lite.time.days": "أيام", + "workspace.lite.time.hour": "ساعة", + "workspace.lite.time.hours": "ساعات", + "workspace.lite.time.minute": "دقيقة", + "workspace.lite.time.minutes": "دقائق", + "workspace.lite.time.fewSeconds": "بضع ثوان", + "workspace.lite.subscription.title": "اشتراك Go", + "workspace.lite.subscription.message": "أنت مشترك في OpenCode Go.", + "workspace.lite.subscription.manage": "إدارة الاشتراك", + "workspace.lite.subscription.rollingUsage": "الاستخدام المتجدد", + "workspace.lite.subscription.weeklyUsage": "الاستخدام الأسبوعي", + "workspace.lite.subscription.monthlyUsage": "الاستخدام الشهري", + "workspace.lite.subscription.resetsIn": "إعادة تعيين في", + "workspace.lite.subscription.useBalance": "استخدم رصيدك المتوفر بعد الوصول إلى حدود الاستخدام", + "workspace.lite.subscription.selectProvider": + 'اختر "OpenCode Go" كمزود في إعدادات opencode الخاصة بك لاستخدام نماذج Go.', + "workspace.lite.other.title": "اشتراك Go", + "workspace.lite.other.message": + "عضو آخر في مساحة العمل هذه مشترك بالفعل في OpenCode Go. يمكن لعضو واحد فقط لكل مساحة عمل الاشتراك.", + "workspace.lite.promo.title": "OpenCode Go", + "workspace.lite.promo.description": + "OpenCode Go هو اشتراك بسعر $10 شهريًا يوفر وصولاً موثوقًا إلى نماذج البرمجة المفتوحة الشائعة مع حدود استخدام سخية.", + "workspace.lite.promo.modelsTitle": "ما يتضمنه", + "workspace.lite.promo.footer": + "تم تصميم الخطة بشكل أساسي للمستخدمين الدوليين، مع استضافة النماذج في الولايات المتحدة والاتحاد الأوروبي وسنغافورة للحصول على وصول عالمي مستقر. قد تتغير الأسعار وحدود الاستخدام بناءً على تعلمنا من الاستخدام المبكر والملاحظات.", + "workspace.lite.promo.subscribe": "الاشتراك في Go", + "workspace.lite.promo.subscribing": "جارٍ إعادة التوجيه...", + "download.title": "OpenCode | تنزيل", "download.meta.description": "نزّل OpenCode لـ macOS، Windows، وLinux", "download.hero.title": "تنزيل OpenCode", @@ -528,6 +688,10 @@ export const dict = { "enterprise.form.send": "إرسال", "enterprise.form.sending": "جارٍ الإرسال...", "enterprise.form.success": "تم إرسال الرسالة، سنتواصل معك قريبًا.", + "enterprise.form.success.submitted": "تم إرسال النموذج بنجاح.", + "enterprise.form.error.allFieldsRequired": "جميع الحقول مطلوبة.", + "enterprise.form.error.invalidEmailFormat": "تنسيق البريد الإلكتروني غير صالح.", + "enterprise.form.error.internalServer": "خطأ داخلي في الخادم.", "enterprise.faq.title": "الأسئلة الشائعة", "enterprise.faq.q1": "ما هو OpenCode Enterprise؟", "enterprise.faq.a1": @@ -560,6 +724,7 @@ export const dict = { "bench.list.table.agent": "الوكيل", "bench.list.table.model": "النموذج", "bench.list.table.score": "الدرجة", + "bench.submission.error.allFieldsRequired": "جميع الحقول مطلوبة.", "bench.detail.title": "المعيار - {{task}}", "bench.detail.notFound": "المهمة غير موجودة", diff --git a/packages/console/app/src/i18n/br.ts b/packages/console/app/src/i18n/br.ts index 0f39484eff..f14a69c85c 100644 --- a/packages/console/app/src/i18n/br.ts +++ b/packages/console/app/src/i18n/br.ts @@ -15,6 +15,7 @@ export const dict = { "nav.home": "Início", "nav.openMenu": "Abrir menu", "nav.getStartedFree": "Começar grátis", + "nav.logoAlt": "OpenCode", "nav.context.copyLogo": "Copiar logo como SVG", "nav.context.copyWordmark": "Copiar marca como SVG", @@ -42,9 +43,13 @@ export const dict = { "notFound.docs": "Documentação", "notFound.github": "GitHub", "notFound.discord": "Discord", + "notFound.logoLightAlt": "logo opencode claro", + "notFound.logoDarkAlt": "logo opencode escuro", "user.logout": "Sair", + "auth.callback.error.codeMissing": "Nenhum código de autorização encontrado.", + "workspace.select": "Selecionar workspace", "workspace.createNew": "+ Criar novo workspace", "workspace.modal.title": "Criar novo workspace", @@ -76,6 +81,8 @@ export const dict = { "error.reloadAmountMin": "O valor de recarga deve ser de pelo menos ${{amount}}", "error.reloadTriggerMin": "O gatilho de saldo deve ser de pelo menos ${{amount}}", + "app.meta.description": "OpenCode - O agente de codificação de código aberto.", + "home.title": "OpenCode | O agente de codificação de código aberto com IA", "temp.title": "opencode | Agente de codificação com IA feito para o terminal", @@ -91,6 +98,8 @@ export const dict = { "temp.feature.models.afterLink": ", incluindo modelos locais", "temp.screenshot.caption": "OpenCode TUI com o tema tokyonight", "temp.screenshot.alt": "OpenCode TUI com tema tokyonight", + "temp.logoLightAlt": "logo opencode claro", + "temp.logoDarkAlt": "logo opencode escuro", "home.banner.badge": "Novo", "home.banner.text": "App desktop disponível em beta", @@ -242,11 +251,131 @@ export const dict = { "Todos os modelos Zen são hospedados nos EUA. Os provedores seguem uma política de retenção zero e não usam seus dados para treinamento de modelo, com as", "zen.privacy.exceptionsLink": "seguintes exceções", + "go.title": "OpenCode Go | Modelos de codificação de baixo custo para todos", + "go.meta.description": + "O Go é uma assinatura de $10/mês com limites generosos de 5 horas de requisição para GLM-5, Kimi K2.5 e MiniMax M2.5.", + "go.hero.title": "Modelos de codificação de baixo custo para todos", + "go.hero.body": + "O Go traz a codificação com agentes para programadores em todo o mundo. Oferecendo limites generosos e acesso confiável aos modelos de código aberto mais capazes, para que você possa construir com agentes poderosos sem se preocupar com custos ou disponibilidade.", + + "go.cta.start": "Assinar o Go", + "go.cta.template": "{{text}} {{price}}", + "go.cta.text": "Assinar o Go", + "go.cta.price": "$10/mês", + "go.pricing.body": "Use com qualquer agente. Recarregue crédito se necessário. Cancele a qualquer momento.", + "go.graph.free": "Grátis", + "go.graph.freePill": "Big Pickle e modelos gratuitos", + "go.graph.go": "Go", + "go.graph.label": "Requisições por 5 horas", + "go.graph.usageLimits": "Limites de uso", + "go.graph.tick": "{{n}}x", + "go.graph.aria": "Requisições por 5h: {{free}} vs {{go}}", + + "go.testimonials.brand.zen": "Zen", + "go.testimonials.brand.go": "Go", + "go.testimonials.handle": "@OpenCode", + "go.testimonials.dax.name": "Dax Raad", + "go.testimonials.dax.title": "ex-CEO, Terminal Products", + "go.testimonials.dax.quoteAfter": "mudou minha vida, é realmente uma escolha óbvia.", + "go.testimonials.jay.name": "Jay V", + "go.testimonials.jay.title": "ex-Fundador, SEED, PM, Melt, Pop, Dapt, Cadmus e ViewPoint", + "go.testimonials.jay.quoteBefore": "4 de 5 pessoas em nossa equipe adoram usar", + "go.testimonials.jay.quoteAfter": ".", + "go.testimonials.adam.name": "Adam Elmore", + "go.testimonials.adam.title": "ex-Hero, AWS", + "go.testimonials.adam.quoteBefore": "Eu não consigo recomendar o", + "go.testimonials.adam.quoteAfter": "o suficiente. Sério, é muito bom.", + "go.testimonials.david.name": "David Hill", + "go.testimonials.david.title": "ex-Head de Design, Laravel", + "go.testimonials.david.quoteBefore": "Com o", + "go.testimonials.david.quoteAfter": + "eu sei que todos os modelos são testados e perfeitos para agentes de codificação.", + "go.testimonials.frank.name": "Frank Wang", + "go.testimonials.frank.title": "ex-Estagiário, Nvidia (4 vezes)", + "go.testimonials.frank.quote": "Eu queria ainda estar na Nvidia.", + "go.problem.title": "Que problema o Go resolve?", + "go.problem.body": + "Estamos focados em levar a experiência OpenCode para o maior número possível de pessoas. OpenCode Go é uma assinatura de baixo custo ($10/mês) projetada para levar a codificação com agentes para programadores em todo o mundo. Fornece limites generosos e acesso confiável aos modelos de código aberto mais capazes.", + "go.problem.subtitle": " ", + "go.problem.item1": "Preço de assinatura de baixo custo", + "go.problem.item2": "Limites generosos e acesso confiável", + "go.problem.item3": "Feito para o maior número possível de programadores", + "go.problem.item4": "Inclui GLM-5, Kimi K2.5 e MiniMax M2.5", + "go.how.title": "Como o Go funciona", + "go.how.body": "Go é uma assinatura de $10/mês que você pode usar com OpenCode ou qualquer agente.", + "go.how.step1.title": "Crie uma conta", + "go.how.step1.beforeLink": "siga as", + "go.how.step1.link": "instruções de configuração", + "go.how.step2.title": "Assinar o Go", + "go.how.step2.link": "$10/mês", + "go.how.step2.afterLink": "com limites generosos", + "go.how.step3.title": "Comece a codificar", + "go.how.step3.body": "com acesso confiável a modelos de código aberto", + "go.privacy.title": "Sua privacidade é importante para nós", + "go.privacy.body": + "O plano é projetado principalmente para usuários internacionais, com modelos hospedados nos EUA, UE e Singapura para acesso global estável.", + "go.privacy.contactAfter": "se você tiver alguma dúvida.", + "go.privacy.beforeExceptions": + "Os modelos Go são hospedados nos EUA. Os provedores seguem uma política de retenção zero e não usam seus dados para treinamento de modelos, com as", + "go.privacy.exceptionsLink": "seguintes exceções", + "go.faq.q1": "O que é OpenCode Go?", + "go.faq.a1": + "Go é uma assinatura de baixo custo que oferece acesso confiável a modelos de código aberto capazes para codificação com agentes.", + "go.faq.q2": "Quais modelos o Go inclui?", + "go.faq.a2": "Go inclui GLM-5, Kimi K2.5 e MiniMax M2.5, com limites generosos e acesso confiável.", + "go.faq.q3": "O Go é o mesmo que o Zen?", + "go.faq.a3": + "Não. O Zen é pago por uso (pay-as-you-go), enquanto o Go é uma assinatura de $10/mês com limites generosos e acesso confiável aos modelos de código aberto GLM-5, Kimi K2.5 e MiniMax M2.5.", + "go.faq.q4": "Quanto custa o Go?", + "go.faq.a4.p1.beforePricing": "O Go custa", + "go.faq.a4.p1.pricingLink": "$10/mês", + "go.faq.a4.p1.afterPricing": "com limites generosos.", + "go.faq.a4.p2.beforeAccount": "Você pode gerenciar sua assinatura em sua", + "go.faq.a4.p2.accountLink": "conta", + "go.faq.a4.p3": "Cancele a qualquer momento.", + "go.faq.q5": "E sobre dados e privacidade?", + "go.faq.a5.body": + "O plano é projetado principalmente para usuários internacionais, com modelos hospedados nos EUA, UE e Singapura para acesso global estável.", + "go.faq.a5.contactAfter": "se você tiver alguma dúvida.", + "go.faq.a5.beforeExceptions": + "Os modelos Go são hospedados nos EUA. Os provedores seguem uma política de retenção zero e não usam seus dados para treinamento de modelos, com as", + "go.faq.a5.exceptionsLink": "seguintes exceções", + "go.faq.q6": "Posso recarregar crédito?", + "go.faq.a6": "Se você precisar de mais uso, pode recarregar crédito em sua conta.", + "go.faq.q7": "Posso cancelar?", + "go.faq.a7": "Sim, você pode cancelar a qualquer momento.", + "go.faq.q8": "Posso usar o Go com outros agentes de codificação?", + "go.faq.a8": + "Sim, você pode usar o Go com qualquer agente. Siga as instruções de configuração no seu agente de codificação preferido.", + + "go.faq.q9": "Qual a diferença entre os modelos gratuitos e o Go?", + "go.faq.a9": + "Os modelos gratuitos incluem Big Pickle e modelos promocionais disponíveis no momento, com uma cota de 200 requisições/dia. O Go inclui GLM-5, Kimi K2.5 e MiniMax M2.5 com cotas de requisição mais altas aplicadas em janelas móveis (5 horas, semanal e mensal), aproximadamente equivalentes a $12 por 5 horas, $30 por semana e $60 por mês (as contagens reais de requisições variam de acordo com o modelo e o uso).", + + "zen.api.error.rateLimitExceeded": "Limite de taxa excedido. Por favor, tente novamente mais tarde.", + "zen.api.error.modelNotSupported": "Modelo {{model}} não suportado", + "zen.api.error.modelFormatNotSupported": "Modelo {{model}} não suportado para o formato {{format}}", + "zen.api.error.noProviderAvailable": "Nenhum provedor disponível", + "zen.api.error.providerNotSupported": "Provedor {{provider}} não suportado", + "zen.api.error.missingApiKey": "Chave de API ausente.", + "zen.api.error.invalidApiKey": "Chave de API inválida.", + "zen.api.error.subscriptionQuotaExceeded": "Cota de assinatura excedida. Tente novamente em {{retryIn}}.", + "zen.api.error.subscriptionQuotaExceededUseFreeModels": + "Cota de assinatura excedida. Você pode continuar usando modelos gratuitos.", + "zen.api.error.noPaymentMethod": "Nenhuma forma de pagamento. Adicione uma forma de pagamento aqui: {{billingUrl}}", + "zen.api.error.insufficientBalance": "Saldo insuficiente. Gerencie seu faturamento aqui: {{billingUrl}}", + "zen.api.error.workspaceMonthlyLimitReached": + "Seu workspace atingiu o limite de gastos mensais de ${{amount}}. Gerencie seus limites aqui: {{billingUrl}}", + "zen.api.error.userMonthlyLimitReached": + "Você atingiu seu limite de gastos mensais de ${{amount}}. Gerencie seus limites aqui: {{membersUrl}}", + "zen.api.error.modelDisabled": "O modelo está desabilitado", + "black.meta.title": "OpenCode Black | Acesse os melhores modelos de codificação do mundo", "black.meta.description": "Tenha acesso ao Claude, GPT, Gemini e mais com os planos de assinatura OpenCode Black.", "black.hero.title": "Acesse os melhores modelos de codificação do mundo", "black.hero.subtitle": "Incluindo Claude, GPT, Gemini e mais", "black.title": "OpenCode Black | Preços", + "black.paused": "A inscrição no plano Black está temporariamente pausada.", "black.plan.icon20": "Plano Black 20", "black.plan.icon100": "Plano Black 100", "black.plan.icon200": "Plano Black 200", @@ -342,12 +471,15 @@ export const dict = { "workspace.usage.table.input": "Entrada", "workspace.usage.table.output": "Saída", "workspace.usage.table.cost": "Custo", + "workspace.usage.table.session": "Sessão", "workspace.usage.breakdown.input": "Entrada", "workspace.usage.breakdown.cacheRead": "Leitura de Cache", "workspace.usage.breakdown.cacheWrite": "Escrita em Cache", "workspace.usage.breakdown.output": "Saída", "workspace.usage.breakdown.reasoning": "Raciocínio", - "workspace.usage.subscription": "assinatura (${{amount}})", + "workspace.usage.subscription": "Black (${{amount}})", + "workspace.usage.lite": "Go (${{amount}})", + "workspace.usage.byok": "BYOK (${{amount}})", "workspace.cost.title": "Custo", "workspace.cost.subtitle": "Custos de uso discriminados por modelo.", @@ -446,6 +578,7 @@ export const dict = { "workspace.reload.updatePaymentMethod": "Por favor, atualize sua forma de pagamento e tente novamente.", "workspace.reload.retrying": "Tentando novamente...", "workspace.reload.retry": "Tentar novamente", + "workspace.reload.error.paymentFailed": "Pagamento falhou.", "workspace.payments.title": "Histórico de Pagamentos", "workspace.payments.subtitle": "Transações de pagamento recentes.", @@ -484,6 +617,36 @@ export const dict = { "workspace.black.waitlist.enrollNote": "Ao clicar em Inscrever-se, sua assinatura começará imediatamente e seu cartão será cobrado.", + "workspace.lite.loading": "Carregando...", + "workspace.lite.time.day": "dia", + "workspace.lite.time.days": "dias", + "workspace.lite.time.hour": "hora", + "workspace.lite.time.hours": "horas", + "workspace.lite.time.minute": "minuto", + "workspace.lite.time.minutes": "minutos", + "workspace.lite.time.fewSeconds": "alguns segundos", + "workspace.lite.subscription.title": "Assinatura Go", + "workspace.lite.subscription.message": "Você assina o OpenCode Go.", + "workspace.lite.subscription.manage": "Gerenciar Assinatura", + "workspace.lite.subscription.rollingUsage": "Uso Contínuo", + "workspace.lite.subscription.weeklyUsage": "Uso Semanal", + "workspace.lite.subscription.monthlyUsage": "Uso Mensal", + "workspace.lite.subscription.resetsIn": "Reinicia em", + "workspace.lite.subscription.useBalance": "Use seu saldo disponível após atingir os limites de uso", + "workspace.lite.subscription.selectProvider": + 'Selecione "OpenCode Go" como provedor na sua configuração do opencode para usar os modelos Go.', + "workspace.lite.other.title": "Assinatura Go", + "workspace.lite.other.message": + "Outro membro neste workspace já assina o OpenCode Go. Apenas um membro por workspace pode assinar.", + "workspace.lite.promo.title": "OpenCode Go", + "workspace.lite.promo.description": + "O OpenCode Go é uma assinatura de $10 por mês que fornece acesso confiável a modelos abertos de codificação populares com limites de uso generosos.", + "workspace.lite.promo.modelsTitle": "O que está incluído", + "workspace.lite.promo.footer": + "O plano é projetado principalmente para usuários internacionais, com modelos hospedados nos EUA, UE e Singapura para acesso global estável. Preços e limites de uso podem mudar conforme aprendemos com o uso inicial e feedback.", + "workspace.lite.promo.subscribe": "Assinar Go", + "workspace.lite.promo.subscribing": "Redirecionando...", + "download.title": "OpenCode | Baixar", "download.meta.description": "Baixe o OpenCode para macOS, Windows e Linux", "download.hero.title": "Baixar OpenCode", @@ -536,6 +699,10 @@ export const dict = { "enterprise.form.send": "Enviar", "enterprise.form.sending": "Enviando...", "enterprise.form.success": "Mensagem enviada, entraremos em contato em breve.", + "enterprise.form.success.submitted": "Formulário enviado com sucesso.", + "enterprise.form.error.allFieldsRequired": "Todos os campos são obrigatórios.", + "enterprise.form.error.invalidEmailFormat": "Formato de e-mail inválido.", + "enterprise.form.error.internalServer": "Erro interno do servidor.", "enterprise.faq.title": "FAQ", "enterprise.faq.q1": "O que é OpenCode Enterprise?", "enterprise.faq.a1": @@ -568,6 +735,7 @@ export const dict = { "bench.list.table.agent": "Agente", "bench.list.table.model": "Modelo", "bench.list.table.score": "Pontuação", + "bench.submission.error.allFieldsRequired": "Todos os campos são obrigatórios.", "bench.detail.title": "Benchmark - {{task}}", "bench.detail.notFound": "Tarefa não encontrada", diff --git a/packages/console/app/src/i18n/da.ts b/packages/console/app/src/i18n/da.ts index 39f8cfb525..775f029fba 100644 --- a/packages/console/app/src/i18n/da.ts +++ b/packages/console/app/src/i18n/da.ts @@ -15,6 +15,7 @@ export const dict = { "nav.home": "Hjem", "nav.openMenu": "Åbn menu", "nav.getStartedFree": "Kom i gang gratis", + "nav.logoAlt": "OpenCode", "nav.context.copyLogo": "Kopier logo som SVG", "nav.context.copyWordmark": "Kopier wordmark som SVG", @@ -42,9 +43,13 @@ export const dict = { "notFound.docs": "Dokumentation", "notFound.github": "GitHub", "notFound.discord": "Discord", + "notFound.logoLightAlt": "opencode logo light", + "notFound.logoDarkAlt": "opencode logo dark", "user.logout": "Log ud", + "auth.callback.error.codeMissing": "Ingen autorisationskode fundet.", + "workspace.select": "Vælg workspace", "workspace.createNew": "+ Opret nyt workspace", "workspace.modal.title": "Opret nyt workspace", @@ -76,6 +81,8 @@ export const dict = { "error.reloadAmountMin": "Genopfyldningsbeløb skal være mindst ${{amount}}", "error.reloadTriggerMin": "Saldogrænse skal være mindst ${{amount}}", + "app.meta.description": "OpenCode - Den open source kodningsagent.", + "home.title": "OpenCode | Den open source AI-kodningsagent", "temp.title": "opencode | AI-kodningsagent bygget til terminalen", @@ -91,6 +98,8 @@ export const dict = { "temp.feature.models.afterLink": ", inklusive lokale modeller", "temp.screenshot.caption": "opencode TUI med tokyonight-temaet", "temp.screenshot.alt": "opencode TUI med tokyonight-temaet", + "temp.logoLightAlt": "opencode logo light", + "temp.logoDarkAlt": "opencode logo dark", "home.banner.badge": "Ny", "home.banner.text": "Desktop-app tilgængelig i beta", @@ -240,11 +249,129 @@ export const dict = { "Alle Zen-modeller er hostet i USA. Udbydere følger en nulopbevaringspolitik og bruger ikke dine data til modeltræning med", "zen.privacy.exceptionsLink": "følgende undtagelser", + "go.title": "OpenCode Go | Kodningsmodeller til lav pris for alle", + "go.meta.description": + "Go er et abonnement til $10/måned med generøse grænser på 5 timers forespørgsler for GLM-5, Kimi K2.5 og MiniMax M2.5.", + "go.hero.title": "Kodningsmodeller til lav pris for alle", + "go.hero.body": + "Go bringer agentisk kodning til programmører over hele verden. Med generøse grænser og pålidelig adgang til de mest kapable open source-modeller, så du kan bygge med kraftfulde agenter uden at bekymre dig om omkostninger eller tilgængelighed.", + + "go.cta.start": "Abonner på Go", + "go.cta.template": "{{text}} {{price}}", + "go.cta.text": "Abonner på Go", + "go.cta.price": "$10/måned", + "go.pricing.body": "Brug med enhver agent. Genopfyld kredit om nødvendigt. Annuller til enhver tid.", + "go.graph.free": "Gratis", + "go.graph.freePill": "Big Pickle og gratis modeller", + "go.graph.go": "Go", + "go.graph.label": "Forespørgsler pr. 5 timer", + "go.graph.usageLimits": "Brugsgrænser", + "go.graph.tick": "{{n}}x", + "go.graph.aria": "Forespørgsler pr. 5t: {{free}} vs {{go}}", + + "go.testimonials.brand.zen": "Zen", + "go.testimonials.brand.go": "Go", + "go.testimonials.handle": "@OpenCode", + "go.testimonials.dax.name": "Dax Raad", + "go.testimonials.dax.title": "ex-CEO, Terminal Products", + "go.testimonials.dax.quoteAfter": "har været livsændrende, det er virkelig en no-brainer.", + "go.testimonials.jay.name": "Jay V", + "go.testimonials.jay.title": "ex-Founder, SEED, PM, Melt, Pop, Dapt, Cadmus, og ViewPoint", + "go.testimonials.jay.quoteBefore": "4 ud af 5 personer på vores team elsker at bruge", + "go.testimonials.jay.quoteAfter": ".", + "go.testimonials.adam.name": "Adam Elmore", + "go.testimonials.adam.title": "ex-Hero, AWS", + "go.testimonials.adam.quoteBefore": "Jeg kan ikke anbefale", + "go.testimonials.adam.quoteAfter": "nok. Seriøst, det er virkelig godt.", + "go.testimonials.david.name": "David Hill", + "go.testimonials.david.title": "ex-Head of Design, Laravel", + "go.testimonials.david.quoteBefore": "Med", + "go.testimonials.david.quoteAfter": "ved jeg, at alle modellerne er testede og perfekte til kodningsagenter.", + "go.testimonials.frank.name": "Frank Wang", + "go.testimonials.frank.title": "ex-Intern, Nvidia (4 gange)", + "go.testimonials.frank.quote": "Jeg ville ønske, jeg stadig var hos Nvidia.", + "go.problem.title": "Hvilket problem løser Go?", + "go.problem.body": + "Vi fokuserer på at bringe OpenCode-oplevelsen til så mange mennesker som muligt. OpenCode Go er et lavprisabonnement ($10/måned) designet til at bringe agentisk kodning til programmører over hele verden. Det giver generøse grænser og pålidelig adgang til de mest kapable open source-modeller.", + "go.problem.subtitle": " ", + "go.problem.item1": "Lavpris abonnementspriser", + "go.problem.item2": "Generøse grænser og pålidelig adgang", + "go.problem.item3": "Bygget til så mange programmører som muligt", + "go.problem.item4": "Inkluderer GLM-5, Kimi K2.5 og MiniMax M2.5", + "go.how.title": "Hvordan Go virker", + "go.how.body": "Go er et abonnement til $10/måned, som du kan bruge med OpenCode eller enhver anden agent.", + "go.how.step1.title": "Opret en konto", + "go.how.step1.beforeLink": "følg", + "go.how.step1.link": "opsætningsinstruktionerne", + "go.how.step2.title": "Abonner på Go", + "go.how.step2.link": "$10/måned", + "go.how.step2.afterLink": "med generøse grænser", + "go.how.step3.title": "Start kodning", + "go.how.step3.body": "med pålidelig adgang til open source-modeller", + "go.privacy.title": "Dit privatliv er vigtigt for os", + "go.privacy.body": + "Planen er primært designet til internationale brugere, med modeller hostet i USA, EU og Singapore for stabil global adgang.", + "go.privacy.contactAfter": "hvis du har spørgsmål.", + "go.privacy.beforeExceptions": + "Go-modeller hostes i USA. Udbydere følger en nulopbevaringspolitik og bruger ikke dine data til modeltræning, med de", + "go.privacy.exceptionsLink": "følgende undtagelser", + "go.faq.q1": "Hvad er OpenCode Go?", + "go.faq.a1": + "Go er et lavprisabonnement, der giver dig pålidelig adgang til kapable open source-modeller til agentisk kodning.", + "go.faq.q2": "Hvilke modeller inkluderer Go?", + "go.faq.a2": "Go inkluderer GLM-5, Kimi K2.5 og MiniMax M2.5, med generøse grænser og pålidelig adgang.", + "go.faq.q3": "Er Go det samme som Zen?", + "go.faq.a3": + "Nej. Zen er pay-as-you-go, mens Go er et abonnement til $10/måned med generøse grænser og pålidelig adgang til open source-modellerne GLM-5, Kimi K2.5 og MiniMax M2.5.", + "go.faq.q4": "Hvad koster Go?", + "go.faq.a4.p1.beforePricing": "Go koster", + "go.faq.a4.p1.pricingLink": "$10/måned", + "go.faq.a4.p1.afterPricing": "med generøse grænser.", + "go.faq.a4.p2.beforeAccount": "Du kan administrere dit abonnement i din", + "go.faq.a4.p2.accountLink": "konto", + "go.faq.a4.p3": "Annuller til enhver tid.", + "go.faq.q5": "Hvad med data og privatliv?", + "go.faq.a5.body": + "Planen er primært designet til internationale brugere, med modeller hostet i USA, EU og Singapore for stabil global adgang.", + "go.faq.a5.contactAfter": "hvis du har spørgsmål.", + "go.faq.a5.beforeExceptions": + "Go-modeller hostes i USA. Udbydere følger en nulopbevaringspolitik og bruger ikke dine data til modeltræning, med de", + "go.faq.a5.exceptionsLink": "følgende undtagelser", + "go.faq.q6": "Kan jeg tanke kredit op?", + "go.faq.a6": "Hvis du har brug for mere forbrug, kan du tanke kredit op på din konto.", + "go.faq.q7": "Kan jeg annullere?", + "go.faq.a7": "Ja, du kan annullere til enhver tid.", + "go.faq.q8": "Kan jeg bruge Go med andre kodningsagenter?", + "go.faq.a8": "Ja, du kan bruge Go med enhver agent. Følg opsætningsinstruktionerne i din foretrukne kodningsagent.", + + "go.faq.q9": "Hvad er forskellen på gratis modeller og Go?", + "go.faq.a9": + "Gratis modeller inkluderer Big Pickle plus salgsfremmende modeller tilgængelige på det tidspunkt, med en kvote på 200 forespørgsler/dag. Go inkluderer GLM-5, Kimi K2.5 og MiniMax M2.5 med højere anmodningskvoter håndhævet over rullende vinduer (5-timers, ugentlig og månedlig), nogenlunde svarende til $12 pr. 5 timer, $30 pr. uge og $60 pr. måned (faktiske anmodningstal varierer efter model og brug).", + + "zen.api.error.rateLimitExceeded": "Hastighedsgrænse overskredet. Prøv venligst igen senere.", + "zen.api.error.modelNotSupported": "Model {{model}} understøttes ikke", + "zen.api.error.modelFormatNotSupported": "Model {{model}} understøttes ikke for format {{format}}", + "zen.api.error.noProviderAvailable": "Ingen udbyder tilgængelig", + "zen.api.error.providerNotSupported": "Udbyder {{provider}} understøttes ikke", + "zen.api.error.missingApiKey": "Manglende API-nøgle.", + "zen.api.error.invalidApiKey": "Ugyldig API-nøgle.", + "zen.api.error.subscriptionQuotaExceeded": "Abonnementskvote overskredet. Prøv igen om {{retryIn}}.", + "zen.api.error.subscriptionQuotaExceededUseFreeModels": + "Abonnementskvote overskredet. Du kan fortsætte med at bruge gratis modeller.", + "zen.api.error.noPaymentMethod": "Ingen betalingsmetode. Tilføj en betalingsmetode her: {{billingUrl}}", + "zen.api.error.insufficientBalance": "Utilstrækkelig saldo. Administrer din fakturering her: {{billingUrl}}", + "zen.api.error.workspaceMonthlyLimitReached": + "Dit workspace har nået sin månedlige forbrugsgrænse på ${{amount}}. Administrer dine grænser her: {{billingUrl}}", + "zen.api.error.userMonthlyLimitReached": + "Du har nået din månedlige forbrugsgrænse på ${{amount}}. Administrer dine grænser her: {{membersUrl}}", + "zen.api.error.modelDisabled": "Modellen er deaktiveret", + "black.meta.title": "OpenCode Black | Få adgang til verdens bedste kodningsmodeller", "black.meta.description": "Få adgang til Claude, GPT, Gemini og mere med OpenCode Black-abonnementer.", "black.hero.title": "Få adgang til verdens bedste kodningsmodeller", "black.hero.subtitle": "Inklusive Claude, GPT, Gemini og mere", "black.title": "OpenCode Black | Priser", + "black.paused": "Black-plantilmelding er midlertidigt sat på pause.", "black.plan.icon20": "Black 20-plan", "black.plan.icon100": "Black 100-plan", "black.plan.icon200": "Black 200-plan", @@ -340,12 +467,15 @@ export const dict = { "workspace.usage.table.input": "Input", "workspace.usage.table.output": "Output", "workspace.usage.table.cost": "Omkostning", + "workspace.usage.table.session": "Session", "workspace.usage.breakdown.input": "Input", "workspace.usage.breakdown.cacheRead": "Cache læst", "workspace.usage.breakdown.cacheWrite": "Cache skriv", "workspace.usage.breakdown.output": "Output", "workspace.usage.breakdown.reasoning": "Ræsonnement", - "workspace.usage.subscription": "abonnement (${{amount}})", + "workspace.usage.subscription": "Black (${{amount}})", + "workspace.usage.lite": "Go (${{amount}})", + "workspace.usage.byok": "BYOK (${{amount}})", "workspace.cost.title": "Omkostninger", "workspace.cost.subtitle": "Brugsomkostninger opdelt efter model.", @@ -444,6 +574,7 @@ export const dict = { "workspace.reload.updatePaymentMethod": "Opdater din betalingsmetode, og prøv igen.", "workspace.reload.retrying": "Prøver igen...", "workspace.reload.retry": "Prøv igen", + "workspace.reload.error.paymentFailed": "Betaling mislykkedes.", "workspace.payments.title": "Betalingshistorik", "workspace.payments.subtitle": "Seneste betalingstransaktioner.", @@ -482,6 +613,36 @@ export const dict = { "workspace.black.waitlist.enrollNote": "Når du klikker på Tilmeld, starter dit abonnement med det samme, og dit kort vil blive debiteret.", + "workspace.lite.loading": "Indlæser...", + "workspace.lite.time.day": "dag", + "workspace.lite.time.days": "dage", + "workspace.lite.time.hour": "time", + "workspace.lite.time.hours": "timer", + "workspace.lite.time.minute": "minut", + "workspace.lite.time.minutes": "minutter", + "workspace.lite.time.fewSeconds": "et par sekunder", + "workspace.lite.subscription.title": "Go-abonnement", + "workspace.lite.subscription.message": "Du abonnerer på OpenCode Go.", + "workspace.lite.subscription.manage": "Administrer abonnement", + "workspace.lite.subscription.rollingUsage": "Løbende forbrug", + "workspace.lite.subscription.weeklyUsage": "Ugentligt forbrug", + "workspace.lite.subscription.monthlyUsage": "Månedligt forbrug", + "workspace.lite.subscription.resetsIn": "Nulstiller i", + "workspace.lite.subscription.useBalance": "Brug din tilgængelige saldo, når du har nået forbrugsgrænserne", + "workspace.lite.subscription.selectProvider": + 'Vælg "OpenCode Go" som udbyder i din opencode-konfiguration for at bruge Go-modeller.', + "workspace.lite.other.title": "Go-abonnement", + "workspace.lite.other.message": + "Et andet medlem i dette workspace abonnerer allerede på OpenCode Go. Kun ét medlem pr. workspace kan abonnere.", + "workspace.lite.promo.title": "OpenCode Go", + "workspace.lite.promo.description": + "OpenCode Go er et abonnement til $10 om måneden, der giver pålidelig adgang til populære åbne kodningsmodeller med generøse forbrugsgrænser.", + "workspace.lite.promo.modelsTitle": "Hvad er inkluderet", + "workspace.lite.promo.footer": + "Planen er primært designet til internationale brugere, med modeller hostet i USA, EU og Singapore for stabil global adgang. Priser og forbrugsgrænser kan ændre sig, efterhånden som vi lærer af tidlig brug og feedback.", + "workspace.lite.promo.subscribe": "Abonner på Go", + "workspace.lite.promo.subscribing": "Omdirigerer...", + "download.title": "OpenCode | Download", "download.meta.description": "Download OpenCode til macOS, Windows og Linux", "download.hero.title": "Download OpenCode", @@ -532,6 +693,10 @@ export const dict = { "enterprise.form.send": "Send", "enterprise.form.sending": "Sender...", "enterprise.form.success": "Besked sendt, vi vender tilbage snart.", + "enterprise.form.success.submitted": "Formular indsendt med succes.", + "enterprise.form.error.allFieldsRequired": "Alle felter er påkrævet.", + "enterprise.form.error.invalidEmailFormat": "Ugyldigt e-mailformat.", + "enterprise.form.error.internalServer": "Intern serverfejl.", "enterprise.faq.title": "FAQ", "enterprise.faq.q1": "Hvad er OpenCode Enterprise?", "enterprise.faq.a1": @@ -564,6 +729,7 @@ export const dict = { "bench.list.table.agent": "Agent", "bench.list.table.model": "Model", "bench.list.table.score": "Score", + "bench.submission.error.allFieldsRequired": "Alle felter er påkrævet.", "bench.detail.title": "Benchmark - {{task}}", "bench.detail.notFound": "Opgave ikke fundet", diff --git a/packages/console/app/src/i18n/de.ts b/packages/console/app/src/i18n/de.ts index 733f38ca5f..2d9be14ff7 100644 --- a/packages/console/app/src/i18n/de.ts +++ b/packages/console/app/src/i18n/de.ts @@ -15,6 +15,7 @@ export const dict = { "nav.home": "Startseite", "nav.openMenu": "Menü öffnen", "nav.getStartedFree": "Kostenlos starten", + "nav.logoAlt": "OpenCode", "nav.context.copyLogo": "Logo als SVG kopieren", "nav.context.copyWordmark": "Wortmarke als SVG kopieren", @@ -42,9 +43,13 @@ export const dict = { "notFound.docs": "Dokumentation", "notFound.github": "GitHub", "notFound.discord": "Discord", + "notFound.logoLightAlt": "OpenCode Logo hell", + "notFound.logoDarkAlt": "OpenCode Logo dunkel", "user.logout": "Abmelden", + "auth.callback.error.codeMissing": "Kein Autorisierungscode gefunden.", + "workspace.select": "Workspace auswählen", "workspace.createNew": "+ Neuen Workspace erstellen", "workspace.modal.title": "Neuen Workspace erstellen", @@ -76,6 +81,8 @@ export const dict = { "error.reloadAmountMin": "Aufladebetrag muss mindestens ${{amount}} betragen", "error.reloadTriggerMin": "Guthaben-Auslöser muss mindestens ${{amount}} betragen", + "app.meta.description": "OpenCode - Der Open-Source Coding-Agent.", + "home.title": "OpenCode | Der Open-Source AI-Coding-Agent", "temp.title": "OpenCode | Für das Terminal gebauter AI-Coding-Agent", @@ -91,6 +98,8 @@ export const dict = { "temp.feature.models.afterLink": ", einschließlich lokaler Modelle", "temp.screenshot.caption": "OpenCode TUI mit dem Tokyonight-Theme", "temp.screenshot.alt": "OpenCode TUI mit Tokyonight-Theme", + "temp.logoLightAlt": "OpenCode Logo hell", + "temp.logoDarkAlt": "OpenCode Logo dunkel", "home.banner.badge": "Neu", "home.banner.text": "Desktop-App in der Beta verfügbar", @@ -242,11 +251,130 @@ export const dict = { "Alle Zen-Modelle werden in den USA gehostet. Anbieter folgen einer Zero-Retention-Policy und nutzen deine Daten nicht für Modelltraining, mit den", "zen.privacy.exceptionsLink": "folgenden Ausnahmen", + "go.title": "OpenCode Go | Kostengünstige Coding-Modelle für alle", + "go.meta.description": + "Go ist ein Abonnement für $10/Monat mit großzügigen 5-Stunden-Limits für GLM-5, Kimi K2.5 und MiniMax M2.5.", + "go.hero.title": "Kostengünstige Coding-Modelle für alle", + "go.hero.body": + "Go bringt Agentic Coding zu Programmierern auf der ganzen Welt. Mit großzügigen Limits und zuverlässigem Zugang zu den leistungsfähigsten Open-Source-Modellen, damit du mit leistungsstarken Agenten entwickeln kannst, ohne dir Gedanken über Kosten oder Verfügbarkeit zu machen.", + + "go.cta.start": "Go abonnieren", + "go.cta.template": "{{text}} {{price}}", + "go.cta.text": "Go abonnieren", + "go.cta.price": "$10/Monat", + "go.pricing.body": "Nutzung mit jedem Agenten. Guthaben bei Bedarf aufladen. Jederzeit kündbar.", + "go.graph.free": "Kostenlos", + "go.graph.freePill": "Big Pickle und kostenlose Modelle", + "go.graph.go": "Go", + "go.graph.label": "Anfragen pro 5 Stunden", + "go.graph.usageLimits": "Nutzungslimits", + "go.graph.tick": "{{n}}x", + "go.graph.aria": "Anfragen pro 5h: {{free}} vs {{go}}", + + "go.testimonials.brand.zen": "Zen", + "go.testimonials.brand.go": "Go", + "go.testimonials.handle": "@OpenCode", + "go.testimonials.dax.name": "Dax Raad", + "go.testimonials.dax.title": "ex-CEO, Terminal Products", + "go.testimonials.dax.quoteAfter": "hat mein Leben verändert, es ist wirklich ein No-Brainer.", + "go.testimonials.jay.name": "Jay V", + "go.testimonials.jay.title": "ex-Gründer, SEED, PM, Melt, Pop, Dapt, Cadmus und ViewPoint", + "go.testimonials.jay.quoteBefore": "4 von 5 Leuten in unserem Team lieben die Nutzung von", + "go.testimonials.jay.quoteAfter": ".", + "go.testimonials.adam.name": "Adam Elmore", + "go.testimonials.adam.title": "ex-Hero, AWS", + "go.testimonials.adam.quoteBefore": "Ich kann", + "go.testimonials.adam.quoteAfter": "nicht genug empfehlen. Ernsthaft, es ist wirklich gut.", + "go.testimonials.david.name": "David Hill", + "go.testimonials.david.title": "ex-Head of Design, Laravel", + "go.testimonials.david.quoteBefore": "Mit", + "go.testimonials.david.quoteAfter": "weiß ich, dass alle Modelle getestet und perfekt für Coding-Agenten sind.", + "go.testimonials.frank.name": "Frank Wang", + "go.testimonials.frank.title": "ex-Praktikant, Nvidia (4 mal)", + "go.testimonials.frank.quote": "Ich wünschte, ich wäre noch bei Nvidia.", + "go.problem.title": "Welches Problem löst Go?", + "go.problem.body": + "Wir konzentrieren uns darauf, die OpenCode-Erfahrung so vielen Menschen wie möglich zugänglich zu machen. OpenCode Go ist ein kostengünstiges ($10/Monat) Abonnement, das entwickelt wurde, um Agentic Coding zu Programmierern auf der ganzen Welt zu bringen. Es bietet großzügige Limits und zuverlässigen Zugang zu den leistungsfähigsten Open-Source-Modellen.", + "go.problem.subtitle": " ", + "go.problem.item1": "Kostengünstiges Abonnement", + "go.problem.item2": "Großzügige Limits und zuverlässiger Zugang", + "go.problem.item3": "Für so viele Programmierer wie möglich gebaut", + "go.problem.item4": "Beinhaltet GLM-5, Kimi K2.5 und MiniMax M2.5", + "go.how.title": "Wie Go funktioniert", + "go.how.body": "Go ist ein Abonnement für $10/Monat, das du mit OpenCode oder jedem anderen Agenten nutzen kannst.", + "go.how.step1.title": "Konto erstellen", + "go.how.step1.beforeLink": "folge den", + "go.how.step1.link": "Einrichtungsanweisungen", + "go.how.step2.title": "Go abonnieren", + "go.how.step2.link": "$10/Monat", + "go.how.step2.afterLink": "mit großzügigen Limits", + "go.how.step3.title": "Loslegen mit Coding", + "go.how.step3.body": "mit zuverlässigem Zugang zu Open-Source-Modellen", + "go.privacy.title": "Deine Privatsphäre ist uns wichtig", + "go.privacy.body": + "Der Plan ist primär für internationale Nutzer konzipiert, mit Modellen gehostet in den USA, der EU und Singapur für stabilen globalen Zugang.", + "go.privacy.contactAfter": "wenn du Fragen hast.", + "go.privacy.beforeExceptions": + "Go-Modelle werden in den USA gehostet. Anbieter verfolgen eine Zero-Retention-Politik und nutzen deine Daten nicht für das Training von Modellen, mit den", + "go.privacy.exceptionsLink": "folgenden Ausnahmen", + "go.faq.q1": "Was ist OpenCode Go?", + "go.faq.a1": + "Go ist ein kostengünstiges Abonnement, das dir zuverlässigen Zugang zu leistungsfähigen Open-Source-Modellen für Agentic Coding bietet.", + "go.faq.q2": "Welche Modelle beinhaltet Go?", + "go.faq.a2": "Go beinhaltet GLM-5, Kimi K2.5 und MiniMax M2.5, mit großzügigen Limits und zuverlässigem Zugang.", + "go.faq.q3": "Ist Go dasselbe wie Zen?", + "go.faq.a3": + "Nein. Zen ist Pay-as-you-go, während Go ein Abonnement für $10/Monat mit großzügigen Limits und zuverlässigem Zugang zu den Open-Source-Modellen GLM-5, Kimi K2.5 und MiniMax M2.5 ist.", + "go.faq.q4": "Wie viel kostet Go?", + "go.faq.a4.p1.beforePricing": "Go kostet", + "go.faq.a4.p1.pricingLink": "$10/Monat", + "go.faq.a4.p1.afterPricing": "mit großzügigen Limits.", + "go.faq.a4.p2.beforeAccount": "Du kannst dein Abonnement in deinem", + "go.faq.a4.p2.accountLink": "Konto verwalten", + "go.faq.a4.p3": "Jederzeit kündbar.", + "go.faq.q5": "Was ist mit Daten und Privatsphäre?", + "go.faq.a5.body": + "Der Plan ist primär für internationale Nutzer konzipiert, mit Modellen gehostet in den USA, der EU und Singapur für stabilen globalen Zugang.", + "go.faq.a5.contactAfter": "wenn du Fragen hast.", + "go.faq.a5.beforeExceptions": + "Go-Modelle werden in den USA gehostet. Anbieter verfolgen eine Zero-Retention-Politik und nutzen deine Daten nicht für das Training von Modellen, mit den", + "go.faq.a5.exceptionsLink": "folgenden Ausnahmen", + "go.faq.q6": "Kann ich Guthaben aufladen?", + "go.faq.a6": "Wenn du mehr Nutzung benötigst, kannst du Guthaben in deinem Konto aufladen.", + "go.faq.q7": "Kann ich kündigen?", + "go.faq.a7": "Ja, du kannst jederzeit kündigen.", + "go.faq.q8": "Kann ich Go mit anderen Coding-Agenten nutzen?", + "go.faq.a8": + "Ja, du kannst Go mit jedem Agenten nutzen. Folge den Einrichtungsanweisungen in deinem bevorzugten Coding-Agenten.", + + "go.faq.q9": "Was ist der Unterschied zwischen kostenlosen Modellen und Go?", + "go.faq.a9": + "Kostenlose Modelle beinhalten Big Pickle sowie Werbemodelle, die zum jeweiligen Zeitpunkt verfügbar sind, mit einem Kontingent von 200 Anfragen/Tag. Go beinhaltet GLM-5, Kimi K2.5 und MiniMax M2.5 mit höheren Anfragekontingenten, die über rollierende Zeitfenster (5 Stunden, wöchentlich und monatlich) durchgesetzt werden, grob äquivalent zu $12 pro 5 Stunden, $30 pro Woche und $60 pro Monat (tatsächliche Anfragezahlen variieren je nach Modell und Nutzung).", + + "zen.api.error.rateLimitExceeded": "Ratenlimit überschritten. Bitte versuche es später erneut.", + "zen.api.error.modelNotSupported": "Modell {{model}} wird nicht unterstützt", + "zen.api.error.modelFormatNotSupported": "Modell {{model}} wird für das Format {{format}} nicht unterstützt", + "zen.api.error.noProviderAvailable": "Kein Anbieter verfügbar", + "zen.api.error.providerNotSupported": "Anbieter {{provider}} wird nicht unterstützt", + "zen.api.error.missingApiKey": "Fehlender API-Key.", + "zen.api.error.invalidApiKey": "Ungültiger API-Key.", + "zen.api.error.subscriptionQuotaExceeded": "Abonnement-Quote überschritten. Erneuter Versuch in {{retryIn}}.", + "zen.api.error.subscriptionQuotaExceededUseFreeModels": + "Abonnement-Quote überschritten. Du kannst weiterhin kostenlose Modelle nutzen.", + "zen.api.error.noPaymentMethod": "Keine Zahlungsmethode. Füge hier eine Zahlungsmethode hinzu: {{billingUrl}}", + "zen.api.error.insufficientBalance": "Unzureichendes Guthaben. Verwalte deine Abrechnung hier: {{billingUrl}}", + "zen.api.error.workspaceMonthlyLimitReached": + "Dein Workspace hat sein monatliches Ausgabenlimit von ${{amount}} erreicht. Verwalte deine Limits hier: {{billingUrl}}", + "zen.api.error.userMonthlyLimitReached": + "Du hast dein monatliches Ausgabenlimit von ${{amount}} erreicht. Verwalte deine Limits hier: {{membersUrl}}", + "zen.api.error.modelDisabled": "Modell ist deaktiviert", + "black.meta.title": "OpenCode Black | Zugriff auf die weltweit besten Coding-Modelle", "black.meta.description": "Erhalte Zugriff auf Claude, GPT, Gemini und mehr mit OpenCode Black Abos.", "black.hero.title": "Zugriff auf die weltweit besten Coding-Modelle", "black.hero.subtitle": "Einschließlich Claude, GPT, Gemini und mehr", "black.title": "OpenCode Black | Preise", + "black.paused": "Die Anmeldung zum Black-Plan ist vorübergehend pausiert.", "black.plan.icon20": "Black 20 Plan", "black.plan.icon100": "Black 100 Plan", "black.plan.icon200": "Black 200 Plan", @@ -342,12 +470,15 @@ export const dict = { "workspace.usage.table.input": "Input", "workspace.usage.table.output": "Output", "workspace.usage.table.cost": "Kosten", + "workspace.usage.table.session": "Sitzung", "workspace.usage.breakdown.input": "Input", "workspace.usage.breakdown.cacheRead": "Cache Read", "workspace.usage.breakdown.cacheWrite": "Cache Write", "workspace.usage.breakdown.output": "Output", "workspace.usage.breakdown.reasoning": "Reasoning", - "workspace.usage.subscription": "Abonnement (${{amount}})", + "workspace.usage.subscription": "Black (${{amount}})", + "workspace.usage.lite": "Go (${{amount}})", + "workspace.usage.byok": "BYOK (${{amount}})", "workspace.cost.title": "Kosten", "workspace.cost.subtitle": "Nutzungskosten aufgeschlüsselt nach Modell.", @@ -446,6 +577,7 @@ export const dict = { "workspace.reload.updatePaymentMethod": "Bitte aktualisiere deine Zahlungsmethode und versuche es erneut.", "workspace.reload.retrying": "Versuche erneut...", "workspace.reload.retry": "Erneut versuchen", + "workspace.reload.error.paymentFailed": "Zahlung fehlgeschlagen.", "workspace.payments.title": "Zahlungshistorie", "workspace.payments.subtitle": "Kürzliche Zahlungstransaktionen.", @@ -484,6 +616,36 @@ export const dict = { "workspace.black.waitlist.enrollNote": "Wenn du auf Einschreiben klickst, startet dein Abo sofort und deine Karte wird belastet.", + "workspace.lite.loading": "Lade...", + "workspace.lite.time.day": "Tag", + "workspace.lite.time.days": "Tage", + "workspace.lite.time.hour": "Stunde", + "workspace.lite.time.hours": "Stunden", + "workspace.lite.time.minute": "Minute", + "workspace.lite.time.minutes": "Minuten", + "workspace.lite.time.fewSeconds": "einige Sekunden", + "workspace.lite.subscription.title": "Go-Abonnement", + "workspace.lite.subscription.message": "Du hast OpenCode Go abonniert.", + "workspace.lite.subscription.manage": "Abo verwalten", + "workspace.lite.subscription.rollingUsage": "Fortlaufende Nutzung", + "workspace.lite.subscription.weeklyUsage": "Wöchentliche Nutzung", + "workspace.lite.subscription.monthlyUsage": "Monatliche Nutzung", + "workspace.lite.subscription.resetsIn": "Setzt zurück in", + "workspace.lite.subscription.useBalance": "Nutze dein verfügbares Guthaben, nachdem die Nutzungslimits erreicht sind", + "workspace.lite.subscription.selectProvider": + 'Wähle "OpenCode Go" als Anbieter in deiner opencode-Konfiguration, um Go-Modelle zu verwenden.', + "workspace.lite.other.title": "Go-Abonnement", + "workspace.lite.other.message": + "Ein anderes Mitglied in diesem Workspace hat OpenCode Go bereits abonniert. Nur ein Mitglied pro Workspace kann abonnieren.", + "workspace.lite.promo.title": "OpenCode Go", + "workspace.lite.promo.description": + "OpenCode Go ist ein Abonnement für $10 pro Monat, das zuverlässigen Zugriff auf beliebte offene Coding-Modelle mit großzügigen Nutzungslimits bietet.", + "workspace.lite.promo.modelsTitle": "Was enthalten ist", + "workspace.lite.promo.footer": + "Der Plan wurde hauptsächlich für internationale Nutzer entwickelt, wobei die Modelle in den USA, der EU und Singapur gehostet werden, um einen stabilen weltweiten Zugriff zu gewährleisten. Preise und Nutzungslimits können sich ändern, während wir aus der frühen Nutzung und dem Feedback lernen.", + "workspace.lite.promo.subscribe": "Go abonnieren", + "workspace.lite.promo.subscribing": "Leite weiter...", + "download.title": "OpenCode | Download", "download.meta.description": "Lade OpenCode für macOS, Windows und Linux herunter", "download.hero.title": "OpenCode herunterladen", @@ -536,6 +698,10 @@ export const dict = { "enterprise.form.send": "Senden", "enterprise.form.sending": "Sende...", "enterprise.form.success": "Nachricht gesendet, wir melden uns bald.", + "enterprise.form.success.submitted": "Formular erfolgreich gesendet.", + "enterprise.form.error.allFieldsRequired": "Alle Felder sind erforderlich.", + "enterprise.form.error.invalidEmailFormat": "Ungültiges E-Mail-Format.", + "enterprise.form.error.internalServer": "Interner Serverfehler.", "enterprise.faq.title": "FAQ", "enterprise.faq.q1": "Was ist OpenCode Enterprise?", "enterprise.faq.a1": @@ -568,6 +734,7 @@ export const dict = { "bench.list.table.agent": "Agent", "bench.list.table.model": "Modell", "bench.list.table.score": "Score", + "bench.submission.error.allFieldsRequired": "Alle Felder sind erforderlich.", "bench.detail.title": "Benchmark - {{task}}", "bench.detail.notFound": "Task nicht gefunden", diff --git a/packages/console/app/src/i18n/en.ts b/packages/console/app/src/i18n/en.ts index 08c716aba3..2a279757b3 100644 --- a/packages/console/app/src/i18n/en.ts +++ b/packages/console/app/src/i18n/en.ts @@ -6,11 +6,13 @@ export const dict = { "nav.x": "X", "nav.enterprise": "Enterprise", "nav.zen": "Zen", + "nav.go": "Go", "nav.login": "Login", "nav.free": "Free", "nav.home": "Home", "nav.openMenu": "Open menu", "nav.getStartedFree": "Get started for free", + "nav.logoAlt": "OpenCode", "nav.context.copyLogo": "Copy logo as SVG", "nav.context.copyWordmark": "Copy wordmark as SVG", @@ -38,9 +40,13 @@ export const dict = { "notFound.docs": "Docs", "notFound.github": "GitHub", "notFound.discord": "Discord", + "notFound.logoLightAlt": "opencode logo light", + "notFound.logoDarkAlt": "opencode logo dark", "user.logout": "Logout", + "auth.callback.error.codeMissing": "No authorization code found.", + "workspace.select": "Select workspace", "workspace.createNew": "+ Create New Workspace", "workspace.modal.title": "Create New Workspace", @@ -49,6 +55,7 @@ export const dict = { "common.cancel": "Cancel", "common.creating": "Creating...", "common.create": "Create", + "common.contactUs": "Contact us", "common.videoUnsupported": "Your browser does not support the video tag.", "common.figure": "Fig {{n}}.", @@ -72,6 +79,8 @@ export const dict = { "error.reloadAmountMin": "Reload amount must be at least ${{amount}}", "error.reloadTriggerMin": "Balance trigger must be at least ${{amount}}", + "app.meta.description": "OpenCode - The open source coding agent.", + "home.title": "OpenCode | The open source AI coding agent", "temp.title": "opencode | AI coding agent built for the terminal", @@ -87,6 +96,8 @@ export const dict = { "temp.feature.models.afterLink": ", including local models", "temp.screenshot.caption": "opencode TUI with the tokyonight theme", "temp.screenshot.alt": "opencode TUI with tokyonight theme", + "temp.logoLightAlt": "opencode logo light", + "temp.logoDarkAlt": "opencode logo dark", "home.banner.badge": "New", "home.banner.text": "Desktop app available in beta", @@ -234,11 +245,129 @@ export const dict = { "All Zen models are hosted in the US. Providers follow a zero-retention policy and do not use your data for model training, with the", "zen.privacy.exceptionsLink": "following exceptions", + "go.title": "OpenCode Go | Low cost coding models for everyone", + "go.meta.description": + "Go is a $10/month subscription with generous 5-hour request limits for GLM-5, Kimi K2.5, and MiniMax M2.5.", + "go.hero.title": "Low cost coding models for everyone", + "go.hero.body": + "Go brings agentic coding to programmers around the world. Offering generous limits and reliable access to the most capable open-source models, so you can build with powerful agents without worrying about cost or availability.", + + "go.cta.start": "Subscribe to Go", + "go.cta.template": "{{text}} {{price}}", + "go.cta.text": "Subscribe to Go", + "go.cta.price": "$10/month", + "go.pricing.body": "Use with any agent. Top up credit if needed. Cancel any time.", + "go.graph.free": "Free", + "go.graph.freePill": "Big Pickle and free models", + "go.graph.go": "Go", + "go.graph.label": "Requests per 5 hour", + "go.graph.usageLimits": "Usage limits", + "go.graph.tick": "{{n}}x", + "go.graph.aria": "Requests per 5h: {{free}} vs {{go}}", + + "go.testimonials.brand.zen": "Zen", + "go.testimonials.brand.go": "Go", + "go.testimonials.handle": "@OpenCode", + "go.testimonials.dax.name": "Dax Raad", + "go.testimonials.dax.title": "ex-CEO, Terminal Products", + "go.testimonials.dax.quoteAfter": "has been life changing, it's truly a no-brainer.", + "go.testimonials.jay.name": "Jay V", + "go.testimonials.jay.title": "ex-Founder, SEED, PM, Melt, Pop, Dapt, Cadmus, and ViewPoint", + "go.testimonials.jay.quoteBefore": "4 out of 5 people on our team love using", + "go.testimonials.jay.quoteAfter": ".", + "go.testimonials.adam.name": "Adam Elmore", + "go.testimonials.adam.title": "ex-Hero, AWS", + "go.testimonials.adam.quoteBefore": "I can't recommend", + "go.testimonials.adam.quoteAfter": "enough. Seriously, it's really good.", + "go.testimonials.david.name": "David Hill", + "go.testimonials.david.title": "ex-Head of Design, Laravel", + "go.testimonials.david.quoteBefore": "With", + "go.testimonials.david.quoteAfter": "I know all the models are tested and perfect for coding agents.", + "go.testimonials.frank.name": "Frank Wang", + "go.testimonials.frank.title": "ex-Intern, Nvidia (4 times)", + "go.testimonials.frank.quote": "I wish I was still at Nvidia.", + "go.problem.title": "What problem is Go solving?", + "go.problem.body": + "We're focused on bringing the OpenCode experience to as many people as possible. OpenCode Go is a low cost ($10/month) subscription designed to bring agentic coding to programmers around the world. It provides generous limits and reliable access to the most capable open source models.", + "go.problem.subtitle": " ", + "go.problem.item1": "Low cost subscription pricing", + "go.problem.item2": "Generous limits and reliable access", + "go.problem.item3": "Built for as many programmers as possible", + "go.problem.item4": "Includes GLM-5, Kimi K2.5, and MiniMax M2.5", + "go.how.title": "How Go works", + "go.how.body": "Go is a $10/month subscription you can use with OpenCode or any agent.", + "go.how.step1.title": "Create an account", + "go.how.step1.beforeLink": "follow the", + "go.how.step1.link": "setup instructions", + "go.how.step2.title": "Subscribe to Go", + "go.how.step2.link": "$10/month", + "go.how.step2.afterLink": "with generous limits", + "go.how.step3.title": "Start coding", + "go.how.step3.body": "with reliable access to open-source models", + "go.privacy.title": "Your privacy is important to us", + "go.privacy.body": + "The plan is designed primarily for international users, with models hosted in the US, EU, and Singapore for stable global access.", + "go.privacy.contactAfter": "if you have any questions.", + "go.privacy.beforeExceptions": + "Go models are hosted in the US. Providers follow a zero-retention policy and do not use your data for model training, with the", + "go.privacy.exceptionsLink": "following exceptions", + "go.faq.q1": "What is OpenCode Go?", + "go.faq.a1": + "Go is a low-cost subscription that gives you reliable access to capable open-source models for agentic coding.", + "go.faq.q2": "What models does Go include?", + "go.faq.a2": "Go includes GLM-5, Kimi K2.5, and MiniMax M2.5, with generous limits and reliable access.", + "go.faq.q3": "Is Go the same as Zen?", + "go.faq.a3": + "No. Zen is pay-as-you-go, while Go is a $10/month subscription with generous limits and reliable access to open-source models GLM-5, Kimi K2.5, and MiniMax M2.5.", + "go.faq.q4": "How much does Go cost?", + "go.faq.a4.p1.beforePricing": "Go costs", + "go.faq.a4.p1.pricingLink": "$10/month", + "go.faq.a4.p1.afterPricing": "with generous limits.", + "go.faq.a4.p2.beforeAccount": "You can manage your subscription in your", + "go.faq.a4.p2.accountLink": "account", + "go.faq.a4.p3": "Cancel any time.", + "go.faq.q5": "What about data and privacy?", + "go.faq.a5.body": + "The plan is designed primarily for international users, with models hosted in the US, EU, and Singapore for stable global access.", + "go.faq.a5.contactAfter": "if you have any questions.", + "go.faq.a5.beforeExceptions": + "Go models are hosted in the US. Providers follow a zero-retention policy and do not use your data for model training, with the", + "go.faq.a5.exceptionsLink": "following exceptions", + "go.faq.q6": "Can I top up credit?", + "go.faq.a6": "If you need more usage, you can top up credit in your account.", + "go.faq.q7": "Can I cancel?", + "go.faq.a7": "Yes, you can cancel any time.", + "go.faq.q8": "Can I use Go with other coding agents?", + "go.faq.a8": "Yes, you can use Go with any agent. Follow the setup instructions in your preferred coding agent.", + + "go.faq.q9": "What is the difference between free models and Go?", + "go.faq.a9": + "Free models include Big Pickle plus promotional models available at the time, with a quota of 200 requests/day. Go includes GLM-5, Kimi K2.5, and MiniMax M2.5 with higher request quotas enforced across rolling windows (5-hour, weekly, and monthly), roughly equivalent to $12 per 5 hours, $30 per week, and $60 per month (actual request counts vary by model and usage).", + + "zen.api.error.rateLimitExceeded": "Rate limit exceeded. Please try again later.", + "zen.api.error.modelNotSupported": "Model {{model}} not supported", + "zen.api.error.modelFormatNotSupported": "Model {{model}} not supported for format {{format}}", + "zen.api.error.noProviderAvailable": "No provider available", + "zen.api.error.providerNotSupported": "Provider {{provider}} not supported", + "zen.api.error.missingApiKey": "Missing API key.", + "zen.api.error.invalidApiKey": "Invalid API key.", + "zen.api.error.subscriptionQuotaExceeded": "Subscription quota exceeded. Retry in {{retryIn}}.", + "zen.api.error.subscriptionQuotaExceededUseFreeModels": + "Subscription quota exceeded. You can continue using free models.", + "zen.api.error.noPaymentMethod": "No payment method. Add a payment method here: {{billingUrl}}", + "zen.api.error.insufficientBalance": "Insufficient balance. Manage your billing here: {{billingUrl}}", + "zen.api.error.workspaceMonthlyLimitReached": + "Your workspace has reached its monthly spending limit of ${{amount}}. Manage your limits here: {{billingUrl}}", + "zen.api.error.userMonthlyLimitReached": + "You have reached your monthly spending limit of ${{amount}}. Manage your limits here: {{membersUrl}}", + "zen.api.error.modelDisabled": "Model is disabled", + "black.meta.title": "OpenCode Black | Access all the world's best coding models", "black.meta.description": "Get access to Claude, GPT, Gemini and more with OpenCode Black subscription plans.", "black.hero.title": "Access all the world's best coding models", "black.hero.subtitle": "Including Claude, GPT, Gemini and more", "black.title": "OpenCode Black | Pricing", + "black.paused": "Black plan enrollment is temporarily paused.", "black.plan.icon20": "Black 20 plan", "black.plan.icon100": "Black 100 plan", "black.plan.icon200": "Black 200 plan", @@ -334,12 +463,15 @@ export const dict = { "workspace.usage.table.input": "Input", "workspace.usage.table.output": "Output", "workspace.usage.table.cost": "Cost", + "workspace.usage.table.session": "Session", "workspace.usage.breakdown.input": "Input", "workspace.usage.breakdown.cacheRead": "Cache Read", "workspace.usage.breakdown.cacheWrite": "Cache Write", "workspace.usage.breakdown.output": "Output", "workspace.usage.breakdown.reasoning": "Reasoning", - "workspace.usage.subscription": "subscription (${{amount}})", + "workspace.usage.subscription": "Black (${{amount}})", + "workspace.usage.lite": "Go (${{amount}})", + "workspace.usage.byok": "BYOK (${{amount}})", "workspace.cost.title": "Cost", "workspace.cost.subtitle": "Usage costs broken down by model.", @@ -438,6 +570,7 @@ export const dict = { "workspace.reload.updatePaymentMethod": "Please update your payment method and try again.", "workspace.reload.retrying": "Retrying...", "workspace.reload.retry": "Retry", + "workspace.reload.error.paymentFailed": "Payment failed.", "workspace.payments.title": "Payments History", "workspace.payments.subtitle": "Recent payment transactions.", @@ -476,6 +609,36 @@ export const dict = { "workspace.black.waitlist.enrollNote": "When you click Enroll, your subscription starts immediately and your card will be charged.", + "workspace.lite.loading": "Loading...", + "workspace.lite.time.day": "day", + "workspace.lite.time.days": "days", + "workspace.lite.time.hour": "hour", + "workspace.lite.time.hours": "hours", + "workspace.lite.time.minute": "minute", + "workspace.lite.time.minutes": "minutes", + "workspace.lite.time.fewSeconds": "a few seconds", + "workspace.lite.subscription.title": "Go Subscription", + "workspace.lite.subscription.message": "You are subscribed to OpenCode Go.", + "workspace.lite.subscription.manage": "Manage Subscription", + "workspace.lite.subscription.rollingUsage": "Rolling Usage", + "workspace.lite.subscription.weeklyUsage": "Weekly Usage", + "workspace.lite.subscription.monthlyUsage": "Monthly Usage", + "workspace.lite.subscription.resetsIn": "Resets in", + "workspace.lite.subscription.useBalance": "Use your available balance after reaching the usage limits", + "workspace.lite.subscription.selectProvider": + 'Select "OpenCode Go" as the provider in your opencode configuration to use Go models.', + "workspace.lite.other.title": "Go Subscription", + "workspace.lite.other.message": + "Another member in this workspace is already subscribed to OpenCode Go. Only one member per workspace can subscribe.", + "workspace.lite.promo.title": "OpenCode Go", + "workspace.lite.promo.description": + "OpenCode Go is a $10 per month subscription that provides reliable access to popular open coding models with generous usage limits.", + "workspace.lite.promo.modelsTitle": "What's Included", + "workspace.lite.promo.footer": + "The plan is designed primarily for international users, with models hosted in the US, EU, and Singapore for stable global access. Pricing and usage limits may change as we learn from early usage and feedback.", + "workspace.lite.promo.subscribe": "Subscribe to Go", + "workspace.lite.promo.subscribing": "Redirecting...", + "download.title": "OpenCode | Download", "download.meta.description": "Download OpenCode for macOS, Windows, and Linux", "download.hero.title": "Download OpenCode", @@ -526,6 +689,10 @@ export const dict = { "enterprise.form.send": "Send", "enterprise.form.sending": "Sending...", "enterprise.form.success": "Message sent, we'll be in touch soon.", + "enterprise.form.success.submitted": "Form submitted successfully.", + "enterprise.form.error.allFieldsRequired": "All fields are required.", + "enterprise.form.error.invalidEmailFormat": "Invalid email format.", + "enterprise.form.error.internalServer": "Internal server error.", "enterprise.faq.title": "FAQ", "enterprise.faq.q1": "What is OpenCode Enterprise?", "enterprise.faq.a1": @@ -558,6 +725,7 @@ export const dict = { "bench.list.table.agent": "Agent", "bench.list.table.model": "Model", "bench.list.table.score": "Score", + "bench.submission.error.allFieldsRequired": "All fields are required.", "bench.detail.title": "Benchmark - {{task}}", "bench.detail.notFound": "Task not found", diff --git a/packages/console/app/src/i18n/es.ts b/packages/console/app/src/i18n/es.ts index 1a18a872eb..25b8d37d7c 100644 --- a/packages/console/app/src/i18n/es.ts +++ b/packages/console/app/src/i18n/es.ts @@ -15,6 +15,7 @@ export const dict = { "nav.home": "Inicio", "nav.openMenu": "Abrir menú", "nav.getStartedFree": "Empezar gratis", + "nav.logoAlt": "OpenCode", "nav.context.copyLogo": "Copiar logo como SVG", "nav.context.copyWordmark": "Copiar marca como SVG", @@ -42,9 +43,13 @@ export const dict = { "notFound.docs": "Documentación", "notFound.github": "GitHub", "notFound.discord": "Discord", + "notFound.logoLightAlt": "opencode logo claro", + "notFound.logoDarkAlt": "opencode logo oscuro", "user.logout": "Cerrar sesión", + "auth.callback.error.codeMissing": "No se encontró código de autorización.", + "workspace.select": "Seleccionar espacio de trabajo", "workspace.createNew": "+ Crear nuevo espacio de trabajo", "workspace.modal.title": "Crear nuevo espacio de trabajo", @@ -76,6 +81,8 @@ export const dict = { "error.reloadAmountMin": "La cantidad de recarga debe ser al menos ${{amount}}", "error.reloadTriggerMin": "El disparador de saldo debe ser al menos ${{amount}}", + "app.meta.description": "OpenCode - El agente de codificación de código abierto.", + "home.title": "OpenCode | El agente de codificación IA de código abierto", "temp.title": "opencode | Agente de codificación IA creado para la terminal", @@ -91,6 +98,8 @@ export const dict = { "temp.feature.models.afterLink": ", incluyendo modelos locales", "temp.screenshot.caption": "opencode TUI con el tema tokyonight", "temp.screenshot.alt": "opencode TUI con tema tokyonight", + "temp.logoLightAlt": "logo de opencode claro", + "temp.logoDarkAlt": "logo de opencode oscuro", "home.banner.badge": "Nuevo", "home.banner.text": "Aplicación de escritorio disponible en beta", @@ -243,11 +252,131 @@ export const dict = { "Todos los modelos Zen están alojados en EE. UU. Los proveedores siguen una política de cero retención y no usan tus datos para entrenamiento de modelos, con las", "zen.privacy.exceptionsLink": "siguientes excepciones", + "go.title": "OpenCode Go | Modelos de programación de bajo coste para todos", + "go.meta.description": + "Go es una suscripción de 10 $/mes con generosos límites de solicitudes de 5 horas para GLM-5, Kimi K2.5 y MiniMax M2.5.", + "go.hero.title": "Modelos de programación de bajo coste para todos", + "go.hero.body": + "Go lleva la programación agéntica a programadores de todo el mundo. Ofrece límites generosos y acceso fiable a los modelos de código abierto más capaces, para que puedas crear con agentes potentes sin preocuparte por el coste o la disponibilidad.", + + "go.cta.start": "Suscribirse a Go", + "go.cta.template": "{{text}} {{price}}", + "go.cta.text": "Suscribirse a Go", + "go.cta.price": "10 $/mes", + "go.pricing.body": "Úsalo con cualquier agente. Recarga crédito si es necesario. Cancela en cualquier momento.", + "go.graph.free": "Gratis", + "go.graph.freePill": "Big Pickle y modelos gratuitos", + "go.graph.go": "Go", + "go.graph.label": "Solicitudes por 5 horas", + "go.graph.usageLimits": "Límites de uso", + "go.graph.tick": "{{n}}x", + "go.graph.aria": "Solicitudes por 5h: {{free}} vs {{go}}", + + "go.testimonials.brand.zen": "Zen", + "go.testimonials.brand.go": "Go", + "go.testimonials.handle": "@OpenCode", + "go.testimonials.dax.name": "Dax Raad", + "go.testimonials.dax.title": "ex-CEO, Terminal Products", + "go.testimonials.dax.quoteAfter": "ha cambiado mi vida, es realmente una obviedad.", + "go.testimonials.jay.name": "Jay V", + "go.testimonials.jay.title": "ex-Founder, SEED, PM, Melt, Pop, Dapt, Cadmus, and ViewPoint", + "go.testimonials.jay.quoteBefore": "A 4 de cada 5 personas en nuestro equipo les encanta usar", + "go.testimonials.jay.quoteAfter": ".", + "go.testimonials.adam.name": "Adam Elmore", + "go.testimonials.adam.title": "ex-Hero, AWS", + "go.testimonials.adam.quoteBefore": "No puedo recomendar", + "go.testimonials.adam.quoteAfter": "lo suficiente. En serio, es realmente bueno.", + "go.testimonials.david.name": "David Hill", + "go.testimonials.david.title": "ex-Head of Design, Laravel", + "go.testimonials.david.quoteBefore": "Con", + "go.testimonials.david.quoteAfter": + "sé que todos los modelos están probados y son perfectos para agentes de programación.", + "go.testimonials.frank.name": "Frank Wang", + "go.testimonials.frank.title": "ex-Intern, Nvidia (4 times)", + "go.testimonials.frank.quote": "Ojalá siguiera en Nvidia.", + "go.problem.title": "¿Qué problema resuelve Go?", + "go.problem.body": + "Estamos enfocados en llevar la experiencia de OpenCode a tanta gente como sea posible. OpenCode Go es una suscripción de bajo coste (10 $/mes) diseñada para llevar la programación agéntica a programadores de todo el mundo. Proporciona límites generosos y acceso fiable a los modelos de código abierto más capaces.", + "go.problem.subtitle": " ", + "go.problem.item1": "Precios de suscripción de bajo coste", + "go.problem.item2": "Límites generosos y acceso fiable", + "go.problem.item3": "Creado para tantos programadores como sea posible", + "go.problem.item4": "Incluye GLM-5, Kimi K2.5 y MiniMax M2.5", + "go.how.title": "Cómo funciona Go", + "go.how.body": "Go es una suscripción de 10 $/mes que puedes usar con OpenCode o cualquier agente.", + "go.how.step1.title": "Crear una cuenta", + "go.how.step1.beforeLink": "sigue las", + "go.how.step1.link": "instrucciones de configuración", + "go.how.step2.title": "Suscribirse a Go", + "go.how.step2.link": "10 $/mes", + "go.how.step2.afterLink": "con límites generosos", + "go.how.step3.title": "Empezar a programar", + "go.how.step3.body": "con acceso fiable a modelos de código abierto", + "go.privacy.title": "Tu privacidad es importante para nosotros", + "go.privacy.body": + "El plan está diseñado principalmente para usuarios internacionales, con modelos alojados en EE. UU., UE y Singapur para un acceso global estable.", + "go.privacy.contactAfter": "si tienes alguna pregunta.", + "go.privacy.beforeExceptions": + "Los modelos de Go están alojados en EE. UU. Los proveedores siguen una política de retención cero y no utilizan tus datos para el entrenamiento de modelos, con las", + "go.privacy.exceptionsLink": "siguientes excepciones", + "go.faq.q1": "¿Qué es OpenCode Go?", + "go.faq.a1": + "Go es una suscripción de bajo coste que te da acceso fiable a modelos de código abierto capaces para programación agéntica.", + "go.faq.q2": "¿Qué modelos incluye Go?", + "go.faq.a2": "Go incluye GLM-5, Kimi K2.5 y MiniMax M2.5, con límites generosos y acceso fiable.", + "go.faq.q3": "¿Es Go lo mismo que Zen?", + "go.faq.a3": + "No. Zen es pago por uso, mientras que Go es una suscripción de 10 $/mes con límites generosos y acceso fiable a modelos de código abierto GLM-5, Kimi K2.5 y MiniMax M2.5.", + "go.faq.q4": "¿Cuánto cuesta Go?", + "go.faq.a4.p1.beforePricing": "Go cuesta", + "go.faq.a4.p1.pricingLink": "10 $/mes", + "go.faq.a4.p1.afterPricing": "con límites generosos.", + "go.faq.a4.p2.beforeAccount": "Puedes gestionar tu suscripción en tu", + "go.faq.a4.p2.accountLink": "cuenta", + "go.faq.a4.p3": "Cancela en cualquier momento.", + "go.faq.q5": "¿Qué pasa con los datos y la privacidad?", + "go.faq.a5.body": + "El plan está diseñado principalmente para usuarios internacionales, con modelos alojados en EE. UU., UE y Singapur para un acceso global estable.", + "go.faq.a5.contactAfter": "si tienes alguna pregunta.", + "go.faq.a5.beforeExceptions": + "Los modelos de Go están alojados en EE. UU. Los proveedores siguen una política de retención cero y no utilizan tus datos para el entrenamiento de modelos, con las", + "go.faq.a5.exceptionsLink": "siguientes excepciones", + "go.faq.q6": "¿Puedo recargar crédito?", + "go.faq.a6": "Si necesitas más uso, puedes recargar crédito en tu cuenta.", + "go.faq.q7": "¿Puedo cancelar?", + "go.faq.a7": "Sí, puedes cancelar en cualquier momento.", + "go.faq.q8": "¿Puedo usar Go con otros agentes de programación?", + "go.faq.a8": + "Sí, puedes usar Go con cualquier agente. Sigue las instrucciones de configuración en tu agente de programación preferido.", + + "go.faq.q9": "¿Cuál es la diferencia entre los modelos gratuitos y Go?", + "go.faq.a9": + "Los modelos gratuitos incluyen Big Pickle más modelos promocionales disponibles en el momento, con una cuota de 200 solicitudes/día. Go incluye GLM-5, Kimi K2.5 y MiniMax M2.5 con cuotas de solicitud más altas aplicadas a través de ventanas móviles (5 horas, semanal y mensual), aproximadamente equivalente a 12 $ por 5 horas, 30 $ por semana y 60 $ por mes (los recuentos reales de solicitudes varían según el modelo y el uso).", + + "zen.api.error.rateLimitExceeded": "Límite de tasa excedido. Por favor, inténtalo de nuevo más tarde.", + "zen.api.error.modelNotSupported": "Modelo {{model}} no soportado", + "zen.api.error.modelFormatNotSupported": "Modelo {{model}} no soportado para el formato {{format}}", + "zen.api.error.noProviderAvailable": "Ningún proveedor disponible", + "zen.api.error.providerNotSupported": "Proveedor {{provider}} no soportado", + "zen.api.error.missingApiKey": "Falta la clave API.", + "zen.api.error.invalidApiKey": "Clave API inválida.", + "zen.api.error.subscriptionQuotaExceeded": "Cuota de suscripción excedida. Reintenta en {{retryIn}}.", + "zen.api.error.subscriptionQuotaExceededUseFreeModels": + "Cuota de suscripción excedida. Puedes continuar usando modelos gratuitos.", + "zen.api.error.noPaymentMethod": "Sin método de pago. Añade un método de pago aquí: {{billingUrl}}", + "zen.api.error.insufficientBalance": "Saldo insuficiente. Gestiona tu facturación aquí: {{billingUrl}}", + "zen.api.error.workspaceMonthlyLimitReached": + "Tu espacio de trabajo ha alcanzado su límite de gasto mensual de ${{amount}}. Gestiona tus límites aquí: {{billingUrl}}", + "zen.api.error.userMonthlyLimitReached": + "Has alcanzado tu límite de gasto mensual de ${{amount}}. Gestiona tus límites aquí: {{membersUrl}}", + "zen.api.error.modelDisabled": "El modelo está deshabilitado", + "black.meta.title": "OpenCode Black | Accede a los mejores modelos de codificación del mundo", "black.meta.description": "Obtén acceso a Claude, GPT, Gemini y más con los planes de suscripción de OpenCode Black.", "black.hero.title": "Accede a los mejores modelos de codificación del mundo", "black.hero.subtitle": "Incluyendo Claude, GPT, Gemini y más", "black.title": "OpenCode Black | Precios", + "black.paused": "La inscripción al plan Black está temporalmente pausada.", "black.plan.icon20": "Plan Black 20", "black.plan.icon100": "Plan Black 100", "black.plan.icon200": "Plan Black 200", @@ -343,12 +472,15 @@ export const dict = { "workspace.usage.table.input": "Entrada", "workspace.usage.table.output": "Salida", "workspace.usage.table.cost": "Costo", + "workspace.usage.table.session": "Sesión", "workspace.usage.breakdown.input": "Entrada", "workspace.usage.breakdown.cacheRead": "Lectura de Caché", "workspace.usage.breakdown.cacheWrite": "Escritura de Caché", "workspace.usage.breakdown.output": "Salida", "workspace.usage.breakdown.reasoning": "Razonamiento", - "workspace.usage.subscription": "suscripción (${{amount}})", + "workspace.usage.subscription": "Black (${{amount}})", + "workspace.usage.lite": "Go (${{amount}})", + "workspace.usage.byok": "BYOK (${{amount}})", "workspace.cost.title": "Costo", "workspace.cost.subtitle": "Costos de uso desglosados por modelo.", @@ -447,6 +579,7 @@ export const dict = { "workspace.reload.updatePaymentMethod": "Por favor actualiza tu método de pago e intenta de nuevo.", "workspace.reload.retrying": "Reintentando...", "workspace.reload.retry": "Reintentar", + "workspace.reload.error.paymentFailed": "El pago falló.", "workspace.payments.title": "Historial de Pagos", "workspace.payments.subtitle": "Transacciones de pago recientes.", @@ -485,6 +618,36 @@ export const dict = { "workspace.black.waitlist.enrollNote": "Cuando haces clic en Inscribirse, tu suscripción comienza inmediatamente y se cargará a tu tarjeta.", + "workspace.lite.loading": "Cargando...", + "workspace.lite.time.day": "día", + "workspace.lite.time.days": "días", + "workspace.lite.time.hour": "hora", + "workspace.lite.time.hours": "horas", + "workspace.lite.time.minute": "minuto", + "workspace.lite.time.minutes": "minutos", + "workspace.lite.time.fewSeconds": "unos pocos segundos", + "workspace.lite.subscription.title": "Suscripción Go", + "workspace.lite.subscription.message": "Estás suscrito a OpenCode Go.", + "workspace.lite.subscription.manage": "Gestionar Suscripción", + "workspace.lite.subscription.rollingUsage": "Uso Continuo", + "workspace.lite.subscription.weeklyUsage": "Uso Semanal", + "workspace.lite.subscription.monthlyUsage": "Uso Mensual", + "workspace.lite.subscription.resetsIn": "Se reinicia en", + "workspace.lite.subscription.useBalance": "Usa tu saldo disponible después de alcanzar los límites de uso", + "workspace.lite.subscription.selectProvider": + 'Selecciona "OpenCode Go" como proveedor en tu configuración de opencode para usar los modelos Go.', + "workspace.lite.other.title": "Suscripción Go", + "workspace.lite.other.message": + "Otro miembro de este espacio de trabajo ya está suscrito a OpenCode Go. Solo un miembro por espacio de trabajo puede suscribirse.", + "workspace.lite.promo.title": "OpenCode Go", + "workspace.lite.promo.description": + "OpenCode Go es una suscripción de $10 al mes que proporciona acceso confiable a modelos de codificación abiertos populares con generosos límites de uso.", + "workspace.lite.promo.modelsTitle": "Qué incluye", + "workspace.lite.promo.footer": + "El plan está diseñado principalmente para usuarios internacionales, con modelos alojados en EE. UU., la UE y Singapur para un acceso global estable. Los precios y los límites de uso pueden cambiar a medida que aprendemos del uso inicial y los comentarios.", + "workspace.lite.promo.subscribe": "Suscribirse a Go", + "workspace.lite.promo.subscribing": "Redirigiendo...", + "download.title": "OpenCode | Descargar", "download.meta.description": "Descarga OpenCode para macOS, Windows y Linux", "download.hero.title": "Descargar OpenCode", @@ -536,6 +699,10 @@ export const dict = { "enterprise.form.send": "Enviar", "enterprise.form.sending": "Enviando...", "enterprise.form.success": "Mensaje enviado, estaremos en contacto pronto.", + "enterprise.form.success.submitted": "Formulario enviado con éxito.", + "enterprise.form.error.allFieldsRequired": "Todos los campos son obligatorios.", + "enterprise.form.error.invalidEmailFormat": "Formato de correo inválido.", + "enterprise.form.error.internalServer": "Error interno del servidor.", "enterprise.faq.title": "FAQ", "enterprise.faq.q1": "¿Qué es OpenCode Enterprise?", "enterprise.faq.a1": @@ -568,6 +735,7 @@ export const dict = { "bench.list.table.agent": "Agente", "bench.list.table.model": "Modelo", "bench.list.table.score": "Puntuación", + "bench.submission.error.allFieldsRequired": "Todos los campos son obligatorios.", "bench.detail.title": "Benchmark - {{task}}", "bench.detail.notFound": "Tarea no encontrada", diff --git a/packages/console/app/src/i18n/fr.ts b/packages/console/app/src/i18n/fr.ts index 8974927a96..ddf33c0ec2 100644 --- a/packages/console/app/src/i18n/fr.ts +++ b/packages/console/app/src/i18n/fr.ts @@ -3,6 +3,7 @@ import { dict as en } from "./en" export const dict = { ...en, + "app.meta.description": "OpenCode - L'agent de code open source.", "nav.github": "GitHub", "nav.docs": "Documentation", "nav.changelog": "Changelog", @@ -15,6 +16,7 @@ export const dict = { "nav.home": "Accueil", "nav.openMenu": "Ouvrir le menu", "nav.getStartedFree": "Commencer gratuitement", + "nav.logoAlt": "OpenCode", "nav.context.copyLogo": "Copier le logo en SVG", "nav.context.copyWordmark": "Copier le logotype en SVG", @@ -42,6 +44,8 @@ export const dict = { "notFound.docs": "Documentation", "notFound.github": "GitHub", "notFound.discord": "Discord", + "notFound.logoLightAlt": "opencode logo light", + "notFound.logoDarkAlt": "opencode logo dark", "user.logout": "Se déconnecter", @@ -75,6 +79,7 @@ export const dict = { "error.modelRequired": "Le modèle est requis", "error.reloadAmountMin": "Le montant de recharge doit être d'au moins {{amount}} $", "error.reloadTriggerMin": "Le seuil de déclenchement doit être d'au moins {{amount}} $", + "auth.callback.error.codeMissing": "Aucun code d'autorisation trouvé.", "home.title": "OpenCode | L'agent de code IA open source", @@ -91,6 +96,8 @@ export const dict = { "temp.feature.models.afterLink": ", y compris les modèles locaux", "temp.screenshot.caption": "OpenCode TUI avec le thème tokyonight", "temp.screenshot.alt": "OpenCode TUI avec le thème tokyonight", + "temp.logoLightAlt": "opencode logo light", + "temp.logoDarkAlt": "opencode logo dark", "home.banner.badge": "Nouveau", "home.banner.text": "Application desktop disponible en bêta", @@ -246,11 +253,129 @@ export const dict = { "Tous les modèles Zen sont hébergés aux États-Unis. Les fournisseurs suivent une politique de rétention zéro et n'utilisent pas vos données pour l'entraînement des modèles, avec les", "zen.privacy.exceptionsLink": "exceptions suivantes", + "go.title": "OpenCode Go | Modèles de code à faible coût pour tous", + "go.meta.description": + "Go est un abonnement à 10 $/mois avec des limites généreuses de 5 heures de requêtes pour GLM-5, Kimi K2.5 et MiniMax M2.5.", + "go.hero.title": "Modèles de code à faible coût pour tous", + "go.hero.body": + "Go apporte le codage agentique aux programmeurs du monde entier. Offrant des limites généreuses et un accès fiable aux modèles open source les plus capables, pour que vous puissiez construire avec des agents puissants sans vous soucier du coût ou de la disponibilité.", + + "go.cta.start": "S'abonner à Go", + "go.cta.template": "{{text}} {{price}}", + "go.cta.text": "S'abonner à Go", + "go.cta.price": "10 $/mois", + "go.pricing.body": "Utilisez avec n'importe quel agent. Rechargez du crédit si nécessaire. Annulez à tout moment.", + "go.graph.free": "Gratuit", + "go.graph.freePill": "Big Pickle et modèles gratuits", + "go.graph.go": "Go", + "go.graph.label": "Requêtes par tranche de 5 heures", + "go.graph.usageLimits": "Limites d'utilisation", + "go.graph.tick": "{{n}}x", + "go.graph.aria": "Requêtes par 5h : {{free}} vs {{go}}", + + "go.testimonials.brand.zen": "Zen", + "go.testimonials.brand.go": "Go", + "go.testimonials.handle": "@OpenCode", + "go.testimonials.dax.name": "Dax Raad", + "go.testimonials.dax.title": "ex-PDG, Terminal Products", + "go.testimonials.dax.quoteAfter": "a changé ma vie, c'est vraiment une évidence.", + "go.testimonials.jay.name": "Jay V", + "go.testimonials.jay.title": "ex-Fondateur, SEED, PM, Melt, Pop, Dapt, Cadmus, et ViewPoint", + "go.testimonials.jay.quoteBefore": "4 personnes sur 5 dans notre équipe adorent utiliser", + "go.testimonials.jay.quoteAfter": ".", + "go.testimonials.adam.name": "Adam Elmore", + "go.testimonials.adam.title": "ex-Hero, AWS", + "go.testimonials.adam.quoteBefore": "Je ne peux pas recommander", + "go.testimonials.adam.quoteAfter": "assez. Sérieusement, c'est vraiment bien.", + "go.testimonials.david.name": "David Hill", + "go.testimonials.david.title": "ex-Directeur du Design, Laravel", + "go.testimonials.david.quoteBefore": "Avec", + "go.testimonials.david.quoteAfter": "je sais que tous les modèles sont testés et parfaits pour les agents de code.", + "go.testimonials.frank.name": "Frank Wang", + "go.testimonials.frank.title": "ex-Stagiaire, Nvidia (4 fois)", + "go.testimonials.frank.quote": "J'aimerais être encore chez Nvidia.", + "go.problem.title": "Quel problème Go résout-il ?", + "go.problem.body": + "Nous nous concentrons sur le fait d'apporter l'expérience OpenCode à autant de personnes que possible. OpenCode Go est un abonnement à faible coût (10 $/mois) conçu pour apporter le codage agentique aux programmeurs du monde entier. Il offre des limites généreuses et un accès fiable aux modèles open source les plus capables.", + "go.problem.subtitle": " ", + "go.problem.item1": "Prix d'abonnement bas", + "go.problem.item2": "Limites généreuses et accès fiable", + "go.problem.item3": "Conçu pour autant de programmeurs que possible", + "go.problem.item4": "Inclut GLM-5, Kimi K2.5 et MiniMax M2.5", + "go.how.title": "Comment fonctionne Go", + "go.how.body": "Go est un abonnement à 10 $/mois que vous pouvez utiliser avec OpenCode ou n'importe quel agent.", + "go.how.step1.title": "Créez un compte", + "go.how.step1.beforeLink": "suivez les", + "go.how.step1.link": "instructions de configuration", + "go.how.step2.title": "Abonnez-vous à Go", + "go.how.step2.link": "10 $/mois", + "go.how.step2.afterLink": "avec des limites généreuses", + "go.how.step3.title": "Commencez à coder", + "go.how.step3.body": "avec un accès fiable aux modèles open source", + "go.privacy.title": "Votre vie privée est importante pour nous", + "go.privacy.body": + "Le plan est conçu principalement pour les utilisateurs internationaux, avec des modèles hébergés aux États-Unis, dans l'UE et à Singapour pour un accès mondial stable.", + "go.privacy.contactAfter": "si vous avez des questions.", + "go.privacy.beforeExceptions": + "Les modèles Go sont hébergés aux États-Unis. Les fournisseurs suivent une politique de rétention zéro et n'utilisent pas vos données pour l'entraînement des modèles, avec les", + "go.privacy.exceptionsLink": "exceptions suivantes", + "go.faq.q1": "Qu'est-ce que OpenCode Go ?", + "go.faq.a1": + "Go est un abonnement à faible coût qui vous donne un accès fiable à des modèles open source performants pour le codage agentique.", + "go.faq.q2": "Quels modèles Go inclut-il ?", + "go.faq.a2": "Go inclut GLM-5, Kimi K2.5 et MiniMax M2.5, avec des limites généreuses et un accès fiable.", + "go.faq.q3": "Est-ce que Go est la même chose que Zen ?", + "go.faq.a3": + "Non. Zen est payé à l'usage (pay-as-you-go), tandis que Go est un abonnement à 10 $/mois avec des limites généreuses et un accès fiable aux modèles open source GLM-5, Kimi K2.5 et MiniMax M2.5.", + "go.faq.q4": "Combien coûte Go ?", + "go.faq.a4.p1.beforePricing": "Go coûte", + "go.faq.a4.p1.pricingLink": "10 $/mois", + "go.faq.a4.p1.afterPricing": "avec des limites généreuses.", + "go.faq.a4.p2.beforeAccount": "Vous pouvez gérer votre abonnement dans votre", + "go.faq.a4.p2.accountLink": "compte", + "go.faq.a4.p3": "Annulez à tout moment.", + "go.faq.q5": "Et pour les données et la confidentialité ?", + "go.faq.a5.body": + "Le plan est conçu principalement pour les utilisateurs internationaux, avec des modèles hébergés aux États-Unis, dans l'UE et à Singapour pour un accès mondial stable.", + "go.faq.a5.contactAfter": "si vous avez des questions.", + "go.faq.a5.beforeExceptions": + "Les modèles Go sont hébergés aux États-Unis. Les fournisseurs suivent une politique de rétention zéro et n'utilisent pas vos données pour l'entraînement des modèles, avec les", + "go.faq.a5.exceptionsLink": "exceptions suivantes", + "go.faq.q6": "Puis-je recharger mon crédit ?", + "go.faq.a6": "Si vous avez besoin de plus d'utilisation, vous pouvez recharger du crédit dans votre compte.", + "go.faq.q7": "Puis-je annuler ?", + "go.faq.a7": "Oui, vous pouvez annuler à tout moment.", + "go.faq.q8": "Puis-je utiliser Go avec d'autres agents de code ?", + "go.faq.a8": + "Oui, vous pouvez utiliser Go avec n'importe quel agent. Suivez les instructions de configuration dans votre agent de code préféré.", + "go.faq.q9": "Quelle est la différence entre les modèles gratuits et Go ?", + "go.faq.a9": + "Les modèles gratuits incluent Big Pickle ainsi que des modèles promotionnels disponibles à ce moment-là, avec un quota de 200 requêtes/jour. Go inclut GLM-5, Kimi K2.5 et MiniMax M2.5 avec des quotas de requêtes plus élevés appliqués sur des fenêtres glissantes (5 heures, hebdomadaire et mensuelle), à peu près équivalent à 12 $ par 5 heures, 30 $ par semaine et 60 $ par mois (le nombre réel de requêtes varie selon le modèle et l'utilisation).", + + "zen.api.error.rateLimitExceeded": "Limite de débit dépassée. Veuillez réessayer plus tard.", + "zen.api.error.modelNotSupported": "Modèle {{model}} non pris en charge", + "zen.api.error.modelFormatNotSupported": "Modèle {{model}} non pris en charge pour le format {{format}}", + "zen.api.error.noProviderAvailable": "Aucun fournisseur disponible", + "zen.api.error.providerNotSupported": "Fournisseur {{provider}} non pris en charge", + "zen.api.error.missingApiKey": "Clé API manquante.", + "zen.api.error.invalidApiKey": "Clé API invalide.", + "zen.api.error.subscriptionQuotaExceeded": "Quota d'abonnement dépassé. Réessayez dans {{retryIn}}.", + "zen.api.error.subscriptionQuotaExceededUseFreeModels": + "Quota d'abonnement dépassé. Vous pouvez continuer à utiliser les modèles gratuits.", + "zen.api.error.noPaymentMethod": "Aucune méthode de paiement. Ajoutez une méthode de paiement ici : {{billingUrl}}", + "zen.api.error.insufficientBalance": "Solde insuffisant. Gérez votre facturation ici : {{billingUrl}}", + "zen.api.error.workspaceMonthlyLimitReached": + "Votre espace de travail a atteint sa limite de dépense mensuelle de {{amount}} $. Gérez vos limites ici : {{billingUrl}}", + "zen.api.error.userMonthlyLimitReached": + "Vous avez atteint votre limite de dépense mensuelle de {{amount}} $. Gérez vos limites ici : {{membersUrl}}", + "zen.api.error.modelDisabled": "Le modèle est désactivé", + "black.meta.title": "OpenCode Black | Accédez aux meilleurs modèles de code au monde", "black.meta.description": "Accédez à Claude, GPT, Gemini et plus avec les forfaits d'abonnement OpenCode Black.", "black.hero.title": "Accédez aux meilleurs modèles de code au monde", "black.hero.subtitle": "Y compris Claude, GPT, Gemini et plus", "black.title": "OpenCode Black | Tarification", + "black.paused": "L'inscription au plan Black est temporairement suspendue.", "black.plan.icon20": "Forfait Black 20", "black.plan.icon100": "Forfait Black 100", "black.plan.icon200": "Forfait Black 200", @@ -348,12 +473,15 @@ export const dict = { "workspace.usage.table.input": "Entrée", "workspace.usage.table.output": "Sortie", "workspace.usage.table.cost": "Coût", + "workspace.usage.table.session": "Session", "workspace.usage.breakdown.input": "Entrée", "workspace.usage.breakdown.cacheRead": "Lecture cache", "workspace.usage.breakdown.cacheWrite": "Écriture cache", "workspace.usage.breakdown.output": "Sortie", "workspace.usage.breakdown.reasoning": "Raisonnement", - "workspace.usage.subscription": "abonnement ({{amount}} $)", + "workspace.usage.subscription": "Black ({{amount}} $)", + "workspace.usage.lite": "Go ({{amount}} $)", + "workspace.usage.byok": "BYOK ({{amount}} $)", "workspace.cost.title": "Coût", "workspace.cost.subtitle": "Coûts d'utilisation répartis par modèle.", @@ -452,6 +580,7 @@ export const dict = { "workspace.reload.updatePaymentMethod": "Veuillez mettre à jour votre méthode de paiement et réessayer.", "workspace.reload.retrying": "Nouvelle tentative...", "workspace.reload.retry": "Réessayer", + "workspace.reload.error.paymentFailed": "Échec du paiement.", "workspace.payments.title": "Historique des paiements", "workspace.payments.subtitle": "Transactions de paiement récentes.", @@ -493,6 +622,37 @@ export const dict = { "workspace.black.waitlist.enrollNote": "Lorsque vous cliquez sur S'inscrire, votre abonnement démarre immédiatement et votre carte sera débitée.", + "workspace.lite.loading": "Chargement...", + "workspace.lite.time.day": "jour", + "workspace.lite.time.days": "jours", + "workspace.lite.time.hour": "heure", + "workspace.lite.time.hours": "heures", + "workspace.lite.time.minute": "minute", + "workspace.lite.time.minutes": "minutes", + "workspace.lite.time.fewSeconds": "quelques secondes", + "workspace.lite.subscription.title": "Abonnement Go", + "workspace.lite.subscription.message": "Vous êtes abonné à OpenCode Go.", + "workspace.lite.subscription.manage": "Gérer l'abonnement", + "workspace.lite.subscription.rollingUsage": "Utilisation glissante", + "workspace.lite.subscription.weeklyUsage": "Utilisation hebdomadaire", + "workspace.lite.subscription.monthlyUsage": "Utilisation mensuelle", + "workspace.lite.subscription.resetsIn": "Réinitialisation dans", + "workspace.lite.subscription.useBalance": + "Utilisez votre solde disponible après avoir atteint les limites d'utilisation", + "workspace.lite.subscription.selectProvider": + 'Sélectionnez "OpenCode Go" comme fournisseur dans votre configuration opencode pour utiliser les modèles Go.', + "workspace.lite.other.title": "Abonnement Go", + "workspace.lite.other.message": + "Un autre membre de cet espace de travail est déjà abonné à OpenCode Go. Un seul membre par espace de travail peut s'abonner.", + "workspace.lite.promo.title": "OpenCode Go", + "workspace.lite.promo.description": + "OpenCode Go est un abonnement à 10 $ par mois qui offre un accès fiable aux modèles de codage ouverts populaires avec des limites d'utilisation généreuses.", + "workspace.lite.promo.modelsTitle": "Ce qui est inclus", + "workspace.lite.promo.footer": + "Le plan est conçu principalement pour les utilisateurs internationaux, avec des modèles hébergés aux États-Unis, dans l'UE et à Singapour pour un accès mondial stable. Les tarifs et les limites d'utilisation peuvent changer à mesure que nous apprenons des premières utilisations et des commentaires.", + "workspace.lite.promo.subscribe": "S'abonner à Go", + "workspace.lite.promo.subscribing": "Redirection...", + "download.title": "OpenCode | Téléchargement", "download.meta.description": "Téléchargez OpenCode pour macOS, Windows et Linux", "download.hero.title": "Télécharger OpenCode", @@ -545,6 +705,10 @@ export const dict = { "enterprise.form.send": "Envoyer", "enterprise.form.sending": "Envoi...", "enterprise.form.success": "Message envoyé, nous vous contacterons bientôt.", + "enterprise.form.success.submitted": "Formulaire soumis avec succès.", + "enterprise.form.error.allFieldsRequired": "Tous les champs sont requis.", + "enterprise.form.error.invalidEmailFormat": "Format d'e-mail invalide.", + "enterprise.form.error.internalServer": "Erreur interne du serveur.", "enterprise.faq.title": "FAQ", "enterprise.faq.q1": "Qu'est-ce que OpenCode Enterprise ?", "enterprise.faq.a1": @@ -604,4 +768,5 @@ export const dict = { "bench.detail.table.duration": "Durée", "bench.detail.run.title": "Exécution {{n}}", "bench.detail.rawJson": "JSON brut", + "bench.submission.error.allFieldsRequired": "Tous les champs sont requis.", } satisfies Dict diff --git a/packages/console/app/src/i18n/it.ts b/packages/console/app/src/i18n/it.ts index ce464f0009..770efde453 100644 --- a/packages/console/app/src/i18n/it.ts +++ b/packages/console/app/src/i18n/it.ts @@ -15,6 +15,7 @@ export const dict = { "nav.home": "Home", "nav.openMenu": "Apri menu", "nav.getStartedFree": "Inizia gratis", + "nav.logoAlt": "OpenCode", "nav.context.copyLogo": "Copia il logo come SVG", "nav.context.copyWordmark": "Copia il wordmark come SVG", @@ -42,9 +43,13 @@ export const dict = { "notFound.docs": "Documentazione", "notFound.github": "GitHub", "notFound.discord": "Discord", + "notFound.logoLightAlt": "logo chiaro di opencode", + "notFound.logoDarkAlt": "logo scuro di opencode", "user.logout": "Esci", + "auth.callback.error.codeMissing": "Nessun codice di autorizzazione trovato.", + "workspace.select": "Seleziona workspace", "workspace.createNew": "+ Crea nuovo workspace", "workspace.modal.title": "Crea nuovo workspace", @@ -76,6 +81,8 @@ export const dict = { "error.reloadAmountMin": "L'importo della ricarica deve essere almeno ${{amount}}", "error.reloadTriggerMin": "La soglia del saldo deve essere almeno ${{amount}}", + "app.meta.description": "OpenCode - L'agente di programmazione open source.", + "home.title": "OpenCode | L'agente di coding IA open source", "temp.title": "opencode | Agente di coding IA costruito per il terminale", @@ -91,6 +98,8 @@ export const dict = { "temp.feature.models.afterLink": ", inclusi modelli locali", "temp.screenshot.caption": "OpenCode TUI con il tema tokyonight", "temp.screenshot.alt": "OpenCode TUI con tema tokyonight", + "temp.logoLightAlt": "logo chiaro di opencode", + "temp.logoDarkAlt": "logo scuro di opencode", "home.banner.badge": "Nuovo", "home.banner.text": "App desktop disponibile in beta", @@ -240,12 +249,131 @@ export const dict = { "Tutti i modelli Zen sono ospitati negli Stati Uniti. I provider seguono una policy di zero-retention e non usano i tuoi dati per l'addestramento dei modelli, con le", "zen.privacy.exceptionsLink": "seguenti eccezioni", + "go.title": "OpenCode Go | Modelli di coding a basso costo per tutti", + "go.meta.description": + "Go è un abbonamento da $10/mese con generosi limiti di richieste di 5 ore per GLM-5, Kimi K2.5 e MiniMax M2.5.", + "go.hero.title": "Modelli di coding a basso costo per tutti", + "go.hero.body": + "Go porta il coding agentico ai programmatori di tutto il mondo. Offrendo limiti generosi e un accesso affidabile ai modelli open source più capaci, in modo da poter costruire con agenti potenti senza preoccuparsi dei costi o della disponibilità.", + + "go.cta.start": "Abbonati a Go", + "go.cta.template": "{{text}} {{price}}", + "go.cta.text": "Abbonati a Go", + "go.cta.price": "$10/mese", + "go.pricing.body": "Usa con qualsiasi agente. Ricarica credito se necessario. Annulla in qualsiasi momento.", + "go.graph.free": "Gratis", + "go.graph.freePill": "Big Pickle e modelli gratuiti", + "go.graph.go": "Go", + "go.graph.label": "Richieste ogni 5 ore", + "go.graph.usageLimits": "Limiti di utilizzo", + "go.graph.tick": "{{n}}x", + "go.graph.aria": "Richieste ogni 5h: {{free}} vs {{go}}", + + "go.testimonials.brand.zen": "Zen", + "go.testimonials.brand.go": "Go", + "go.testimonials.handle": "@OpenCode", + "go.testimonials.dax.name": "Dax Raad", + "go.testimonials.dax.title": "ex-CEO, Terminal Products", + "go.testimonials.dax.quoteAfter": "ha cambiato la vita, è davvero una scelta ovvia.", + "go.testimonials.jay.name": "Jay V", + "go.testimonials.jay.title": "ex-Founder, SEED, PM, Melt, Pop, Dapt, Cadmus, e ViewPoint", + "go.testimonials.jay.quoteBefore": "4 persone su 5 nel nostro team amano usare", + "go.testimonials.jay.quoteAfter": ".", + "go.testimonials.adam.name": "Adam Elmore", + "go.testimonials.adam.title": "ex-Hero, AWS", + "go.testimonials.adam.quoteBefore": "Non posso raccomandare", + "go.testimonials.adam.quoteAfter": "abbastanza. Seriamente, è davvero buono.", + "go.testimonials.david.name": "David Hill", + "go.testimonials.david.title": "ex-Head of Design, Laravel", + "go.testimonials.david.quoteBefore": "Con", + "go.testimonials.david.quoteAfter": "so che tutti i modelli sono testati e perfetti per gli agenti di coding.", + "go.testimonials.frank.name": "Frank Wang", + "go.testimonials.frank.title": "ex-Intern, Nvidia (4 volte)", + "go.testimonials.frank.quote": "Vorrei essere ancora a Nvidia.", + "go.problem.title": "Quale problema risolve Go?", + "go.problem.body": + "Ci concentriamo nel portare l'esperienza OpenCode a quante più persone possibile. OpenCode Go è un abbonamento a basso costo ($10/mese) progettato per portare il coding agentico ai programmatori di tutto il mondo. Fornisce limiti generosi e accesso affidabile ai modelli open source più capaci.", + "go.problem.subtitle": " ", + "go.problem.item1": "Prezzo di abbonamento a basso costo", + "go.problem.item2": "Limiti generosi e accesso affidabile", + "go.problem.item3": "Costruito per il maggior numero possibile di programmatori", + "go.problem.item4": "Include GLM-5, Kimi K2.5 e MiniMax M2.5", + "go.how.title": "Come funziona Go", + "go.how.body": "Go è un abbonamento da $10/mese che puoi usare con OpenCode o qualsiasi agente.", + "go.how.step1.title": "Crea un account", + "go.how.step1.beforeLink": "segui le", + "go.how.step1.link": "istruzioni di configurazione", + "go.how.step2.title": "Abbonati a Go", + "go.how.step2.link": "$10/mese", + "go.how.step2.afterLink": "con limiti generosi", + "go.how.step3.title": "Inizia a programmare", + "go.how.step3.body": "con accesso affidabile ai modelli open source", + "go.privacy.title": "La tua privacy è importante per noi", + "go.privacy.body": + "Il piano è progettato principalmente per gli utenti internazionali, con modelli ospitati negli Stati Uniti, UE e Singapore per un accesso globale stabile.", + "go.privacy.contactAfter": "se hai domande.", + "go.privacy.beforeExceptions": + "I modelli Go sono ospitati negli Stati Uniti. I provider seguono una policy di zero-retention e non usano i tuoi dati per l'addestramento dei modelli, con le", + "go.privacy.exceptionsLink": "seguenti eccezioni", + "go.faq.q1": "Che cos'è OpenCode Go?", + "go.faq.a1": + "Go è un abbonamento a basso costo che ti dà un accesso affidabile a modelli open source capaci per il coding agentico.", + "go.faq.q2": "Quali modelli include Go?", + "go.faq.a2": "Go include GLM-5, Kimi K2.5 e MiniMax M2.5, con limiti generosi e accesso affidabile.", + "go.faq.q3": "Go è lo stesso di Zen?", + "go.faq.a3": + "No. Zen è a consumo, mentre Go è un abbonamento da $10/mese con limiti generosi e accesso affidabile ai modelli open source GLM-5, Kimi K2.5 e MiniMax M2.5.", + "go.faq.q4": "Quanto costa Go?", + "go.faq.a4.p1.beforePricing": "Go costa", + "go.faq.a4.p1.pricingLink": "$10/mese", + "go.faq.a4.p1.afterPricing": "con limiti generosi.", + "go.faq.a4.p2.beforeAccount": "Puoi gestire il tuo abbonamento nel tuo", + "go.faq.a4.p2.accountLink": "account", + "go.faq.a4.p3": "Annulla in qualsiasi momento.", + "go.faq.q5": "E per quanto riguarda dati e privacy?", + "go.faq.a5.body": + "Il piano è progettato principalmente per gli utenti internazionali, con modelli ospitati negli Stati Uniti, UE e Singapore per un accesso globale stabile.", + "go.faq.a5.contactAfter": "se hai domande.", + "go.faq.a5.beforeExceptions": + "I modelli Go sono ospitati negli Stati Uniti. I provider seguono una policy di zero-retention e non usano i tuoi dati per l'addestramento dei modelli, con le", + "go.faq.a5.exceptionsLink": "seguenti eccezioni", + "go.faq.q6": "Posso ricaricare il credito?", + "go.faq.a6": "Se hai bisogno di più utilizzo, puoi ricaricare il credito nel tuo account.", + "go.faq.q7": "Posso annullare?", + "go.faq.a7": "Sì, puoi annullare in qualsiasi momento.", + "go.faq.q8": "Posso usare Go con altri agenti di coding?", + "go.faq.a8": + "Sì, puoi usare Go con qualsiasi agente. Segui le istruzioni di configurazione nel tuo agente di coding preferito.", + + "go.faq.q9": "Qual è la differenza tra i modelli gratuiti e Go?", + "go.faq.a9": + "I modelli gratuiti includono Big Pickle più modelli promozionali disponibili al momento, con una quota di 200 richieste/giorno. Go include GLM-5, Kimi K2.5 e MiniMax M2.5 con quote di richiesta più elevate applicate su finestre mobili (5 ore, settimanale e mensile), approssimativamente equivalenti a $12 ogni 5 ore, $30 a settimana e $60 al mese (il conteggio effettivo delle richieste varia in base al modello e all'utilizzo).", + + "zen.api.error.rateLimitExceeded": "Limite di richieste superato. Riprova più tardi.", + "zen.api.error.modelNotSupported": "Modello {{model}} non supportato", + "zen.api.error.modelFormatNotSupported": "Modello {{model}} non supportato per il formato {{format}}", + "zen.api.error.noProviderAvailable": "Nessun provider disponibile", + "zen.api.error.providerNotSupported": "Provider {{provider}} non supportato", + "zen.api.error.missingApiKey": "Chiave API mancante.", + "zen.api.error.invalidApiKey": "Chiave API non valida.", + "zen.api.error.subscriptionQuotaExceeded": "Quota dell'abbonamento superata. Riprova tra {{retryIn}}.", + "zen.api.error.subscriptionQuotaExceededUseFreeModels": + "Quota dell'abbonamento superata. Puoi continuare a utilizzare modelli gratuiti.", + "zen.api.error.noPaymentMethod": "Nessun metodo di pagamento. Aggiungi un metodo di pagamento qui: {{billingUrl}}", + "zen.api.error.insufficientBalance": "Saldo insufficiente. Gestisci la tua fatturazione qui: {{billingUrl}}", + "zen.api.error.workspaceMonthlyLimitReached": + "La tua area di lavoro ha raggiunto il limite di spesa mensile di ${{amount}}. Gestisci i tuoi limiti qui: {{billingUrl}}", + "zen.api.error.userMonthlyLimitReached": + "Hai raggiunto il tuo limite di spesa mensile di ${{amount}}. Gestisci i tuoi limiti qui: {{membersUrl}}", + "zen.api.error.modelDisabled": "Il modello è disabilitato", + "black.meta.title": "OpenCode Black | Accedi ai migliori modelli di coding al mondo", "black.meta.description": "Ottieni l'accesso a Claude, GPT, Gemini e altri con i piani di abbonamento OpenCode Black.", "black.hero.title": "Accedi ai migliori modelli di coding al mondo", "black.hero.subtitle": "Inclusi Claude, GPT, Gemini e altri", "black.title": "OpenCode Black | Prezzi", + "black.paused": "L'iscrizione al piano Black è temporaneamente sospesa.", "black.plan.icon20": "Piano Black 20", "black.plan.icon100": "Piano Black 100", "black.plan.icon200": "Piano Black 200", @@ -342,12 +470,15 @@ export const dict = { "workspace.usage.table.input": "Input", "workspace.usage.table.output": "Output", "workspace.usage.table.cost": "Costo", + "workspace.usage.table.session": "Sessione", "workspace.usage.breakdown.input": "Input", "workspace.usage.breakdown.cacheRead": "Lettura Cache", "workspace.usage.breakdown.cacheWrite": "Scrittura Cache", "workspace.usage.breakdown.output": "Output", "workspace.usage.breakdown.reasoning": "Reasoning", - "workspace.usage.subscription": "abbonamento (${{amount}})", + "workspace.usage.subscription": "Black (${{amount}})", + "workspace.usage.lite": "Go (${{amount}})", + "workspace.usage.byok": "BYOK (${{amount}})", "workspace.cost.title": "Costo", "workspace.cost.subtitle": "Costi di utilizzo suddivisi per modello.", @@ -446,6 +577,7 @@ export const dict = { "workspace.reload.updatePaymentMethod": "Aggiorna il tuo metodo di pagamento e riprova.", "workspace.reload.retrying": "Riprovo...", "workspace.reload.retry": "Riprova", + "workspace.reload.error.paymentFailed": "Pagamento fallito.", "workspace.payments.title": "Cronologia Pagamenti", "workspace.payments.subtitle": "Transazioni di pagamento recenti.", @@ -484,6 +616,36 @@ export const dict = { "workspace.black.waitlist.enrollNote": "Quando clicchi su Iscriviti, il tuo abbonamento inizia immediatamente e la tua carta verrà addebitata.", + "workspace.lite.loading": "Caricamento...", + "workspace.lite.time.day": "giorno", + "workspace.lite.time.days": "giorni", + "workspace.lite.time.hour": "ora", + "workspace.lite.time.hours": "ore", + "workspace.lite.time.minute": "minuto", + "workspace.lite.time.minutes": "minuti", + "workspace.lite.time.fewSeconds": "pochi secondi", + "workspace.lite.subscription.title": "Abbonamento Go", + "workspace.lite.subscription.message": "Sei abbonato a OpenCode Go.", + "workspace.lite.subscription.manage": "Gestisci Abbonamento", + "workspace.lite.subscription.rollingUsage": "Utilizzo Continuativo", + "workspace.lite.subscription.weeklyUsage": "Utilizzo Settimanale", + "workspace.lite.subscription.monthlyUsage": "Utilizzo Mensile", + "workspace.lite.subscription.resetsIn": "Si resetta tra", + "workspace.lite.subscription.useBalance": "Usa il tuo saldo disponibile dopo aver raggiunto i limiti di utilizzo", + "workspace.lite.subscription.selectProvider": + 'Seleziona "OpenCode Go" come provider nella tua configurazione opencode per utilizzare i modelli Go.', + "workspace.lite.other.title": "Abbonamento Go", + "workspace.lite.other.message": + "Un altro membro in questo workspace è già abbonato a OpenCode Go. Solo un membro per workspace può abbonarsi.", + "workspace.lite.promo.title": "OpenCode Go", + "workspace.lite.promo.description": + "OpenCode Go è un abbonamento a $10 al mese che fornisce un accesso affidabile a popolari modelli di coding aperti con generosi limiti di utilizzo.", + "workspace.lite.promo.modelsTitle": "Cosa è incluso", + "workspace.lite.promo.footer": + "Il piano è progettato principalmente per gli utenti internazionali, con modelli ospitati in US, EU e Singapore per un accesso globale stabile. I prezzi e i limiti di utilizzo potrebbero cambiare man mano che impariamo dall'utilizzo iniziale e dal feedback.", + "workspace.lite.promo.subscribe": "Abbonati a Go", + "workspace.lite.promo.subscribing": "Reindirizzamento...", + "download.title": "OpenCode | Download", "download.meta.description": "Scarica OpenCode per macOS, Windows e Linux", "download.hero.title": "Scarica OpenCode", @@ -534,6 +696,10 @@ export const dict = { "enterprise.form.send": "Invia", "enterprise.form.sending": "Invio...", "enterprise.form.success": "Messaggio inviato, ti contatteremo presto.", + "enterprise.form.success.submitted": "Modulo inviato con successo.", + "enterprise.form.error.allFieldsRequired": "Tutti i campi sono obbligatori.", + "enterprise.form.error.invalidEmailFormat": "Formato email non valido.", + "enterprise.form.error.internalServer": "Errore interno del server.", "enterprise.faq.title": "FAQ", "enterprise.faq.q1": "Cos'è OpenCode Enterprise?", "enterprise.faq.a1": @@ -566,6 +732,7 @@ export const dict = { "bench.list.table.agent": "Agente", "bench.list.table.model": "Modello", "bench.list.table.score": "Punteggio", + "bench.submission.error.allFieldsRequired": "Tutti i campi sono obbligatori.", "bench.detail.title": "Benchmark - {{task}}", "bench.detail.notFound": "Task non trovato", diff --git a/packages/console/app/src/i18n/ja.ts b/packages/console/app/src/i18n/ja.ts index 4dea6ccf4f..f2786ba8d8 100644 --- a/packages/console/app/src/i18n/ja.ts +++ b/packages/console/app/src/i18n/ja.ts @@ -15,6 +15,7 @@ export const dict = { "nav.home": "ホーム", "nav.openMenu": "メニューを開く", "nav.getStartedFree": "無料ではじめる", + "nav.logoAlt": "OpenCode", "nav.context.copyLogo": "ロゴをSVGでコピー", "nav.context.copyWordmark": "ワードマークをSVGでコピー", @@ -42,9 +43,13 @@ export const dict = { "notFound.docs": "ドキュメント", "notFound.github": "GitHub", "notFound.discord": "Discord", + "notFound.logoLightAlt": "opencodeのロゴ(ライト)", + "notFound.logoDarkAlt": "opencodeのロゴ(ダーク)", "user.logout": "ログアウト", + "auth.callback.error.codeMissing": "認証コードが見つかりません。", + "workspace.select": "ワークスペースを選択", "workspace.createNew": "+ 新しいワークスペースを作成", "workspace.modal.title": "新しいワークスペースを作成", @@ -76,6 +81,8 @@ export const dict = { "error.reloadAmountMin": "リロード額は少なくとも ${{amount}} である必要があります", "error.reloadTriggerMin": "残高トリガーは少なくとも ${{amount}} である必要があります", + "app.meta.description": "OpenCode - オープンソースのコーディングエージェント。", + "home.title": "OpenCode | オープンソースのAIコーディングエージェント", "temp.title": "OpenCode | ターミナル向けに構築されたAIコーディングエージェント", @@ -91,6 +98,8 @@ export const dict = { "temp.feature.models.afterLink": "を通じて75以上のLLMプロバイダーをサポート", "temp.screenshot.caption": "tokyonight テーマを使用した OpenCode TUI", "temp.screenshot.alt": "tokyonight テーマの OpenCode TUI", + "temp.logoLightAlt": "opencodeのロゴ(ライト)", + "temp.logoDarkAlt": "opencodeのロゴ(ダーク)", "home.banner.badge": "新着", "home.banner.text": "デスクトップアプリのベータ版が利用可能", @@ -239,11 +248,132 @@ export const dict = { "すべてのZenモデルは米国でホストされています。プロバイダーはゼロ保持ポリシーに従い、モデルのトレーニングにデータを使用しません(", "zen.privacy.exceptionsLink": "以下の例外", + "go.title": "OpenCode Go | すべての人のための低価格なコーディングモデル", + "go.meta.description": + "Goは、GLM-5、Kimi K2.5、MiniMax M2.5を5時間ごとの十分なリクエスト制限で利用できる月額$10のサブスクリプションです。", + "go.hero.title": "すべての人のための低価格なコーディングモデル", + "go.hero.body": + "Goは、世界中のプログラマーにエージェント型コーディングをもたらします。最も高性能なオープンソースモデルへの十分な制限と安定したアクセスを提供し、コストや可用性を気にすることなく強力なエージェントで構築できます。", + + "go.cta.start": "Goを購読する", + "go.cta.template": "{{text}} {{price}}", + "go.cta.text": "Goを購読する", + "go.cta.price": "$10/月", + "go.pricing.body": "任意のエージェントで利用可能。必要に応じてクレジットを追加。いつでもキャンセル可能。", + "go.graph.free": "無料", + "go.graph.freePill": "Big Pickleと無料モデル", + "go.graph.go": "Go", + "go.graph.label": "5時間あたりのリクエスト数", + "go.graph.usageLimits": "利用制限", + "go.graph.tick": "{{n}}倍", + "go.graph.aria": "5時間あたりのリクエスト数: {{free}} 対 {{go}}", + + "go.testimonials.brand.zen": "Zen", + "go.testimonials.brand.go": "Go", + "go.testimonials.handle": "@OpenCode", + "go.testimonials.dax.name": "Dax Raad", + "go.testimonials.dax.title": "元CEO, Terminal Products", + "go.testimonials.dax.quoteAfter": "は人生を変えるものでした。本当に迷う必要はありません。", + "go.testimonials.jay.name": "Jay V", + "go.testimonials.jay.title": "元創業者, SEED, PM, Melt, Pop, Dapt, Cadmus, ViewPoint", + "go.testimonials.jay.quoteBefore": "チームの5人中4人が", + "go.testimonials.jay.quoteAfter": "の使用を気に入っています。", + "go.testimonials.adam.name": "Adam Elmore", + "go.testimonials.adam.title": "元Hero, AWS", + "go.testimonials.adam.quoteBefore": "私は", + "go.testimonials.adam.quoteAfter": "をどれだけ推薦してもしきれません。真剣に、本当に良いです。", + "go.testimonials.david.name": "David Hill", + "go.testimonials.david.title": "元デザイン責任者, Laravel", + "go.testimonials.david.quoteBefore": "", + "go.testimonials.david.quoteAfter": + "を使えば、すべてのモデルがテスト済みでコーディングエージェントに最適だと確信できます。", + "go.testimonials.frank.name": "Frank Wang", + "go.testimonials.frank.title": "元インターン, Nvidia (4回)", + "go.testimonials.frank.quote": "まだNvidiaにいられたらよかったのに。", + "go.problem.title": "Goはどのような問題を解決していますか?", + "go.problem.body": + "私たちは、OpenCodeの体験をできるだけ多くの人々に届けることに注力しています。OpenCode Goは、世界中のプログラマーにエージェント型コーディングをもたらすために設計された低価格($10/月)のサブスクリプションです。最も高性能なオープンソースモデルへの十分な制限と安定したアクセスを提供します。", + "go.problem.subtitle": " ", + "go.problem.item1": "低価格なサブスクリプション料金", + "go.problem.item2": "十分な制限と安定したアクセス", + "go.problem.item3": "できるだけ多くのプログラマーのために構築", + "go.problem.item4": "GLM-5、Kimi K2.5、MiniMax M2.5を含む", + "go.how.title": "Goの仕組み", + "go.how.body": "Goは、OpenCodeまたは任意のエージェントで使用できる月額$10のサブスクリプションです。", + "go.how.step1.title": "アカウントを作成", + "go.how.step1.beforeLink": "", + "go.how.step1.link": "セットアップ手順はこちら", + "go.how.step2.title": "Goを購読する", + "go.how.step2.link": "$10/月", + "go.how.step2.afterLink": "(十分な制限付き)", + "go.how.step3.title": "コーディングを開始", + "go.how.step3.body": "オープンソースモデルへの安定したアクセスで", + "go.privacy.title": "あなたのプライバシーは私たちにとって重要です", + "go.privacy.body": + "このプランは主に海外ユーザー向けに設計されており、米国、EU、シンガポールでホストされたモデルにより安定したグローバルアクセスを提供します。", + "go.privacy.contactAfter": "ご質問がございましたら。", + "go.privacy.beforeExceptions": + "Goのモデルは米国でホストされています。プロバイダーはゼロ保持ポリシーに従い、モデルのトレーニングにデータを使用しません(", + "go.privacy.exceptionsLink": "以下の例外", + "go.faq.q1": "OpenCode Goとは?", + "go.faq.a1": + "Goは、エージェント型コーディングのための有能なオープンソースモデルへの安定したアクセスを提供する低価格なサブスクリプションです。", + "go.faq.q2": "Goにはどのモデルが含まれますか?", + "go.faq.a2": "Goには、GLM-5、Kimi K2.5、MiniMax M2.5が含まれており、十分な制限と安定したアクセスが提供されます。", + "go.faq.q3": "GoはZenと同じですか?", + "go.faq.a3": + "いいえ。Zenは従量課金制ですが、Goは月額$10のサブスクリプションで、GLM-5、Kimi K2.5、MiniMax M2.5といったオープンソースモデルへの十分な制限と安定したアクセスを提供します。", + "go.faq.q4": "Goの料金は?", + "go.faq.a4.p1.beforePricing": "Goは", + "go.faq.a4.p1.pricingLink": "月額$10", + "go.faq.a4.p1.afterPricing": "で、十分な制限が含まれます。", + "go.faq.a4.p2.beforeAccount": "管理画面:", + "go.faq.a4.p2.accountLink": "アカウント", + "go.faq.a4.p3": "いつでもキャンセル可能です。", + "go.faq.q5": "データとプライバシーは?", + "go.faq.a5.body": + "このプランは主に海外ユーザー向けに設計されており、米国、EU、シンガポールでホストされたモデルにより安定したグローバルアクセスを提供します。", + "go.faq.a5.contactAfter": "ご質問がございましたら。", + "go.faq.a5.beforeExceptions": + "Goのモデルは米国でホストされています。プロバイダーはゼロ保持ポリシーに従い、モデルのトレーニングにデータを使用しません(", + "go.faq.a5.exceptionsLink": "以下の例外", + "go.faq.q6": "クレジットをチャージできますか?", + "go.faq.a6": "利用枠を追加したい場合は、アカウントでクレジットをチャージできます。", + "go.faq.q7": "キャンセルできますか?", + "go.faq.a7": "はい、いつでもキャンセル可能です。", + "go.faq.q8": "他のコーディングエージェントでGoを使えますか?", + "go.faq.a8": + "はい、Goは任意のエージェントで使用できます。お使いのコーディングエージェントのセットアップ手順に従ってください。", + + "go.faq.q9": "無料モデルとGoの違いは何ですか?", + "go.faq.a9": + "無料モデルにはBig Pickleと、その時点で利用可能なプロモーションモデルが含まれ、1日200リクエストの制限があります。GoにはGLM-5、Kimi K2.5、MiniMax M2.5が含まれ、ローリングウィンドウ(5時間、週間、月間)全体でより高いリクエスト制限が適用されます。これは概算で5時間あたり$12、週間$30、月間$60相当です(実際のリクエスト数はモデルと使用状況により異なります)。", + + "zen.api.error.rateLimitExceeded": "レート制限を超えました。後でもう一度お試しください。", + "zen.api.error.modelNotSupported": "モデル {{model}} はサポートされていません", + "zen.api.error.modelFormatNotSupported": "フォーマット {{format}} ではモデル {{model}} はサポートされていません", + "zen.api.error.noProviderAvailable": "利用可能なプロバイダーがありません", + "zen.api.error.providerNotSupported": "プロバイダー {{provider}} はサポートされていません", + "zen.api.error.missingApiKey": "APIキーがありません。", + "zen.api.error.invalidApiKey": "無効なAPIキーです。", + "zen.api.error.subscriptionQuotaExceeded": + "サブスクリプションの制限を超えました。{{retryIn}} 後に再試行してください。", + "zen.api.error.subscriptionQuotaExceededUseFreeModels": + "サブスクリプションの制限を超えました。無料モデルは引き続きご利用いただけます。", + "zen.api.error.noPaymentMethod": "お支払い方法がありません。こちらからお支払い方法を追加してください: {{billingUrl}}", + "zen.api.error.insufficientBalance": "残高が不足しています。こちらから請求を管理してください: {{billingUrl}}", + "zen.api.error.workspaceMonthlyLimitReached": + "ワークスペースが月額の利用上限 ${{amount}} に達しました。こちらから上限を管理してください: {{billingUrl}}", + "zen.api.error.userMonthlyLimitReached": + "月額の利用上限 ${{amount}} に達しました。こちらから上限を管理してください: {{membersUrl}}", + "zen.api.error.modelDisabled": "モデルが無効です", + "black.meta.title": "OpenCode Black | 世界最高峰のコーディングモデルすべてにアクセス", "black.meta.description": "OpenCode Black サブスクリプションプランで、Claude、GPT、Gemini などにアクセス。", "black.hero.title": "世界最高峰のコーディングモデルすべてにアクセス", "black.hero.subtitle": "Claude、GPT、Gemini などを含む", "black.title": "OpenCode Black | 料金", + "black.paused": "Blackプランの登録は一時的に停止しています。", "black.plan.icon20": "Black 20 プラン", "black.plan.icon100": "Black 100 プラン", "black.plan.icon200": "Black 200 プラン", @@ -339,12 +469,15 @@ export const dict = { "workspace.usage.table.input": "入力", "workspace.usage.table.output": "出力", "workspace.usage.table.cost": "コスト", + "workspace.usage.table.session": "セッション", "workspace.usage.breakdown.input": "入力", "workspace.usage.breakdown.cacheRead": "キャッシュ読み取り", "workspace.usage.breakdown.cacheWrite": "キャッシュ書き込み", "workspace.usage.breakdown.output": "出力", "workspace.usage.breakdown.reasoning": "推論", - "workspace.usage.subscription": "サブスクリプション (${{amount}})", + "workspace.usage.subscription": "Black (${{amount}})", + "workspace.usage.lite": "Go (${{amount}})", + "workspace.usage.byok": "BYOK (${{amount}})", "workspace.cost.title": "コスト", "workspace.cost.subtitle": "モデルごとの使用料金の内訳。", @@ -443,6 +576,7 @@ export const dict = { "workspace.reload.updatePaymentMethod": "支払い方法を更新して、もう一度お試しください。", "workspace.reload.retrying": "再試行中...", "workspace.reload.retry": "再試行", + "workspace.reload.error.paymentFailed": "支払いに失敗しました。", "workspace.payments.title": "支払い履歴", "workspace.payments.subtitle": "最近の支払い取引。", @@ -482,6 +616,36 @@ export const dict = { "workspace.black.waitlist.enrollNote": "「登録する」をクリックすると、サブスクリプションがすぐに開始され、カードに請求されます。", + "workspace.lite.loading": "読み込み中...", + "workspace.lite.time.day": "日", + "workspace.lite.time.days": "日", + "workspace.lite.time.hour": "時間", + "workspace.lite.time.hours": "時間", + "workspace.lite.time.minute": "分", + "workspace.lite.time.minutes": "分", + "workspace.lite.time.fewSeconds": "数秒", + "workspace.lite.subscription.title": "Goサブスクリプション", + "workspace.lite.subscription.message": "あなたは OpenCode Go を購読しています。", + "workspace.lite.subscription.manage": "サブスクリプションの管理", + "workspace.lite.subscription.rollingUsage": "ローリング利用量", + "workspace.lite.subscription.weeklyUsage": "週間利用量", + "workspace.lite.subscription.monthlyUsage": "月間利用量", + "workspace.lite.subscription.resetsIn": "リセットまで", + "workspace.lite.subscription.useBalance": "利用限度額に達したら利用可能な残高を使用する", + "workspace.lite.subscription.selectProvider": + "Go モデルを使用するには、opencode の設定で「OpenCode Go」をプロバイダーとして選択してください。", + "workspace.lite.other.title": "Goサブスクリプション", + "workspace.lite.other.message": + "このワークスペースの別のメンバーが既に OpenCode Go を購読しています。ワークスペースにつき1人のメンバーのみが購読できます。", + "workspace.lite.promo.title": "OpenCode Go", + "workspace.lite.promo.description": + "OpenCode Goは月額$10のサブスクリプションプランで、人気のオープンコーディングモデルへの安定したアクセスを十分な利用枠で提供します。", + "workspace.lite.promo.modelsTitle": "含まれるもの", + "workspace.lite.promo.footer": + "このプランは主にグローバルユーザー向けに設計されており、米国、EU、シンガポールでホストされたモデルにより安定したグローバルアクセスを提供します。料金と利用制限は、初期の利用状況やフィードバックに基づいて変更される可能性があります。", + "workspace.lite.promo.subscribe": "Goを購読する", + "workspace.lite.promo.subscribing": "リダイレクト中...", + "download.title": "OpenCode | ダウンロード", "download.meta.description": "OpenCode を macOS、Windows、Linux 向けにダウンロード", "download.hero.title": "OpenCode をダウンロード", @@ -533,6 +697,10 @@ export const dict = { "enterprise.form.send": "送信", "enterprise.form.sending": "送信中...", "enterprise.form.success": "送信しました。まもなくご連絡いたします。", + "enterprise.form.success.submitted": "フォームが正常に送信されました。", + "enterprise.form.error.allFieldsRequired": "すべての項目は必須です。", + "enterprise.form.error.invalidEmailFormat": "無効なメール形式です。", + "enterprise.form.error.internalServer": "内部サーバーエラー。", "enterprise.faq.title": "FAQ", "enterprise.faq.q1": "OpenCode Enterpriseとは?", "enterprise.faq.a1": @@ -565,6 +733,7 @@ export const dict = { "bench.list.table.agent": "エージェント", "bench.list.table.model": "モデル", "bench.list.table.score": "スコア", + "bench.submission.error.allFieldsRequired": "すべての項目は必須です。", "bench.detail.title": "ベンチマーク - {{task}}", "bench.detail.notFound": "タスクが見つかりません", diff --git a/packages/console/app/src/i18n/ko.ts b/packages/console/app/src/i18n/ko.ts index 984dbbe67b..169b56c0a3 100644 --- a/packages/console/app/src/i18n/ko.ts +++ b/packages/console/app/src/i18n/ko.ts @@ -15,6 +15,7 @@ export const dict = { "nav.home": "홈", "nav.openMenu": "메뉴 열기", "nav.getStartedFree": "무료로 시작하기", + "nav.logoAlt": "OpenCode", "nav.context.copyLogo": "로고를 SVG로 복사", "nav.context.copyWordmark": "워드마크를 SVG로 복사", @@ -42,9 +43,13 @@ export const dict = { "notFound.docs": "문서", "notFound.github": "GitHub", "notFound.discord": "Discord", + "notFound.logoLightAlt": "opencode 밝은 로고", + "notFound.logoDarkAlt": "opencode 어두운 로고", "user.logout": "로그아웃", + "auth.callback.error.codeMissing": "인증 코드를 찾을 수 없습니다.", + "workspace.select": "워크스페이스 선택", "workspace.createNew": "+ 새 워크스페이스 만들기", "workspace.modal.title": "새 워크스페이스 만들기", @@ -76,6 +81,8 @@ export const dict = { "error.reloadAmountMin": "충전 금액은 최소 ${{amount}}이어야 합니다", "error.reloadTriggerMin": "잔액 트리거는 최소 ${{amount}}이어야 합니다", + "app.meta.description": "OpenCode - 오픈 소스 코딩 에이전트.", + "home.title": "OpenCode | 오픈 소스 AI 코딩 에이전트", "temp.title": "OpenCode | 터미널을 위해 만들어진 AI 코딩 에이전트", @@ -91,6 +98,8 @@ export const dict = { "temp.feature.models.afterLink": "를 통해 75개 이상의 LLM 제공자 지원", "temp.screenshot.caption": "tokyonight 테마가 적용된 OpenCode TUI", "temp.screenshot.alt": "tokyonight 테마가 적용된 OpenCode TUI", + "temp.logoLightAlt": "opencode 밝은 로고", + "temp.logoDarkAlt": "opencode 어두운 로고", "home.banner.badge": "신규", "home.banner.text": "데스크톱 앱 베타 버전 출시", @@ -236,11 +245,129 @@ export const dict = { "모든 Zen 모델은 미국에서 호스팅됩니다. 제공자들은 데이터 보존 금지 정책을 따르며 모델 학습에 데이터를 사용하지 않습니다. 단,", "zen.privacy.exceptionsLink": "다음 예외", + "go.title": "OpenCode Go | 모두를 위한 저비용 코딩 모델", + "go.meta.description": + "Go는 GLM-5, Kimi K2.5, MiniMax M2.5에 대해 넉넉한 5시간 요청 한도를 제공하는 월 $10 구독입니다.", + "go.hero.title": "모두를 위한 저비용 코딩 모델", + "go.hero.body": + "Go는 전 세계 프로그래머들에게 에이전트 코딩을 제공합니다. 가장 유능한 오픈 소스 모델에 대한 넉넉한 한도와 안정적인 액세스를 제공하므로, 비용이나 가용성 걱정 없이 강력한 에이전트로 빌드할 수 있습니다.", + + "go.cta.start": "Go 구독하기", + "go.cta.template": "{{text}} {{price}}", + "go.cta.text": "Go 구독하기", + "go.cta.price": "$10/월", + "go.pricing.body": "모든 에이전트와 함께 사용하세요. 필요 시 크레딧을 충전하세요. 언제든지 취소 가능.", + "go.graph.free": "무료", + "go.graph.freePill": "Big Pickle 및 무료 모델", + "go.graph.go": "Go", + "go.graph.label": "5시간당 요청 수", + "go.graph.usageLimits": "사용 한도", + "go.graph.tick": "{{n}}배", + "go.graph.aria": "5시간당 요청 수: {{free}} 대 {{go}}", + + "go.testimonials.brand.zen": "Zen", + "go.testimonials.brand.go": "Go", + "go.testimonials.handle": "@OpenCode", + "go.testimonials.dax.name": "Dax Raad", + "go.testimonials.dax.title": "전 Terminal Products CEO", + "go.testimonials.dax.quoteAfter": "(은)는 삶을 변화시켰습니다. 정말 당연한 선택입니다.", + "go.testimonials.jay.name": "Jay V", + "go.testimonials.jay.title": "전 Founder, SEED, PM, Melt, Pop, Dapt, Cadmus, ViewPoint", + "go.testimonials.jay.quoteBefore": "우리 팀 5명 중 4명이", + "go.testimonials.jay.quoteAfter": " 사용을 정말 좋아합니다.", + "go.testimonials.adam.name": "Adam Elmore", + "go.testimonials.adam.title": "전 AWS Hero", + "go.testimonials.adam.quoteBefore": "저는", + "go.testimonials.adam.quoteAfter": "를(을) 아무리 추천해도 부족합니다. 진심으로 정말 좋습니다.", + "go.testimonials.david.name": "David Hill", + "go.testimonials.david.title": "전 Laravel 디자인 총괄", + "go.testimonials.david.quoteBefore": "", + "go.testimonials.david.quoteAfter": + "와(과) 함께라면 모든 모델이 테스트를 거쳤고 코딩 에이전트에 완벽하다는 것을 알 수 있습니다.", + "go.testimonials.frank.name": "Frank Wang", + "go.testimonials.frank.title": "전 Nvidia 인턴 (4회)", + "go.testimonials.frank.quote": "아직 Nvidia에 있었으면 좋았을 텐데요.", + "go.problem.title": "Go는 어떤 문제를 해결하나요?", + "go.problem.body": + "우리는 가능한 한 많은 사람들에게 OpenCode 경험을 제공하는 데 집중하고 있습니다. OpenCode Go는 전 세계 프로그래머들에게 에이전트 코딩을 제공하기 위해 설계된 저렴한(월 $10) 구독입니다. 가장 유능한 오픈 소스 모델에 대해 넉넉한 한도와 안정적인 액세스를 제공합니다.", + "go.problem.subtitle": " ", + "go.problem.item1": "저렴한 구독 가격", + "go.problem.item2": "넉넉한 한도와 안정적인 액세스", + "go.problem.item3": "가능한 한 많은 프로그래머를 위해 제작됨", + "go.problem.item4": "GLM-5, Kimi K2.5, MiniMax M2.5 포함", + "go.how.title": "Go 작동 방식", + "go.how.body": "Go는 OpenCode 또는 다른 어떤 에이전트와도 사용할 수 있는 월 $10 구독입니다.", + "go.how.step1.title": "계정 생성", + "go.how.step1.beforeLink": "", + "go.how.step1.link": "설정 지침을 따르세요", + "go.how.step2.title": "Go 구독", + "go.how.step2.link": "$10/월", + "go.how.step2.afterLink": "(넉넉한 한도 포함)", + "go.how.step3.title": "코딩 시작", + "go.how.step3.body": "오픈 소스 모델에 대한 안정적인 액세스와 함께", + "go.privacy.title": "귀하의 프라이버시는 우리에게 중요합니다", + "go.privacy.body": + "이 플랜은 주로 글로벌 사용자를 위해 설계되었으며, 안정적인 글로벌 액세스를 위해 미국, EU, 싱가포르에 모델이 호스팅되어 있습니다.", + "go.privacy.contactAfter": "질문이 있으시면 언제든지 문의해 주세요.", + "go.privacy.beforeExceptions": + "Go 모델은 미국에서 호스팅됩니다. 제공자들은 데이터 보존 금지 정책을 따르며 모델 학습에 데이터를 사용하지 않습니다. 단,", + "go.privacy.exceptionsLink": "다음 예외", + "go.faq.q1": "OpenCode Go란 무엇인가요?", + "go.faq.a1": "Go는 에이전트 코딩을 위한 유능한 오픈 소스 모델에 대해 안정적인 액세스를 제공하는 저비용 구독입니다.", + "go.faq.q2": "Go에는 어떤 모델이 포함되나요?", + "go.faq.a2": "Go에는 넉넉한 한도와 안정적인 액세스를 제공하는 GLM-5, Kimi K2.5, MiniMax M2.5가 포함됩니다.", + "go.faq.q3": "Go는 Zen과 같은가요?", + "go.faq.a3": + "아니요. Zen은 사용한 만큼 지불(pay-as-you-go)하는 방식인 반면, Go는 월 $10 구독으로 오픈 소스 모델인 GLM-5, Kimi K2.5, MiniMax M2.5에 대해 넉넉한 한도와 안정적인 액세스를 제공합니다.", + "go.faq.q4": "Go 비용은 얼마인가요?", + "go.faq.a4.p1.beforePricing": "Go 비용은", + "go.faq.a4.p1.pricingLink": "$10/월", + "go.faq.a4.p1.afterPricing": "이며 넉넉한 한도를 제공합니다.", + "go.faq.a4.p2.beforeAccount": "구독 관리는 다음에서 가능합니다:", + "go.faq.a4.p2.accountLink": "계정", + "go.faq.a4.p3": "언제든지 취소할 수 있습니다.", + "go.faq.q5": "데이터와 프라이버시는 어떤가요?", + "go.faq.a5.body": + "이 플랜은 주로 글로벌 사용자를 위해 설계되었으며, 안정적인 글로벌 액세스를 위해 미국, EU, 싱가포르에 모델이 호스팅되어 있습니다.", + "go.faq.a5.contactAfter": "질문이 있으시면 언제든지 문의해 주세요.", + "go.faq.a5.beforeExceptions": + "Go 모델은 미국에서 호스팅됩니다. 제공자들은 데이터 보존 금지 정책을 따르며 모델 학습에 데이터를 사용하지 않습니다. 단,", + "go.faq.a5.exceptionsLink": "다음 예외", + "go.faq.q6": "크레딧을 충전할 수 있나요?", + "go.faq.a6": "사용량이 더 필요한 경우 계정에서 크레딧을 충전할 수 있습니다.", + "go.faq.q7": "취소할 수 있나요?", + "go.faq.a7": "네, 언제든지 취소할 수 있습니다.", + "go.faq.q8": "다른 코딩 에이전트와 Go를 사용할 수 있나요?", + "go.faq.a8": "네, Go는 어떤 에이전트와도 사용할 수 있습니다. 선호하는 코딩 에이전트의 설정 지침을 따르세요.", + + "go.faq.q9": "무료 모델과 Go의 차이점은 무엇인가요?", + "go.faq.a9": + "무료 모델에는 Big Pickle과 당시 사용 가능한 프로모션 모델이 포함되며, 하루 200회 요청 할당량이 적용됩니다. Go는 GLM-5, Kimi K2.5, MiniMax M2.5를 포함하며, 롤링 윈도우(5시간, 주간, 월간)에 걸쳐 더 높은 요청 할당량을 적용합니다. 이는 대략 5시간당 $12, 주당 $30, 월 $60에 해당합니다(실제 요청 수는 모델 및 사용량에 따라 다름).", + + "zen.api.error.rateLimitExceeded": "속도 제한을 초과했습니다. 나중에 다시 시도해 주세요.", + "zen.api.error.modelNotSupported": "{{model}} 모델은 지원되지 않습니다", + "zen.api.error.modelFormatNotSupported": "{{model}} 모델은 {{format}} 형식에 대해 지원되지 않습니다", + "zen.api.error.noProviderAvailable": "사용 가능한 제공자가 없습니다", + "zen.api.error.providerNotSupported": "{{provider}} 제공자는 지원되지 않습니다", + "zen.api.error.missingApiKey": "API 키가 누락되었습니다.", + "zen.api.error.invalidApiKey": "유효하지 않은 API 키입니다.", + "zen.api.error.subscriptionQuotaExceeded": "구독 할당량을 초과했습니다. {{retryIn}} 후 다시 시도해 주세요.", + "zen.api.error.subscriptionQuotaExceededUseFreeModels": + "구독 할당량을 초과했습니다. 무료 모델은 계속 사용할 수 있습니다.", + "zen.api.error.noPaymentMethod": "결제 수단이 없습니다. 결제 수단을 추가하세요: {{billingUrl}}", + "zen.api.error.insufficientBalance": "잔액이 부족합니다. 결제 관리를 여기서 하세요: {{billingUrl}}", + "zen.api.error.workspaceMonthlyLimitReached": + "워크스페이스의 월간 지출 한도인 ${{amount}}에 도달했습니다. 한도 관리를 여기서 하세요: {{billingUrl}}", + "zen.api.error.userMonthlyLimitReached": + "월간 지출 한도인 ${{amount}}에 도달했습니다. 한도 관리를 여기서 하세요: {{membersUrl}}", + "zen.api.error.modelDisabled": "모델이 비활성화되었습니다", + "black.meta.title": "OpenCode Black | 세계 최고의 코딩 모델에 액세스하세요", "black.meta.description": "OpenCode Black 구독 플랜으로 Claude, GPT, Gemini 등에 액세스하세요.", "black.hero.title": "세계 최고의 코딩 모델에 액세스하세요", "black.hero.subtitle": "Claude, GPT, Gemini 등 포함", "black.title": "OpenCode Black | 가격", + "black.paused": "Black 플랜 등록이 일시적으로 중단되었습니다.", "black.plan.icon20": "Black 20 플랜", "black.plan.icon100": "Black 100 플랜", "black.plan.icon200": "Black 200 플랜", @@ -336,12 +463,15 @@ export const dict = { "workspace.usage.table.input": "입력", "workspace.usage.table.output": "출력", "workspace.usage.table.cost": "비용", + "workspace.usage.table.session": "세션", "workspace.usage.breakdown.input": "입력", "workspace.usage.breakdown.cacheRead": "캐시 읽기", "workspace.usage.breakdown.cacheWrite": "캐시 쓰기", "workspace.usage.breakdown.output": "출력", "workspace.usage.breakdown.reasoning": "추론", - "workspace.usage.subscription": "구독 (${{amount}})", + "workspace.usage.subscription": "Black (${{amount}})", + "workspace.usage.lite": "Go (${{amount}})", + "workspace.usage.byok": "BYOK (${{amount}})", "workspace.cost.title": "비용", "workspace.cost.subtitle": "모델별 사용 비용 내역.", @@ -440,6 +570,7 @@ export const dict = { "workspace.reload.updatePaymentMethod": "결제 수단을 업데이트하고 다시 시도해 주세요.", "workspace.reload.retrying": "재시도 중...", "workspace.reload.retry": "재시도", + "workspace.reload.error.paymentFailed": "결제에 실패했습니다.", "workspace.payments.title": "결제 내역", "workspace.payments.subtitle": "최근 결제 거래 내역입니다.", @@ -477,6 +608,36 @@ export const dict = { "workspace.black.waitlist.enrolled": "등록됨", "workspace.black.waitlist.enrollNote": "등록을 클릭하면 구독이 즉시 시작되며 카드에 요금이 청구됩니다.", + "workspace.lite.loading": "로드 중...", + "workspace.lite.time.day": "일", + "workspace.lite.time.days": "일", + "workspace.lite.time.hour": "시간", + "workspace.lite.time.hours": "시간", + "workspace.lite.time.minute": "분", + "workspace.lite.time.minutes": "분", + "workspace.lite.time.fewSeconds": "몇 초", + "workspace.lite.subscription.title": "Go 구독", + "workspace.lite.subscription.message": "현재 OpenCode Go를 구독 중입니다.", + "workspace.lite.subscription.manage": "구독 관리", + "workspace.lite.subscription.rollingUsage": "롤링 사용량", + "workspace.lite.subscription.weeklyUsage": "주간 사용량", + "workspace.lite.subscription.monthlyUsage": "월간 사용량", + "workspace.lite.subscription.resetsIn": "초기화까지 남은 시간:", + "workspace.lite.subscription.useBalance": "사용 한도 도달 후에는 보유 잔액 사용", + "workspace.lite.subscription.selectProvider": + 'Go 모델을 사용하려면 opencode 설정에서 "OpenCode Go"를 공급자로 선택하세요.', + "workspace.lite.other.title": "Go 구독", + "workspace.lite.other.message": + "이 워크스페이스의 다른 멤버가 이미 OpenCode Go를 구독 중입니다. 워크스페이스당 한 명의 멤버만 구독할 수 있습니다.", + "workspace.lite.promo.title": "OpenCode Go", + "workspace.lite.promo.description": + "OpenCode Go는 넉넉한 사용 한도와 함께 인기 있는 오픈 코딩 모델에 대한 안정적인 액세스를 제공하는 월 $10의 구독입니다.", + "workspace.lite.promo.modelsTitle": "포함 내역", + "workspace.lite.promo.footer": + "이 플랜은 주로 글로벌 사용자를 위해 설계되었으며, 안정적인 글로벌 액세스를 위해 미국, EU 및 싱가포르에 모델이 호스팅되어 있습니다. 가격 및 사용 한도는 초기 사용을 통해 학습하고 피드백을 수집함에 따라 변경될 수 있습니다.", + "workspace.lite.promo.subscribe": "Go 구독하기", + "workspace.lite.promo.subscribing": "리디렉션 중...", + "download.title": "OpenCode | 다운로드", "download.meta.description": "macOS, Windows, Linux용 OpenCode 다운로드", "download.hero.title": "OpenCode 다운로드", @@ -527,6 +688,10 @@ export const dict = { "enterprise.form.send": "전송", "enterprise.form.sending": "전송 중...", "enterprise.form.success": "메시지가 전송되었습니다. 곧 연락드리겠습니다.", + "enterprise.form.success.submitted": "양식이 성공적으로 제출되었습니다.", + "enterprise.form.error.allFieldsRequired": "모든 필드는 필수 항목입니다.", + "enterprise.form.error.invalidEmailFormat": "유효하지 않은 이메일 형식입니다.", + "enterprise.form.error.internalServer": "내부 서버 오류입니다.", "enterprise.faq.title": "FAQ", "enterprise.faq.q1": "OpenCode 엔터프라이즈란 무엇인가요?", "enterprise.faq.a1": @@ -559,6 +724,7 @@ export const dict = { "bench.list.table.agent": "에이전트", "bench.list.table.model": "모델", "bench.list.table.score": "점수", + "bench.submission.error.allFieldsRequired": "모든 필드는 필수 항목입니다.", "bench.detail.title": "벤치마크 - {{task}}", "bench.detail.notFound": "태스크를 찾을 수 없음", diff --git a/packages/console/app/src/i18n/no.ts b/packages/console/app/src/i18n/no.ts index 1f9b1b2464..0b6e76e0c3 100644 --- a/packages/console/app/src/i18n/no.ts +++ b/packages/console/app/src/i18n/no.ts @@ -15,6 +15,7 @@ export const dict = { "nav.home": "Hjem", "nav.openMenu": "Åpne meny", "nav.getStartedFree": "Kom i gang gratis", + "nav.logoAlt": "OpenCode", "nav.context.copyLogo": "Kopier logo som SVG", "nav.context.copyWordmark": "Kopier wordmark som SVG", @@ -42,9 +43,13 @@ export const dict = { "notFound.docs": "Dokumentasjon", "notFound.github": "GitHub", "notFound.discord": "Discord", + "notFound.logoLightAlt": "opencode logo lys", + "notFound.logoDarkAlt": "opencode logo mørk", "user.logout": "Logg ut", + "auth.callback.error.codeMissing": "Ingen autorisasjonskode funnet.", + "workspace.select": "Velg arbeidsområde", "workspace.createNew": "+ Opprett nytt arbeidsområde", "workspace.modal.title": "Opprett nytt arbeidsområde", @@ -76,6 +81,8 @@ export const dict = { "error.reloadAmountMin": "Påfyllingsbeløp må være minst ${{amount}}", "error.reloadTriggerMin": "Saldo-trigger må være minst ${{amount}}", + "app.meta.description": "OpenCode - Den åpne kildekode kodingsagenten.", + "home.title": "OpenCode | Den åpne kildekode AI-kodingsagenten", "temp.title": "opencode | AI-kodingsagent bygget for terminalen", @@ -91,6 +98,8 @@ export const dict = { "temp.feature.models.afterLink": ", inkludert lokale modeller", "temp.screenshot.caption": "opencode TUI med tokyonight-tema", "temp.screenshot.alt": "opencode TUI med tokyonight-tema", + "temp.logoLightAlt": "opencode logo lys", + "temp.logoDarkAlt": "opencode logo mørk", "home.banner.badge": "Ny", "home.banner.text": "Desktop-app tilgjengelig i beta", @@ -240,11 +249,130 @@ export const dict = { "Alle Zen-modeller hostes i USA. Leverandører følger en policy om null oppbevaring og bruker ikke dataene dine til modelltrening, med", "zen.privacy.exceptionsLink": "følgende unntak", + "go.title": "OpenCode Go | Rimelige kodemodeller for alle", + "go.meta.description": + "Go er et abonnement til $10/måned med rause grenser på 5 timer for GLM-5, Kimi K2.5 og MiniMax M2.5.", + "go.hero.title": "Rimelige kodemodeller for alle", + "go.hero.body": + "Go bringer agent-koding til programmerere over hele verden. Med rause grenser og pålitelig tilgang til de mest kapable åpen kildekode-modellene, kan du bygge med kraftige agenter uten å bekymre deg for kostnader eller tilgjengelighet.", + + "go.cta.start": "Abonner på Go", + "go.cta.template": "{{text}} {{price}}", + "go.cta.text": "Abonner på Go", + "go.cta.price": "$10/måned", + "go.pricing.body": "Bruk med hvilken som helst agent. Fyll på kreditt om nødvendig. Avslutt når som helst.", + "go.graph.free": "Gratis", + "go.graph.freePill": "Big Pickle og gratis modeller", + "go.graph.go": "Go", + "go.graph.label": "Forespørsler per 5 timer", + "go.graph.usageLimits": "Bruksgrenser", + "go.graph.tick": "{{n}}x", + "go.graph.aria": "Forespørsler per 5t: {{free}} vs {{go}}", + + "go.testimonials.brand.zen": "Zen", + "go.testimonials.brand.go": "Go", + "go.testimonials.handle": "@OpenCode", + "go.testimonials.dax.name": "Dax Raad", + "go.testimonials.dax.title": "tidligere CEO, Terminal Products", + "go.testimonials.dax.quoteAfter": "har endret livet mitt, det er virkelig en no-brainer.", + "go.testimonials.jay.name": "Jay V", + "go.testimonials.jay.title": "tidligere grunnlegger, SEED, PM, Melt, Pop, Dapt, Cadmus og ViewPoint", + "go.testimonials.jay.quoteBefore": "4 av 5 personer på teamet vårt elsker å bruke", + "go.testimonials.jay.quoteAfter": ".", + "go.testimonials.adam.name": "Adam Elmore", + "go.testimonials.adam.title": "tidligere Hero, AWS", + "go.testimonials.adam.quoteBefore": "Jeg kan ikke anbefale", + "go.testimonials.adam.quoteAfter": "nok. Seriøst, det er virkelig bra.", + "go.testimonials.david.name": "David Hill", + "go.testimonials.david.title": "tidligere Head of Design, Laravel", + "go.testimonials.david.quoteBefore": "Med", + "go.testimonials.david.quoteAfter": "vet jeg at alle modellene er testet og perfekte for kodeagenter.", + "go.testimonials.frank.name": "Frank Wang", + "go.testimonials.frank.title": "tidligere intern, Nvidia (4 ganger)", + "go.testimonials.frank.quote": "Jeg skulle ønske jeg fortsatt var hos Nvidia.", + "go.problem.title": "Hvilket problem løser Go?", + "go.problem.body": + "Vi fokuserer på å bringe OpenCode-opplevelsen til så mange mennesker som mulig. OpenCode Go er et rimelig ($10/måned) abonnement designet for å bringe agent-koding til programmerere over hele verden. Det gir rause grenser og pålitelig tilgang til de mest kapable åpen kildekode-modellene.", + "go.problem.subtitle": " ", + "go.problem.item1": "Rimelig abonnementspris", + "go.problem.item2": "Rause grenser og pålitelig tilgang", + "go.problem.item3": "Bygget for så mange programmerere som mulig", + "go.problem.item4": "Inkluderer GLM-5, Kimi K2.5 og MiniMax M2.5", + "go.how.title": "Hvordan Go fungerer", + "go.how.body": "Go er et abonnement til $10/måned som du kan bruke med OpenCode eller hvilken som helst agent.", + "go.how.step1.title": "Opprett en konto", + "go.how.step1.beforeLink": "følg", + "go.how.step1.link": "oppsettsinstruksjonene", + "go.how.step2.title": "Abonner på Go", + "go.how.step2.link": "$10/måned", + "go.how.step2.afterLink": "med rause grenser", + "go.how.step3.title": "Begynn å kode", + "go.how.step3.body": "med pålitelig tilgang til åpen kildekode-modeller", + "go.privacy.title": "Personvernet ditt er viktig for oss", + "go.privacy.body": + "Planen er primært designet for internasjonale brukere, med modeller driftet i USA, EU og Singapore for stabil global tilgang.", + "go.privacy.contactAfter": "hvis du har spørsmål.", + "go.privacy.beforeExceptions": + "Go-modeller hostes i USA. Leverandører følger en policy om null oppbevaring og bruker ikke dataene dine til modelltrening, med", + "go.privacy.exceptionsLink": "følgende unntak", + "go.faq.q1": "Hva er OpenCode Go?", + "go.faq.a1": + "Go er et rimelig abonnement som gir deg pålitelig tilgang til kapable åpen kildekode-modeller for agent-koding.", + "go.faq.q2": "Hvilke modeller inkluderer Go?", + "go.faq.a2": "Go inkluderer GLM-5, Kimi K2.5 og MiniMax M2.5, med rause grenser og pålitelig tilgang.", + "go.faq.q3": "Er Go det samme som Zen?", + "go.faq.a3": + "Nei. Zen er pay-as-you-go, mens Go er et abonnement til $10/måned med rause grenser og pålitelig tilgang til åpen kildekode-modellene GLM-5, Kimi K2.5 og MiniMax M2.5.", + "go.faq.q4": "Hva koster Go?", + "go.faq.a4.p1.beforePricing": "Go koster", + "go.faq.a4.p1.pricingLink": "$10/måned", + "go.faq.a4.p1.afterPricing": "med rause grenser.", + "go.faq.a4.p2.beforeAccount": "Du kan administrere abonnementet ditt i din", + "go.faq.a4.p2.accountLink": "konto", + "go.faq.a4.p3": "Avslutt når som helst.", + "go.faq.q5": "Hva med data og personvern?", + "go.faq.a5.body": + "Planen er primært designet for internasjonale brukere, med modeller driftet i USA, EU og Singapore for stabil global tilgang.", + "go.faq.a5.contactAfter": "hvis du har spørsmål.", + "go.faq.a5.beforeExceptions": + "Go-modeller hostes i USA. Leverandører følger en policy om null oppbevaring og bruker ikke dataene dine til modelltrening, med", + "go.faq.a5.exceptionsLink": "følgende unntak", + "go.faq.q6": "Kan jeg fylle på kreditt?", + "go.faq.a6": "Hvis du trenger mer bruk, kan du fylle på kreditt i kontoen din.", + "go.faq.q7": "Kan jeg avslutte?", + "go.faq.a7": "Ja, du kan avslutte når som helst.", + "go.faq.q8": "Kan jeg bruke Go med andre kodeagenter?", + "go.faq.a8": + "Ja, du kan bruke Go med hvilken som helst agent. Følg oppsettinstruksjonene i din foretrukne kodeagent.", + + "go.faq.q9": "Hva er forskjellen mellom gratis modeller og Go?", + "go.faq.a9": + "Gratis modeller inkluderer Big Pickle pluss kampanjemodeller tilgjengelig på det tidspunktet, med en kvote på 200 forespørsler/dag. Go inkluderer GLM-5, Kimi K2.5 og MiniMax M2.5 med høyere kvoter håndhevet over rullerende vinduer (5 timer, ukentlig og månedlig), omtrent tilsvarende $12 per 5 timer, $30 per uke og $60 per måned (faktiske forespørselsantall varierer etter modell og bruk).", + + "zen.api.error.rateLimitExceeded": "Rate limit overskredet. Vennligst prøv igjen senere.", + "zen.api.error.modelNotSupported": "Modell {{model}} støttes ikke", + "zen.api.error.modelFormatNotSupported": "Modell {{model}} støttes ikke for format {{format}}", + "zen.api.error.noProviderAvailable": "Ingen leverandør tilgjengelig", + "zen.api.error.providerNotSupported": "Leverandør {{provider}} støttes ikke", + "zen.api.error.missingApiKey": "Mangler API-nøkkel.", + "zen.api.error.invalidApiKey": "Ugyldig API-nøkkel.", + "zen.api.error.subscriptionQuotaExceeded": "Abonnementskvote overskredet. Prøv igjen om {{retryIn}}.", + "zen.api.error.subscriptionQuotaExceededUseFreeModels": + "Abonnementskvote overskredet. Du kan fortsette å bruke gratis modeller.", + "zen.api.error.noPaymentMethod": "Ingen betalingsmetode. Legg til en betalingsmetode her: {{billingUrl}}", + "zen.api.error.insufficientBalance": "Utilstrekkelig saldo. Administrer faktureringen din her: {{billingUrl}}", + "zen.api.error.workspaceMonthlyLimitReached": + "Arbeidsområdet ditt har nådd sin månedlige utgiftsgrense på ${{amount}}. Administrer grensene dine her: {{billingUrl}}", + "zen.api.error.userMonthlyLimitReached": + "Du har nådd din månedlige utgiftsgrense på ${{amount}}. Administrer grensene dine her: {{membersUrl}}", + "zen.api.error.modelDisabled": "Modellen er deaktivert", + "black.meta.title": "OpenCode Black | Få tilgang til verdens beste kodemodeller", "black.meta.description": "Få tilgang til Claude, GPT, Gemini og mer med OpenCode Black-abonnementer.", "black.hero.title": "Få tilgang til verdens beste kodemodeller", "black.hero.subtitle": "Inkludert Claude, GPT, Gemini og mer", "black.title": "OpenCode Black | Priser", + "black.paused": "Black-planregistrering er midlertidig satt på pause.", "black.plan.icon20": "Black 20-plan", "black.plan.icon100": "Black 100-plan", "black.plan.icon200": "Black 200-plan", @@ -340,12 +468,15 @@ export const dict = { "workspace.usage.table.input": "Input", "workspace.usage.table.output": "Output", "workspace.usage.table.cost": "Kostnad", + "workspace.usage.table.session": "Økt", "workspace.usage.breakdown.input": "Input", "workspace.usage.breakdown.cacheRead": "Cache Lest", "workspace.usage.breakdown.cacheWrite": "Cache Skrevet", "workspace.usage.breakdown.output": "Output", "workspace.usage.breakdown.reasoning": "Resonnering", - "workspace.usage.subscription": "abonnement (${{amount}})", + "workspace.usage.subscription": "Black (${{amount}})", + "workspace.usage.lite": "Go (${{amount}})", + "workspace.usage.byok": "BYOK (${{amount}})", "workspace.cost.title": "Kostnad", "workspace.cost.subtitle": "Brukskostnader fordelt på modell.", @@ -444,6 +575,7 @@ export const dict = { "workspace.reload.updatePaymentMethod": "Vennligst oppdater betalingsmetoden din og prøv på nytt.", "workspace.reload.retrying": "Prøver på nytt...", "workspace.reload.retry": "Prøv på nytt", + "workspace.reload.error.paymentFailed": "Betaling mislyktes.", "workspace.payments.title": "Betalingshistorikk", "workspace.payments.subtitle": "Nylige betalingstransaksjoner.", @@ -482,6 +614,36 @@ export const dict = { "workspace.black.waitlist.enrollNote": "Når du klikker på Meld på, starter abonnementet umiddelbart og kortet ditt belastes.", + "workspace.lite.loading": "Laster...", + "workspace.lite.time.day": "dag", + "workspace.lite.time.days": "dager", + "workspace.lite.time.hour": "time", + "workspace.lite.time.hours": "timer", + "workspace.lite.time.minute": "minutt", + "workspace.lite.time.minutes": "minutter", + "workspace.lite.time.fewSeconds": "noen få sekunder", + "workspace.lite.subscription.title": "Go-abonnement", + "workspace.lite.subscription.message": "Du abonnerer på OpenCode Go.", + "workspace.lite.subscription.manage": "Administrer abonnement", + "workspace.lite.subscription.rollingUsage": "Løpende bruk", + "workspace.lite.subscription.weeklyUsage": "Ukentlig bruk", + "workspace.lite.subscription.monthlyUsage": "Månedlig bruk", + "workspace.lite.subscription.resetsIn": "Nullstilles om", + "workspace.lite.subscription.useBalance": "Bruk din tilgjengelige saldo etter å ha nådd bruksgrensene", + "workspace.lite.subscription.selectProvider": + 'Velg "OpenCode Go" som leverandør i opencode-konfigurasjonen din for å bruke Go-modeller.', + "workspace.lite.other.title": "Go-abonnement", + "workspace.lite.other.message": + "Et annet medlem i dette arbeidsområdet abonnerer allerede på OpenCode Go. Kun ett medlem per arbeidsområde kan abonnere.", + "workspace.lite.promo.title": "OpenCode Go", + "workspace.lite.promo.description": + "OpenCode Go er et abonnement til $10 per måned som gir pålitelig tilgang til populære åpne kodemodeller med rause bruksgrenser.", + "workspace.lite.promo.modelsTitle": "Hva som er inkludert", + "workspace.lite.promo.footer": + "Planen er primært designet for internasjonale brukere, med modeller driftet i USA, EU og Singapore for stabil global tilgang. Priser og bruksgrenser kan endres etter hvert som vi lærer fra tidlig bruk og tilbakemeldinger.", + "workspace.lite.promo.subscribe": "Abonner på Go", + "workspace.lite.promo.subscribing": "Omdirigerer...", + "download.title": "OpenCode | Last ned", "download.meta.description": "Last ned OpenCode for macOS, Windows og Linux", "download.hero.title": "Last ned OpenCode", @@ -532,6 +694,10 @@ export const dict = { "enterprise.form.send": "Send", "enterprise.form.sending": "Sender...", "enterprise.form.success": "Melding sendt, vi tar kontakt snart.", + "enterprise.form.success.submitted": "Skjemaet ble sendt inn.", + "enterprise.form.error.allFieldsRequired": "Alle felt er obligatoriske.", + "enterprise.form.error.invalidEmailFormat": "Ugyldig e-postformat.", + "enterprise.form.error.internalServer": "Intern serverfeil.", "enterprise.faq.title": "FAQ", "enterprise.faq.q1": "Hva er OpenCode Enterprise?", "enterprise.faq.a1": @@ -564,6 +730,7 @@ export const dict = { "bench.list.table.agent": "Agent", "bench.list.table.model": "Modell", "bench.list.table.score": "Poengsum", + "bench.submission.error.allFieldsRequired": "Alle felt er obligatoriske.", "bench.detail.title": "Benchmark - {{task}}", "bench.detail.notFound": "Oppgave ikke funnet", diff --git a/packages/console/app/src/i18n/pl.ts b/packages/console/app/src/i18n/pl.ts index f35300710c..b46280ae15 100644 --- a/packages/console/app/src/i18n/pl.ts +++ b/packages/console/app/src/i18n/pl.ts @@ -14,6 +14,7 @@ export const dict = { "nav.home": "Strona główna", "nav.openMenu": "Otwórz menu", "nav.getStartedFree": "Zacznij za darmo", + "nav.logoAlt": "OpenCode", "nav.context.copyLogo": "Skopiuj logo jako SVG", "nav.context.copyWordmark": "Skopiuj logotyp jako SVG", @@ -41,9 +42,13 @@ export const dict = { "notFound.docs": "Dokumentacja", "notFound.github": "GitHub", "notFound.discord": "Discord", + "notFound.logoLightAlt": "jasne logo opencode", + "notFound.logoDarkAlt": "ciemne logo opencode", "user.logout": "Wyloguj się", + "auth.callback.error.codeMissing": "Nie znaleziono kodu autoryzacji.", + "workspace.select": "Wybierz obszar roboczy", "workspace.createNew": "+ Utwórz nowy obszar roboczy", "workspace.modal.title": "Utwórz nowy obszar roboczy", @@ -75,6 +80,8 @@ export const dict = { "error.reloadAmountMin": "Kwota doładowania musi wynosić co najmniej ${{amount}}", "error.reloadTriggerMin": "Próg salda musi wynosić co najmniej ${{amount}}", + "app.meta.description": "OpenCode - Otwartoźródłowy agent programistyczny.", + "home.title": "OpenCode | Open source'owy agent AI do kodowania", "temp.title": "opencode | Agent AI do kodowania zbudowany dla terminala", @@ -90,6 +97,8 @@ export const dict = { "temp.feature.models.afterLink": ", w tym modele lokalne", "temp.screenshot.caption": "OpenCode TUI z motywem tokyonight", "temp.screenshot.alt": "OpenCode TUI z motywem tokyonight", + "temp.logoLightAlt": "jasne logo opencode", + "temp.logoDarkAlt": "ciemne logo opencode", "home.banner.badge": "Nowość", "home.banner.text": "Aplikacja desktopowa dostępna w wersji beta", @@ -241,11 +250,130 @@ export const dict = { "Wszystkie modele Zen są hostowane w USA. Dostawcy stosują politykę zerowej retencji i nie wykorzystują Twoich danych do trenowania modeli, z", "zen.privacy.exceptionsLink": "następującymi wyjątkami", + "go.title": "OpenCode Go | Niskokosztowe modele do kodowania dla każdego", + "go.meta.description": + "Go to subskrypcja za $10/miesiąc z hojnymi 5-godzinnymi limitami zapytań dla GLM-5, Kimi K2.5 i MiniMax M2.5.", + "go.hero.title": "Niskokosztowe modele do kodowania dla każdego", + "go.hero.body": + "Go udostępnia programowanie z agentami programistom na całym świecie. Oferuje hojne limity i niezawodny dostęp do najzdolniejszych modeli open source, dzięki czemu możesz budować za pomocą potężnych agentów, nie martwiąc się o koszty czy dostępność.", + + "go.cta.start": "Zasubskrybuj Go", + "go.cta.template": "{{text}} {{price}}", + "go.cta.text": "Zasubskrybuj Go", + "go.cta.price": "$10/miesiąc", + "go.pricing.body": "Używaj z dowolnym agentem. Doładuj środki w razie potrzeby. Anuluj w dowolnym momencie.", + "go.graph.free": "Darmowe", + "go.graph.freePill": "Big Pickle i darmowe modele", + "go.graph.go": "Go", + "go.graph.label": "Żądania na 5 godzin", + "go.graph.usageLimits": "Limity użycia", + "go.graph.tick": "{{n}}x", + "go.graph.aria": "Żądania na 5h: {{free}} vs {{go}}", + + "go.testimonials.brand.zen": "Zen", + "go.testimonials.brand.go": "Go", + "go.testimonials.handle": "@OpenCode", + "go.testimonials.dax.name": "Dax Raad", + "go.testimonials.dax.title": "ex-CEO, Terminal Products", + "go.testimonials.dax.quoteAfter": "zmieniło moje życie, to naprawdę oczywisty wybór.", + "go.testimonials.jay.name": "Jay V", + "go.testimonials.jay.title": "ex-Founder, SEED, PM, Melt, Pop, Dapt, Cadmus, and ViewPoint", + "go.testimonials.jay.quoteBefore": "4 na 5 osób w naszym zespole uwielbia używać", + "go.testimonials.jay.quoteAfter": ".", + "go.testimonials.adam.name": "Adam Elmore", + "go.testimonials.adam.title": "ex-Hero, AWS", + "go.testimonials.adam.quoteBefore": "Nie mogę wystarczająco polecić", + "go.testimonials.adam.quoteAfter": ". Poważnie, to jest naprawdę dobre.", + "go.testimonials.david.name": "David Hill", + "go.testimonials.david.title": "ex-Head of Design, Laravel", + "go.testimonials.david.quoteBefore": "Dzięki", + "go.testimonials.david.quoteAfter": "wiem, że wszystkie modele są przetestowane i idealne dla agentów kodujących.", + "go.testimonials.frank.name": "Frank Wang", + "go.testimonials.frank.title": "ex-Intern, Nvidia (4 times)", + "go.testimonials.frank.quote": "Chciałbym wciąż być w Nvidia.", + "go.problem.title": "Jaki problem rozwiązuje Go?", + "go.problem.body": + "Skupiamy się na dostarczeniu doświadczenia OpenCode jak największej liczbie osób. OpenCode Go to niskokosztowa ($10/miesiąc) subskrypcja zaprojektowana, aby udostępnić programowanie z agentami programistom na całym świecie. Zapewnia hojne limity i niezawodny dostęp do najzdolniejszych modeli open source.", + "go.problem.subtitle": " ", + "go.problem.item1": "Niskokosztowa cena subskrypcji", + "go.problem.item2": "Hojne limity i niezawodny dostęp", + "go.problem.item3": "Stworzony dla jak największej liczby programistów", + "go.problem.item4": "Zawiera GLM-5, Kimi K2.5 i MiniMax M2.5", + "go.how.title": "Jak działa Go", + "go.how.body": "Go to subskrypcja za $10/miesiąc, której możesz używać z OpenCode lub dowolnym agentem.", + "go.how.step1.title": "Załóż konto", + "go.how.step1.beforeLink": "postępuj zgodnie z", + "go.how.step1.link": "instrukcją konfiguracji", + "go.how.step2.title": "Zasubskrybuj Go", + "go.how.step2.link": "$10/miesiąc", + "go.how.step2.afterLink": "z hojnymi limitami", + "go.how.step3.title": "Zacznij kodować", + "go.how.step3.body": "z niezawodnym dostępem do modeli open source", + "go.privacy.title": "Twoja prywatność jest dla nas ważna", + "go.privacy.body": + "Plan został zaprojektowany głównie dla użytkowników międzynarodowych, z modelami hostowanymi w USA, UE i Singapurze, aby zapewnić stabilny globalny dostęp.", + "go.privacy.contactAfter": "jeśli masz jakiekolwiek pytania.", + "go.privacy.beforeExceptions": + "Modele Go są hostowane w USA. Dostawcy stosują politykę zerowej retencji i nie używają Twoich danych do trenowania modeli, z", + "go.privacy.exceptionsLink": "następującymi wyjątkami", + "go.faq.q1": "Czym jest OpenCode Go?", + "go.faq.a1": + "Go to niskokosztowa subskrypcja, która daje niezawodny dostęp do zdolnych modeli open source dla agentów kodujących.", + "go.faq.q2": "Jakie modele zawiera Go?", + "go.faq.a2": "Go zawiera GLM-5, Kimi K2.5 i MiniMax M2.5, z hojnymi limitami i niezawodnym dostępem.", + "go.faq.q3": "Czy Go to to samo co Zen?", + "go.faq.a3": + "Nie. Zen działa w modelu pay-as-you-go (płacisz za użycie), podczas gdy Go to subskrypcja za $10/miesiąc z hojnymi limitami i niezawodnym dostępem do modeli open source GLM-5, Kimi K2.5 i MiniMax M2.5.", + "go.faq.q4": "Ile kosztuje Go?", + "go.faq.a4.p1.beforePricing": "Go kosztuje", + "go.faq.a4.p1.pricingLink": "$10/miesiąc", + "go.faq.a4.p1.afterPricing": "z hojnymi limitami.", + "go.faq.a4.p2.beforeAccount": "Możesz zarządzać subskrypcją na swoim", + "go.faq.a4.p2.accountLink": "koncie", + "go.faq.a4.p3": "Anuluj w dowolnym momencie.", + "go.faq.q5": "A co z danymi i prywatnością?", + "go.faq.a5.body": + "Plan został zaprojektowany głównie dla użytkowników międzynarodowych, z modelami hostowanymi w USA, UE i Singapurze, aby zapewnić stabilny globalny dostęp.", + "go.faq.a5.contactAfter": "jeśli masz jakiekolwiek pytania.", + "go.faq.a5.beforeExceptions": + "Modele Go są hostowane w USA. Dostawcy stosują politykę zerowej retencji i nie używają Twoich danych do trenowania modeli, z", + "go.faq.a5.exceptionsLink": "następującymi wyjątkami", + "go.faq.q6": "Czy mogę doładować środki?", + "go.faq.a6": "Jeśli potrzebujesz większego użycia, możesz doładować środki na swoim koncie.", + "go.faq.q7": "Czy mogę anulować?", + "go.faq.a7": "Tak, możesz anulować w dowolnym momencie.", + "go.faq.q8": "Czy mogę używać Go z innymi agentami kodującymi?", + "go.faq.a8": + "Tak, możesz używać Go z dowolnym agentem. Postępuj zgodnie z instrukcjami konfiguracji w swoim preferowanym agencie.", + + "go.faq.q9": "Jaka jest różnica między darmowymi modelami a Go?", + "go.faq.a9": + "Darmowe modele obejmują Big Pickle oraz modele promocyjne dostępne w danym momencie, z limitem 200 zapytań/dzień. Go zawiera GLM-5, Kimi K2.5 i MiniMax M2.5 z wyższymi limitami zapytań egzekwowanymi w oknach kroczących (5-godzinnych, tygodniowych i miesięcznych), w przybliżeniu równoważnymi $12 na 5 godzin, $30 tygodniowo i $60 miesięcznie (rzeczywista liczba zapytań zależy od modelu i użycia).", + + "zen.api.error.rateLimitExceeded": "Przekroczono limit zapytań. Spróbuj ponownie później.", + "zen.api.error.modelNotSupported": "Model {{model}} nie jest obsługiwany", + "zen.api.error.modelFormatNotSupported": "Model {{model}} nie jest obsługiwany dla formatu {{format}}", + "zen.api.error.noProviderAvailable": "Brak dostępnego dostawcy", + "zen.api.error.providerNotSupported": "Dostawca {{provider}} nie jest obsługiwany", + "zen.api.error.missingApiKey": "Brak klucza API.", + "zen.api.error.invalidApiKey": "Nieprawidłowy klucz API.", + "zen.api.error.subscriptionQuotaExceeded": "Przekroczono limit subskrypcji. Spróbuj ponownie za {{retryIn}}.", + "zen.api.error.subscriptionQuotaExceededUseFreeModels": + "Przekroczono limit subskrypcji. Możesz kontynuować korzystanie z darmowych modeli.", + "zen.api.error.noPaymentMethod": "Brak metody płatności. Dodaj metodę płatności tutaj: {{billingUrl}}", + "zen.api.error.insufficientBalance": "Niewystarczające saldo. Zarządzaj swoimi płatnościami tutaj: {{billingUrl}}", + "zen.api.error.workspaceMonthlyLimitReached": + "Twoja przestrzeń robocza osiągnęła miesięczny limit wydatków w wysokości ${{amount}}. Zarządzaj swoimi limitami tutaj: {{billingUrl}}", + "zen.api.error.userMonthlyLimitReached": + "Osiągnąłeś swój miesięczny limit wydatków w wysokości ${{amount}}. Zarządzaj swoimi limitami tutaj: {{membersUrl}}", + "zen.api.error.modelDisabled": "Model jest wyłączony", + "black.meta.title": "OpenCode Black | Dostęp do najlepszych na świecie modeli kodujących", "black.meta.description": "Uzyskaj dostęp do Claude, GPT, Gemini i innych dzięki planom subskrypcji OpenCode Black.", "black.hero.title": "Dostęp do najlepszych na świecie modeli kodujących", "black.hero.subtitle": "W tym Claude, GPT, Gemini i inne", "black.title": "OpenCode Black | Cennik", + "black.paused": "Rejestracja planu Black jest tymczasowo wstrzymana.", "black.plan.icon20": "Plan Black 20", "black.plan.icon100": "Plan Black 100", "black.plan.icon200": "Plan Black 200", @@ -341,12 +469,15 @@ export const dict = { "workspace.usage.table.input": "Wejście", "workspace.usage.table.output": "Wyjście", "workspace.usage.table.cost": "Koszt", + "workspace.usage.table.session": "Sesja", "workspace.usage.breakdown.input": "Wejście", "workspace.usage.breakdown.cacheRead": "Odczyt Cache", "workspace.usage.breakdown.cacheWrite": "Zapis Cache", "workspace.usage.breakdown.output": "Wyjście", "workspace.usage.breakdown.reasoning": "Rozumowanie", - "workspace.usage.subscription": "subskrypcja (${{amount}})", + "workspace.usage.subscription": "Black (${{amount}})", + "workspace.usage.lite": "Go (${{amount}})", + "workspace.usage.byok": "BYOK (${{amount}})", "workspace.cost.title": "Koszt", "workspace.cost.subtitle": "Koszty użycia w podziale na modele.", @@ -445,6 +576,7 @@ export const dict = { "workspace.reload.updatePaymentMethod": "Zaktualizuj metodę płatności i spróbuj ponownie.", "workspace.reload.retrying": "Ponawianie...", "workspace.reload.retry": "Spróbuj ponownie", + "workspace.reload.error.paymentFailed": "Płatność nie powiodła się.", "workspace.payments.title": "Historia płatności", "workspace.payments.subtitle": "Ostatnie transakcje płatnicze.", @@ -483,6 +615,36 @@ export const dict = { "workspace.black.waitlist.enrollNote": "Po kliknięciu Zapisz się, Twoja subskrypcja rozpocznie się natychmiast, a karta zostanie obciążona.", + "workspace.lite.loading": "Ładowanie...", + "workspace.lite.time.day": "dzień", + "workspace.lite.time.days": "dni", + "workspace.lite.time.hour": "godzina", + "workspace.lite.time.hours": "godzin(y)", + "workspace.lite.time.minute": "minuta", + "workspace.lite.time.minutes": "minut(y)", + "workspace.lite.time.fewSeconds": "kilka sekund", + "workspace.lite.subscription.title": "Subskrypcja Go", + "workspace.lite.subscription.message": "Subskrybujesz OpenCode Go.", + "workspace.lite.subscription.manage": "Zarządzaj subskrypcją", + "workspace.lite.subscription.rollingUsage": "Użycie kroczące", + "workspace.lite.subscription.weeklyUsage": "Użycie tygodniowe", + "workspace.lite.subscription.monthlyUsage": "Użycie miesięczne", + "workspace.lite.subscription.resetsIn": "Resetuje się za", + "workspace.lite.subscription.useBalance": "Użyj dostępnego salda po osiągnięciu limitów użycia", + "workspace.lite.subscription.selectProvider": + 'Wybierz "OpenCode Go" jako dostawcę w konfiguracji opencode, aby używać modeli Go.', + "workspace.lite.other.title": "Subskrypcja Go", + "workspace.lite.other.message": + "Inny członek tego obszaru roboczego już subskrybuje OpenCode Go. Tylko jeden członek na obszar roboczy może subskrybować.", + "workspace.lite.promo.title": "OpenCode Go", + "workspace.lite.promo.description": + "OpenCode Go to subskrypcja za $10 miesięcznie, która zapewnia niezawodny dostęp do popularnych otwartych modeli do kodowania z hojnymi limitami użycia.", + "workspace.lite.promo.modelsTitle": "Co zawiera", + "workspace.lite.promo.footer": + "Plan został zaprojektowany głównie dla użytkowników międzynarodowych, z modelami hostowanymi w USA, UE i Singapurze, aby zapewnić stabilny globalny dostęp. Ceny i limity użycia mogą ulec zmianie w miarę analizy wczesnego użycia i zbierania opinii.", + "workspace.lite.promo.subscribe": "Subskrybuj Go", + "workspace.lite.promo.subscribing": "Przekierowywanie...", + "download.title": "OpenCode | Pobierz", "download.meta.description": "Pobierz OpenCode na macOS, Windows i Linux", "download.hero.title": "Pobierz OpenCode", @@ -535,6 +697,10 @@ export const dict = { "enterprise.form.send": "Wyślij", "enterprise.form.sending": "Wysyłanie...", "enterprise.form.success": "Wiadomość wysłana, skontaktujemy się wkrótce.", + "enterprise.form.success.submitted": "Formularz został pomyślnie wysłany.", + "enterprise.form.error.allFieldsRequired": "Wszystkie pola są wymagane.", + "enterprise.form.error.invalidEmailFormat": "Nieprawidłowy format adresu e-mail.", + "enterprise.form.error.internalServer": "Wewnętrzny błąd serwera.", "enterprise.faq.title": "FAQ", "enterprise.faq.q1": "Czym jest OpenCode Enterprise?", "enterprise.faq.a1": @@ -567,6 +733,7 @@ export const dict = { "bench.list.table.agent": "Agent", "bench.list.table.model": "Model", "bench.list.table.score": "Wynik", + "bench.submission.error.allFieldsRequired": "Wszystkie pola są wymagane.", "bench.detail.title": "Benchmark - {{task}}", "bench.detail.notFound": "Nie znaleziono zadania", diff --git a/packages/console/app/src/i18n/ru.ts b/packages/console/app/src/i18n/ru.ts index 27a30cc815..801c8fc7d4 100644 --- a/packages/console/app/src/i18n/ru.ts +++ b/packages/console/app/src/i18n/ru.ts @@ -15,6 +15,7 @@ export const dict = { "nav.home": "Главная", "nav.openMenu": "Открыть меню", "nav.getStartedFree": "Начать бесплатно", + "nav.logoAlt": "OpenCode", "nav.context.copyLogo": "Скопировать логотип как SVG", "nav.context.copyWordmark": "Скопировать название как SVG", @@ -42,9 +43,13 @@ export const dict = { "notFound.docs": "Документация", "notFound.github": "GitHub", "notFound.discord": "Discord", + "notFound.logoLightAlt": "светлый логотип opencode", + "notFound.logoDarkAlt": "темный логотип opencode", "user.logout": "Выйти", + "auth.callback.error.codeMissing": "Код авторизации не найден.", + "workspace.select": "Выбрать рабочее пространство", "workspace.createNew": "+ Создать рабочее пространство", "workspace.modal.title": "Создать рабочее пространство", @@ -76,6 +81,8 @@ export const dict = { "error.reloadAmountMin": "Сумма пополнения должна быть не менее ${{amount}}", "error.reloadTriggerMin": "Порог баланса должен быть не менее ${{amount}}", + "app.meta.description": "OpenCode - AI-агент с открытым кодом для программирования.", + "home.title": "OpenCode | AI-агент с открытым кодом для программирования", "temp.title": "opencode | AI-агент для программирования в терминале", @@ -91,6 +98,8 @@ export const dict = { "temp.feature.models.afterLink": ", включая локальные модели", "temp.screenshot.caption": "OpenCode TUI с темой tokyonight", "temp.screenshot.alt": "OpenCode TUI с темой tokyonight", + "temp.logoLightAlt": "светлый логотип opencode", + "temp.logoDarkAlt": "темный логотип opencode", "home.banner.badge": "Новое", "home.banner.text": "Доступно десктопное приложение (бета)", @@ -244,11 +253,131 @@ export const dict = { "Все модели Zen размещены в США. Провайдеры следуют политике нулевого хранения и не используют ваши данные для обучения моделей, за", "zen.privacy.exceptionsLink": "следующими исключениями", + "go.title": "OpenCode Go | Недорогие модели для кодинга для всех", + "go.meta.description": + "Go — это подписка за $10/месяц с щедрыми 5-часовыми лимитами запросов для GLM-5, Kimi K2.5 и MiniMax M2.5.", + "go.hero.title": "Недорогие модели для кодинга для всех", + "go.hero.body": + "Go открывает доступ к агентам-программистам разработчикам по всему миру. Предлагая щедрые лимиты и надежный доступ к наиболее способным моделям с открытым исходным кодом, вы можете создавать проекты с мощными агентами, не беспокоясь о затратах или доступности.", + + "go.cta.start": "Подписаться на Go", + "go.cta.template": "{{text}} {{price}}", + "go.cta.text": "Подписаться на Go", + "go.cta.price": "$10/месяц", + "go.pricing.body": "Используйте с любым агентом. Пополняйте баланс при необходимости. Отменяйте в любое время.", + "go.graph.free": "Бесплатно", + "go.graph.freePill": "Big Pickle и бесплатные модели", + "go.graph.go": "Go", + "go.graph.label": "Запросов за 5 часов", + "go.graph.usageLimits": "Лимиты использования", + "go.graph.tick": "{{n}}x", + "go.graph.aria": "Запросов за 5ч: {{free}} против {{go}}", + + "go.testimonials.brand.zen": "Zen", + "go.testimonials.brand.go": "Go", + "go.testimonials.handle": "@OpenCode", + "go.testimonials.dax.name": "Dax Raad", + "go.testimonials.dax.title": "ex-CEO, Terminal Products", + "go.testimonials.dax.quoteAfter": "изменил мою жизнь, это действительно очевидный выбор.", + "go.testimonials.jay.name": "Jay V", + "go.testimonials.jay.title": "ex-Founder, SEED, PM, Melt, Pop, Dapt, Cadmus, и ViewPoint", + "go.testimonials.jay.quoteBefore": "4 из 5 человек в нашей команде любят использовать", + "go.testimonials.jay.quoteAfter": ".", + "go.testimonials.adam.name": "Adam Elmore", + "go.testimonials.adam.title": "ex-Hero, AWS", + "go.testimonials.adam.quoteBefore": "Я не могу не порекомендовать", + "go.testimonials.adam.quoteAfter": "достаточно сильно. Серьезно, это очень круто.", + "go.testimonials.david.name": "David Hill", + "go.testimonials.david.title": "ex-Head of Design, Laravel", + "go.testimonials.david.quoteBefore": "С", + "go.testimonials.david.quoteAfter": + "я знаю, что все модели протестированы и идеально подходят для агентов-программистов.", + "go.testimonials.frank.name": "Frank Wang", + "go.testimonials.frank.title": "ex-Intern, Nvidia (4 раза)", + "go.testimonials.frank.quote": "Жаль, что я больше не в Nvidia.", + "go.problem.title": "Какую проблему решает Go?", + "go.problem.body": + "Мы сосредоточены на том, чтобы сделать OpenCode доступным как можно большему числу людей. OpenCode Go — это недорогая ($10/месяц) подписка, разработанная, чтобы сделать агентов-программистов доступными для разработчиков по всему миру. Она предоставляет щедрые лимиты и надежный доступ к самым способным моделям с открытым исходным кодом.", + "go.problem.subtitle": " ", + "go.problem.item1": "Недорогая подписка", + "go.problem.item2": "Щедрые лимиты и надежный доступ", + "go.problem.item3": "Создан для максимального числа программистов", + "go.problem.item4": "Включает GLM-5, Kimi K2.5 и MiniMax M2.5", + "go.how.title": "Как работает Go", + "go.how.body": "Go — это подписка за $10/месяц, которую можно использовать с OpenCode или любым агентом.", + "go.how.step1.title": "Создайте аккаунт", + "go.how.step1.beforeLink": "следуйте", + "go.how.step1.link": "инструкциям по настройке", + "go.how.step2.title": "Подпишитесь на Go", + "go.how.step2.link": "$10/месяц", + "go.how.step2.afterLink": "с щедрыми лимитами", + "go.how.step3.title": "Начните кодить", + "go.how.step3.body": "с надежным доступом к open-source моделям", + "go.privacy.title": "Ваша приватность важна для нас", + "go.privacy.body": + "План разработан в первую очередь для международных пользователей, с моделями, размещенными в США, ЕС и Сингапуре для стабильного глобального доступа.", + "go.privacy.contactAfter": "если у вас есть вопросы.", + "go.privacy.beforeExceptions": + "Модели Go размещены в США. Провайдеры следуют политике нулевого хранения и не используют ваши данные для обучения моделей, за", + "go.privacy.exceptionsLink": "следующими исключениями", + "go.faq.q1": "Что такое OpenCode Go?", + "go.faq.a1": + "Go — это недорогая подписка, дающая надежный доступ к мощным моделям с открытым исходным кодом для агентов-программистов.", + "go.faq.q2": "Какие модели включает Go?", + "go.faq.a2": "Go включает GLM-5, Kimi K2.5 и MiniMax M2.5, с щедрыми лимитами и надежным доступом.", + "go.faq.q3": "Go — это то же самое, что и Zen?", + "go.faq.a3": + "Нет. Zen работает по системе оплаты за использование (pay-as-you-go), тогда как Go — это подписка за $10/месяц с щедрыми лимитами и надежным доступом к open-source моделям GLM-5, Kimi K2.5 и MiniMax M2.5.", + "go.faq.q4": "Сколько стоит Go?", + "go.faq.a4.p1.beforePricing": "Go стоит", + "go.faq.a4.p1.pricingLink": "$10/месяц", + "go.faq.a4.p1.afterPricing": "с щедрыми лимитами.", + "go.faq.a4.p2.beforeAccount": "Вы можете управлять подпиской в своем", + "go.faq.a4.p2.accountLink": "аккаунте", + "go.faq.a4.p3": "Отмена в любое время.", + "go.faq.q5": "Как насчет данных и приватности?", + "go.faq.a5.body": + "План разработан в первую очередь для международных пользователей, с моделями, размещенными в США, ЕС и Сингапуре для стабильного глобального доступа.", + "go.faq.a5.contactAfter": "если у вас есть вопросы.", + "go.faq.a5.beforeExceptions": + "Модели Go размещены в США. Провайдеры следуют политике нулевого хранения и не используют ваши данные для обучения моделей, за", + "go.faq.a5.exceptionsLink": "следующими исключениями", + "go.faq.q6": "Могу ли я пополнить баланс?", + "go.faq.a6": "Если вам нужно больше использования, вы можете пополнить баланс в своем аккаунте.", + "go.faq.q7": "Могу ли я отменить подписку?", + "go.faq.a7": "Да, вы можете отменить подписку в любое время.", + "go.faq.q8": "Могу ли я использовать Go с другими кодинг-агентами?", + "go.faq.a8": + "Да, вы можете использовать Go с любым агентом. Следуйте инструкциям по настройке в вашем предпочитаемом агенте.", + + "go.faq.q9": "В чем разница между бесплатными моделями и Go?", + "go.faq.a9": + "Бесплатные модели включают Big Pickle плюс промо-модели, доступные на данный момент, с квотой 200 запросов/день. Go включает GLM-5, Kimi K2.5 и MiniMax M2.5 с более высокими квотами запросов, применяемыми в скользящих окнах (5 часов, неделя и месяц), что примерно эквивалентно $12 за 5 часов, $30 в неделю и $60 в месяц (фактическое количество запросов зависит от модели и использования).", + + "zen.api.error.rateLimitExceeded": "Превышен лимит запросов. Пожалуйста, попробуйте позже.", + "zen.api.error.modelNotSupported": "Модель {{model}} не поддерживается", + "zen.api.error.modelFormatNotSupported": "Модель {{model}} не поддерживается для формата {{format}}", + "zen.api.error.noProviderAvailable": "Нет доступных провайдеров", + "zen.api.error.providerNotSupported": "Провайдер {{provider}} не поддерживается", + "zen.api.error.missingApiKey": "Отсутствует API ключ.", + "zen.api.error.invalidApiKey": "Неверный API ключ.", + "zen.api.error.subscriptionQuotaExceeded": "Квота подписки превышена. Повторите попытку через {{retryIn}}.", + "zen.api.error.subscriptionQuotaExceededUseFreeModels": + "Квота подписки превышена. Вы можете продолжить использовать бесплатные модели.", + "zen.api.error.noPaymentMethod": "Нет способа оплаты. Добавьте способ оплаты здесь: {{billingUrl}}", + "zen.api.error.insufficientBalance": "Недостаточно средств. Управляйте оплатой здесь: {{billingUrl}}", + "zen.api.error.workspaceMonthlyLimitReached": + "Ваше рабочее пространство достигло ежемесячного лимита расходов в ${{amount}}. Управляйте лимитами здесь: {{billingUrl}}", + "zen.api.error.userMonthlyLimitReached": + "Вы достигли ежемесячного лимита расходов в ${{amount}}. Управляйте лимитами здесь: {{membersUrl}}", + "zen.api.error.modelDisabled": "Модель отключена", + "black.meta.title": "OpenCode Black | Доступ к лучшим моделям для кодинга в мире", "black.meta.description": "Получите доступ к Claude, GPT, Gemini и другим моделям с подпиской OpenCode Black.", "black.hero.title": "Доступ к лучшим моделям для кодинга в мире", "black.hero.subtitle": "Включая Claude, GPT, Gemini и другие", "black.title": "OpenCode Black | Цены", + "black.paused": "Регистрация на план Black временно приостановлена.", "black.plan.icon20": "План Black 20", "black.plan.icon100": "План Black 100", "black.plan.icon200": "План Black 200", @@ -346,12 +475,15 @@ export const dict = { "workspace.usage.table.input": "Вход", "workspace.usage.table.output": "Выход", "workspace.usage.table.cost": "Стоимость", + "workspace.usage.table.session": "Сессия", "workspace.usage.breakdown.input": "Вход", "workspace.usage.breakdown.cacheRead": "Чтение кэша", "workspace.usage.breakdown.cacheWrite": "Запись кэша", "workspace.usage.breakdown.output": "Выход", "workspace.usage.breakdown.reasoning": "Reasoning (рассуждения)", - "workspace.usage.subscription": "подписка (${{amount}})", + "workspace.usage.subscription": "Black (${{amount}})", + "workspace.usage.lite": "Go (${{amount}})", + "workspace.usage.byok": "BYOK (${{amount}})", "workspace.cost.title": "Расходы", "workspace.cost.subtitle": "Расходы на использование с разбивкой по моделям.", @@ -450,6 +582,7 @@ export const dict = { "workspace.reload.updatePaymentMethod": "Пожалуйста, обновите способ оплаты и попробуйте снова.", "workspace.reload.retrying": "Повторная попытка...", "workspace.reload.retry": "Повторить", + "workspace.reload.error.paymentFailed": "Ошибка оплаты.", "workspace.payments.title": "История платежей", "workspace.payments.subtitle": "Недавние транзакции.", @@ -488,6 +621,36 @@ export const dict = { "workspace.black.waitlist.enrollNote": "Когда вы нажмете Подключиться, ваша подписка начнется немедленно, и с карты будет списана оплата.", + "workspace.lite.loading": "Загрузка...", + "workspace.lite.time.day": "день", + "workspace.lite.time.days": "дней", + "workspace.lite.time.hour": "час", + "workspace.lite.time.hours": "часов", + "workspace.lite.time.minute": "минута", + "workspace.lite.time.minutes": "минут", + "workspace.lite.time.fewSeconds": "несколько секунд", + "workspace.lite.subscription.title": "Подписка Go", + "workspace.lite.subscription.message": "Вы подписаны на OpenCode Go.", + "workspace.lite.subscription.manage": "Управление подпиской", + "workspace.lite.subscription.rollingUsage": "Скользящее использование", + "workspace.lite.subscription.weeklyUsage": "Недельное использование", + "workspace.lite.subscription.monthlyUsage": "Ежемесячное использование", + "workspace.lite.subscription.resetsIn": "Сброс через", + "workspace.lite.subscription.useBalance": "Использовать доступный баланс после достижения лимитов", + "workspace.lite.subscription.selectProvider": + 'Выберите "OpenCode Go" в качестве провайдера в настройках opencode для использования моделей Go.', + "workspace.lite.other.title": "Подписка Go", + "workspace.lite.other.message": + "Другой участник в этом рабочем пространстве уже подписан на OpenCode Go. Только один участник в рабочем пространстве может оформить подписку.", + "workspace.lite.promo.title": "OpenCode Go", + "workspace.lite.promo.description": + "OpenCode Go — это подписка за $10 в месяц, которая предоставляет надежный доступ к популярным открытым моделям для кодинга с щедрыми лимитами использования.", + "workspace.lite.promo.modelsTitle": "Что включено", + "workspace.lite.promo.footer": + "План предназначен в первую очередь для международных пользователей. Модели размещены в США, ЕС и Сингапуре для стабильного глобального доступа. Цены и лимиты использования могут меняться по мере того, как мы изучаем раннее использование и собираем отзывы.", + "workspace.lite.promo.subscribe": "Подписаться на Go", + "workspace.lite.promo.subscribing": "Перенаправление...", + "download.title": "OpenCode | Скачать", "download.meta.description": "Скачать OpenCode для macOS, Windows и Linux", "download.hero.title": "Скачать OpenCode", @@ -539,6 +702,10 @@ export const dict = { "enterprise.form.send": "Отправить", "enterprise.form.sending": "Отправка...", "enterprise.form.success": "Сообщение отправлено, мы скоро свяжемся с вами.", + "enterprise.form.success.submitted": "Форма успешно отправлена.", + "enterprise.form.error.allFieldsRequired": "Все поля обязательны.", + "enterprise.form.error.invalidEmailFormat": "Неверный формат email.", + "enterprise.form.error.internalServer": "Внутренняя ошибка сервера.", "enterprise.faq.title": "FAQ", "enterprise.faq.q1": "Что такое OpenCode Enterprise?", "enterprise.faq.a1": @@ -571,6 +738,7 @@ export const dict = { "bench.list.table.agent": "Агент", "bench.list.table.model": "Модель", "bench.list.table.score": "Оценка", + "bench.submission.error.allFieldsRequired": "Все поля обязательны.", "bench.detail.title": "Бенчмарк - {{task}}", "bench.detail.notFound": "Задача не найдена", diff --git a/packages/console/app/src/i18n/th.ts b/packages/console/app/src/i18n/th.ts index d94be479c9..d9d7d03d1f 100644 --- a/packages/console/app/src/i18n/th.ts +++ b/packages/console/app/src/i18n/th.ts @@ -15,6 +15,7 @@ export const dict = { "nav.home": "หน้าหลัก", "nav.openMenu": "เปิดเมนู", "nav.getStartedFree": "เริ่มต้นฟรี", + "nav.logoAlt": "OpenCode", "nav.context.copyLogo": "คัดลอกโลโก้เป็น SVG", "nav.context.copyWordmark": "คัดลอกตัวอักษรแบรนด์เป็น SVG", @@ -42,9 +43,13 @@ export const dict = { "notFound.docs": "เอกสาร", "notFound.github": "GitHub", "notFound.discord": "Discord", + "notFound.logoLightAlt": "โลโก้ opencode แบบสว่าง", + "notFound.logoDarkAlt": "โลโก้ opencode แบบมืด", "user.logout": "ออกจากระบบ", + "auth.callback.error.codeMissing": "ไม่พบ authorization code", + "workspace.select": "เลือก Workspace", "workspace.createNew": "+ สร้าง Workspace ใหม่", "workspace.modal.title": "สร้าง Workspace ใหม่", @@ -76,6 +81,8 @@ export const dict = { "error.reloadAmountMin": "จำนวนเงินที่โหลดซ้ำต้องมีอย่างน้อย ${{amount}}", "error.reloadTriggerMin": "ยอดคงเหลือที่กระตุ้นต้องมีอย่างน้อย ${{amount}}", + "app.meta.description": "OpenCode - เอเจนต์เขียนโค้ดแบบโอเพนซอร์ส", + "home.title": "OpenCode | เอเจนต์เขียนโค้ดด้วย AI แบบโอเพนซอร์ส", "temp.title": "OpenCode | เอเจนต์เขียนโค้ด AI ที่สร้างมาเพื่อเทอร์มินัล", @@ -91,6 +98,8 @@ export const dict = { "temp.feature.models.afterLink": "รวมถึงโมเดล Local", "temp.screenshot.caption": "OpenCode TUI พร้อมธีม tokyonight", "temp.screenshot.alt": "OpenCode TUI พร้อมธีม tokyonight", + "temp.logoLightAlt": "โลโก้ opencode แบบสว่าง", + "temp.logoDarkAlt": "โลโก้ opencode แบบมืด", "home.banner.badge": "ใหม่", "home.banner.text": "แอปเดสก์ท็อปพร้อมใช้งานในเวอร์ชันเบต้า", @@ -239,11 +248,129 @@ export const dict = { "โมเดล Zen ทั้งหมดโฮสต์ในสหรัฐอเมริกา ผู้ให้บริการปฏิบัติตามนโยบายไม่เก็บรักษาข้อมูล (zero-retention policy) และไม่ใช้ข้อมูลของคุณสำหรับการฝึกโมเดล โดยมี", "zen.privacy.exceptionsLink": "ข้อยกเว้นดังนี้", + "go.title": "OpenCode Go | โมเดลเขียนโค้ดราคาประหยัดสำหรับทุกคน", + "go.meta.description": + "Go คือการสมัครสมาชิกราคา $10/เดือน พร้อมขีดจำกัดการร้องขอที่กว้างขวางถึง 5 ชั่วโมงสำหรับ GLM-5, Kimi K2.5 และ MiniMax M2.5", + "go.hero.title": "โมเดลเขียนโค้ดราคาประหยัดสำหรับทุกคน", + "go.hero.body": + "Go นำการเขียนโค้ดแบบเอเจนต์มาสู่นักเขียนโปรแกรมทั่วโลก เสนอขีดจำกัดที่กว้างขวางและการเข้าถึงโมเดลโอเพนซอร์สที่มีความสามารถสูงสุดได้อย่างน่าเชื่อถือ เพื่อให้คุณสามารถสร้างสรรค์ด้วยเอเจนต์ที่ทรงพลังโดยไม่ต้องกังวลเรื่องค่าใช้จ่ายหรือความพร้อมใช้งาน", + + "go.cta.start": "สมัครสมาชิก Go", + "go.cta.template": "{{text}} {{price}}", + "go.cta.text": "สมัครสมาชิก Go", + "go.cta.price": "$10/เดือน", + "go.pricing.body": "ใช้กับเอเจนต์ใดก็ได้ เติมเงินเครดิตหากต้องการ ยกเลิกได้ตลอดเวลา", + "go.graph.free": "ฟรี", + "go.graph.freePill": "Big Pickle และโมเดลฟรี", + "go.graph.go": "Go", + "go.graph.label": "คำขอต่อ 5 ชั่วโมง", + "go.graph.usageLimits": "ขีดจำกัดการใช้งาน", + "go.graph.tick": "{{n}}x", + "go.graph.aria": "คำขอต่อ 5 ชม.: {{free}} vs {{go}}", + + "go.testimonials.brand.zen": "Zen", + "go.testimonials.brand.go": "Go", + "go.testimonials.handle": "@OpenCode", + "go.testimonials.dax.name": "Dax Raad", + "go.testimonials.dax.title": "อดีต CEO, Terminal Products", + "go.testimonials.dax.quoteAfter": "เปลี่ยนชีวิตไปเลย มันเป็นสิ่งที่ต้องมีจริงๆ", + "go.testimonials.jay.name": "Jay V", + "go.testimonials.jay.title": "อดีตผู้ก่อตั้ง SEED, PM, Melt, Pop, Dapt, Cadmus และ ViewPoint", + "go.testimonials.jay.quoteBefore": "4 ใน 5 คนในทีมของเราชอบใช้", + "go.testimonials.jay.quoteAfter": "", + "go.testimonials.adam.name": "Adam Elmore", + "go.testimonials.adam.title": "อดีต Hero, AWS", + "go.testimonials.adam.quoteBefore": "ผมแนะนำ", + "go.testimonials.adam.quoteAfter": "ได้ไม่พอจริงๆ พูดจริงนะ มันดีมากๆ", + "go.testimonials.david.name": "David Hill", + "go.testimonials.david.title": "อดีตหัวหน้าฝ่ายออกแบบ, Laravel", + "go.testimonials.david.quoteBefore": "ด้วย", + "go.testimonials.david.quoteAfter": "ผมรู้ว่าโมเดลทั้งหมดผ่านการทดสอบและสมบูรณ์แบบสำหรับเอเจนต์เขียนโค้ด", + "go.testimonials.frank.name": "Frank Wang", + "go.testimonials.frank.title": "อดีตเด็กฝึกงาน, Nvidia (4 ครั้ง)", + "go.testimonials.frank.quote": "ผมหวังว่าผมจะยังอยู่ที่ Nvidia", + "go.problem.title": "Go แก้ปัญหาอะไร?", + "go.problem.body": + "เรามุ่งเน้นที่จะนำประสบการณ์ OpenCode ไปสู่ผู้คนให้ได้มากที่สุด OpenCode Go เป็นการสมัครสมาชิกราคาประหยัด ($10/เดือน) ที่ออกแบบมาเพื่อนำการเขียนโค้ดแบบเอเจนต์มาสู่นักเขียนโปรแกรมทั่วโลก โดยมอบขีดจำกัดที่กว้างขวางและการเข้าถึงโมเดลโอเพนซอร์สที่มีความสามารถสูงสุดได้อย่างน่าเชื่อถือ", + "go.problem.subtitle": " ", + "go.problem.item1": "ราคาการสมัครสมาชิกที่ต่ำ", + "go.problem.item2": "ขีดจำกัดที่กว้างขวางและการเข้าถึงที่เชื่อถือได้", + "go.problem.item3": "สร้างขึ้นเพื่อโปรแกรมเมอร์จำนวนมากที่สุดเท่าที่จะเป็นไปได้", + "go.problem.item4": "รวมถึง GLM-5, Kimi K2.5 และ MiniMax M2.5", + "go.how.title": "Go ทำงานอย่างไร", + "go.how.body": "Go คือการสมัครสมาชิกราคา $10/เดือน ที่คุณสามารถใช้กับ OpenCode หรือเอเจนต์ใดก็ได้", + "go.how.step1.title": "สร้างบัญชี", + "go.how.step1.beforeLink": "ทำตาม", + "go.how.step1.link": "คำแนะนำการตั้งค่า", + "go.how.step2.title": "สมัครสมาชิก Go", + "go.how.step2.link": "$10/เดือน", + "go.how.step2.afterLink": "ด้วยขีดจำกัดที่กว้างขวาง", + "go.how.step3.title": "เริ่มเขียนโค้ด", + "go.how.step3.body": "ด้วยการเข้าถึงโมเดลโอเพนซอร์สที่เชื่อถือได้", + "go.privacy.title": "ความเป็นส่วนตัวของคุณสำคัญสำหรับเรา", + "go.privacy.body": + "แผนนี้ออกแบบมาเพื่อผู้ใช้งานระหว่างประเทศเป็นหลัก โดยมีโมเดลโฮสต์ในสหรัฐอเมริกา สหภาพยุโรป และสิงคโปร์ เพื่อการเข้าถึงทั่วโลกที่เสถียร", + "go.privacy.contactAfter": "หากคุณมีคำถามใดๆ", + "go.privacy.beforeExceptions": + "โมเดล Go โฮสต์ในสหรัฐอเมริกา ผู้ให้บริการปฏิบัติตามนโยบายไม่เก็บรักษาข้อมูล (zero-retention policy) และไม่ใช้ข้อมูลของคุณสำหรับการฝึกโมเดล โดยมี", + "go.privacy.exceptionsLink": "ข้อยกเว้นดังนี้", + "go.faq.q1": "OpenCode Go คืออะไร?", + "go.faq.a1": + "Go คือการสมัครสมาชิกราคาประหยัดที่ให้คุณเข้าถึงโมเดลโอเพนซอร์สที่มีความสามารถสำหรับการเขียนโค้ดแบบเอเจนต์ได้อย่างน่าเชื่อถือ", + "go.faq.q2": "Go รวมโมเดลอะไรบ้าง?", + "go.faq.a2": "Go รวมถึง GLM-5, Kimi K2.5 และ MiniMax M2.5 พร้อมขีดจำกัดที่กว้างขวางและการเข้าถึงที่เชื่อถือได้", + "go.faq.q3": "Go เหมือนกับ Zen หรือไม่?", + "go.faq.a3": + "ไม่ Zen เป็นแบบจ่ายตามการใช้งาน (pay-as-you-go) ในขณะที่ Go เป็นการสมัครสมาชิกราคา $10/เดือน พร้อมขีดจำกัดที่กว้างขวางและการเข้าถึงโมเดลโอเพนซอร์ส GLM-5, Kimi K2.5 และ MiniMax M2.5 ได้อย่างน่าเชื่อถือ", + "go.faq.q4": "Go ราคาเท่าไหร่?", + "go.faq.a4.p1.beforePricing": "Go ราคา", + "go.faq.a4.p1.pricingLink": "$10/เดือน", + "go.faq.a4.p1.afterPricing": "พร้อมขีดจำกัดที่กว้างขวาง", + "go.faq.a4.p2.beforeAccount": "คุณสามารถจัดการการสมัครสมาชิกของคุณได้ใน", + "go.faq.a4.p2.accountLink": "บัญชีของคุณ", + "go.faq.a4.p3": "ยกเลิกได้ตลอดเวลา", + "go.faq.q5": "แล้วเรื่องข้อมูลและความเป็นส่วนตัวล่ะ?", + "go.faq.a5.body": + "แผนนี้ออกแบบมาเพื่อผู้ใช้งานระหว่างประเทศเป็นหลัก โดยมีโมเดลโฮสต์ในสหรัฐอเมริกา สหภาพยุโรป และสิงคโปร์ เพื่อการเข้าถึงทั่วโลกที่เสถียร", + "go.faq.a5.contactAfter": "หากคุณมีคำถามใดๆ", + "go.faq.a5.beforeExceptions": + "โมเดล Go โฮสต์ในสหรัฐอเมริกา ผู้ให้บริการปฏิบัติตามนโยบายไม่เก็บรักษาข้อมูล (zero-retention policy) และไม่ใช้ข้อมูลของคุณสำหรับการฝึกโมเดล โดยมี", + "go.faq.a5.exceptionsLink": "ข้อยกเว้นดังนี้", + "go.faq.q6": "ฉันสามารถเติมเครดิตได้หรือไม่?", + "go.faq.a6": "หากคุณต้องการใช้งานเพิ่ม คุณสามารถเติมเครดิตในบัญชีของคุณได้", + "go.faq.q7": "ฉันสามารถยกเลิกได้หรือไม่?", + "go.faq.a7": "ได้ คุณสามารถยกเลิกได้ตลอดเวลา", + "go.faq.q8": "ฉันสามารถใช้ Go กับเอเจนต์เขียนโค้ดอื่นได้หรือไม่?", + "go.faq.a8": "ได้ คุณสามารถใช้ Go กับเอเจนต์ใดก็ได้ ทำตามคำแนะนำการตั้งค่าในเอเจนต์เขียนโค้ดที่คุณต้องการ", + + "go.faq.q9": "ความแตกต่างระหว่างโมเดลฟรีและ Go คืออะไร?", + "go.faq.a9": + "โมเดลฟรีรวมถึง Big Pickle บวกกับโมเดลโปรโมชั่นที่มีให้ในขณะนั้น ด้วยโควต้า 200 คำขอ/วัน Go รวมถึง GLM-5, Kimi K2.5 และ MiniMax M2.5 ที่มีโควต้าคำขอสูงกว่า ซึ่งบังคับใช้ผ่านช่วงเวลาหมุนเวียน (5 ชั่วโมง, รายสัปดาห์ และรายเดือน) เทียบเท่าประมาณ $12 ต่อ 5 ชั่วโมง, $30 ต่อสัปดาห์ และ $60 ต่อเดือน (จำนวนคำขอจริงจะแตกต่างกันไปตามโมเดลและการใช้งาน)", + + "zen.api.error.rateLimitExceeded": "เกินขีดจำกัดอัตราการใช้งาน กรุณาลองใหม่ในภายหลัง", + "zen.api.error.modelNotSupported": "ไม่รองรับโมเดล {{model}}", + "zen.api.error.modelFormatNotSupported": "ไม่รองรับโมเดล {{model}} สำหรับรูปแบบ {{format}}", + "zen.api.error.noProviderAvailable": "ไม่มีผู้ให้บริการที่พร้อมใช้งาน", + "zen.api.error.providerNotSupported": "ไม่รองรับผู้ให้บริการ {{provider}}", + "zen.api.error.missingApiKey": "ไม่มี API key", + "zen.api.error.invalidApiKey": "API key ไม่ถูกต้อง", + "zen.api.error.subscriptionQuotaExceeded": "โควต้าการสมัครสมาชิกเกินขีดจำกัด ลองใหม่ในอีก {{retryIn}}", + "zen.api.error.subscriptionQuotaExceededUseFreeModels": + "โควต้าการสมัครสมาชิกเกินขีดจำกัด คุณสามารถดำเนินการต่อโดยใช้โมเดลฟรี", + "zen.api.error.noPaymentMethod": "ไม่มีวิธีการชำระเงิน เพิ่มวิธีการชำระเงินที่นี่: {{billingUrl}}", + "zen.api.error.insufficientBalance": "ยอดเงินคงเหลือไม่เพียงพอ จัดการการเรียกเก็บเงินของคุณที่นี่: {{billingUrl}}", + "zen.api.error.workspaceMonthlyLimitReached": + "Workspace ของคุณถึงขีดจำกัดการใช้จ่ายรายเดือนที่ ${{amount}} แล้ว จัดการขีดจำกัดของคุณที่นี่: {{billingUrl}}", + "zen.api.error.userMonthlyLimitReached": + "คุณถึงขีดจำกัดการใช้จ่ายรายเดือนที่ ${{amount}} แล้ว จัดการขีดจำกัดของคุณที่นี่: {{membersUrl}}", + "zen.api.error.modelDisabled": "โมเดลถูกปิดใช้งาน", + "black.meta.title": "OpenCode Black | เข้าถึงโมเดลเขียนโค้ดที่ดีที่สุดในโลก", "black.meta.description": "เข้าถึง Claude, GPT, Gemini และอื่นๆ ด้วยแผนสมาชิก OpenCode Black", "black.hero.title": "เข้าถึงโมเดลเขียนโค้ดที่ดีที่สุดในโลก", "black.hero.subtitle": "รวมถึง Claude, GPT, Gemini และอื่นๆ อีกมากมาย", "black.title": "OpenCode Black | ราคา", + "black.paused": "การสมัครแผน Black หยุดชั่วคราว", "black.plan.icon20": "แผน Black 20", "black.plan.icon100": "แผน Black 100", "black.plan.icon200": "แผน Black 200", @@ -339,12 +466,15 @@ export const dict = { "workspace.usage.table.input": "Input", "workspace.usage.table.output": "Output", "workspace.usage.table.cost": "ค่าใช้จ่าย", + "workspace.usage.table.session": "เซสชัน", "workspace.usage.breakdown.input": "Input", "workspace.usage.breakdown.cacheRead": "Cache Read", "workspace.usage.breakdown.cacheWrite": "Cache Write", "workspace.usage.breakdown.output": "Output", "workspace.usage.breakdown.reasoning": "Reasoning", - "workspace.usage.subscription": "สมัครสมาชิก (${{amount}})", + "workspace.usage.subscription": "Black (${{amount}})", + "workspace.usage.lite": "Go (${{amount}})", + "workspace.usage.byok": "BYOK (${{amount}})", "workspace.cost.title": "ค่าใช้จ่าย", "workspace.cost.subtitle": "ต้นทุนการใช้งานแยกตามโมเดล", @@ -443,6 +573,7 @@ export const dict = { "workspace.reload.updatePaymentMethod": "โปรดอัปเดตวิธีการชำระเงินของคุณแล้วลองอีกครั้ง", "workspace.reload.retrying": "กำลังลองอีกครั้ง...", "workspace.reload.retry": "ลองอีกครั้ง", + "workspace.reload.error.paymentFailed": "การชำระเงินล้มเหลว", "workspace.payments.title": "ประวัติการชำระเงิน", "workspace.payments.subtitle": "รายการธุรกรรมการชำระเงินล่าสุด", @@ -481,6 +612,36 @@ export const dict = { "workspace.black.waitlist.enrollNote": "เมื่อคุณคลิกลงทะเบียน การสมัครสมาชิกของคุณจะเริ่มต้นทันทีและบัตรของคุณจะถูกเรียกเก็บเงิน", + "workspace.lite.loading": "กำลังโหลด...", + "workspace.lite.time.day": "วัน", + "workspace.lite.time.days": "วัน", + "workspace.lite.time.hour": "ชั่วโมง", + "workspace.lite.time.hours": "ชั่วโมง", + "workspace.lite.time.minute": "นาที", + "workspace.lite.time.minutes": "นาที", + "workspace.lite.time.fewSeconds": "ไม่กี่วินาที", + "workspace.lite.subscription.title": "การสมัครสมาชิก Go", + "workspace.lite.subscription.message": "คุณได้สมัครสมาชิก OpenCode Go แล้ว", + "workspace.lite.subscription.manage": "จัดการการสมัครสมาชิก", + "workspace.lite.subscription.rollingUsage": "การใช้งานแบบหมุนเวียน", + "workspace.lite.subscription.weeklyUsage": "การใช้งานรายสัปดาห์", + "workspace.lite.subscription.monthlyUsage": "การใช้งานรายเดือน", + "workspace.lite.subscription.resetsIn": "รีเซ็ตใน", + "workspace.lite.subscription.useBalance": "ใช้ยอดคงเหลือของคุณหลังจากถึงขีดจำกัดการใช้งาน", + "workspace.lite.subscription.selectProvider": + 'เลือก "OpenCode Go" เป็นผู้ให้บริการในการตั้งค่า opencode ของคุณเพื่อใช้โมเดล Go', + "workspace.lite.other.title": "การสมัครสมาชิก Go", + "workspace.lite.other.message": + "สมาชิกคนอื่นใน Workspace นี้ได้สมัคร OpenCode Go แล้ว สามารถสมัครได้เพียงหนึ่งคนต่อหนึ่ง Workspace เท่านั้น", + "workspace.lite.promo.title": "OpenCode Go", + "workspace.lite.promo.description": + "OpenCode Go เป็นการสมัครสมาชิกราคา 10 ดอลลาร์ต่อเดือน ที่ให้การเข้าถึงโมเดลโอเพนโค้ดดิงยอดนิยมได้อย่างเสถียร ด้วยขีดจำกัดการใช้งานที่ครอบคลุม", + "workspace.lite.promo.modelsTitle": "สิ่งที่รวมอยู่ด้วย", + "workspace.lite.promo.footer": + "แผนนี้ออกแบบมาสำหรับผู้ใช้งานต่างประเทศเป็นหลัก โดยมีโมเดลโฮสต์อยู่ในสหรัฐอเมริกา สหภาพยุโรป และสิงคโปร์ เพื่อการเข้าถึงที่เสถียรทั่วโลก ราคาและขีดจำกัดการใช้งานอาจมีการเปลี่ยนแปลงตามที่เราได้เรียนรู้จากการใช้งานในช่วงแรกและข้อเสนอแนะ", + "workspace.lite.promo.subscribe": "สมัครสมาชิก Go", + "workspace.lite.promo.subscribing": "กำลังเปลี่ยนเส้นทาง...", + "download.title": "OpenCode | ดาวน์โหลด", "download.meta.description": "ดาวน์โหลด OpenCode สำหรับ macOS, Windows และ Linux", "download.hero.title": "ดาวน์โหลด OpenCode", @@ -531,6 +692,10 @@ export const dict = { "enterprise.form.send": "ส่ง", "enterprise.form.sending": "กำลังส่ง...", "enterprise.form.success": "ส่งข้อความแล้ว เราจะติดต่อกลับเร็วๆ นี้", + "enterprise.form.success.submitted": "ส่งแบบฟอร์มสำเร็จแล้ว", + "enterprise.form.error.allFieldsRequired": "จำเป็นต้องกรอกทุกช่อง", + "enterprise.form.error.invalidEmailFormat": "รูปแบบอีเมลไม่ถูกต้อง", + "enterprise.form.error.internalServer": "เกิดข้อผิดพลาดภายในเซิร์ฟเวอร์", "enterprise.faq.title": "คำถามที่พบบ่อย", "enterprise.faq.q1": "OpenCode Enterprise คืออะไร?", "enterprise.faq.a1": @@ -563,6 +728,7 @@ export const dict = { "bench.list.table.agent": "เอเจนต์", "bench.list.table.model": "โมเดล", "bench.list.table.score": "คะแนน", + "bench.submission.error.allFieldsRequired": "จำเป็นต้องกรอกทุกช่อง", "bench.detail.title": "Benchmark - {{task}}", "bench.detail.notFound": "ไม่พบงาน", diff --git a/packages/console/app/src/i18n/tr.ts b/packages/console/app/src/i18n/tr.ts index e2f747704e..e28afe2b06 100644 --- a/packages/console/app/src/i18n/tr.ts +++ b/packages/console/app/src/i18n/tr.ts @@ -15,6 +15,7 @@ export const dict = { "nav.home": "Ana sayfa", "nav.openMenu": "Menüyü aç", "nav.getStartedFree": "Ücretsiz başla", + "nav.logoAlt": "OpenCode", "nav.context.copyLogo": "Logoyu SVG olarak kopyala", "nav.context.copyWordmark": "Wordmark'ı SVG olarak kopyala", @@ -42,9 +43,13 @@ export const dict = { "notFound.docs": "Dokümantasyon", "notFound.github": "GitHub", "notFound.discord": "Discord", + "notFound.logoLightAlt": "opencode açık logo", + "notFound.logoDarkAlt": "opencode koyu logo", "user.logout": "Çıkış", + "auth.callback.error.codeMissing": "Yetkilendirme kodu bulunamadı.", + "workspace.select": "Çalışma alanı seç", "workspace.createNew": "+ Yeni çalışma alanı oluştur", "workspace.modal.title": "Yeni çalışma alanı oluştur", @@ -76,6 +81,8 @@ export const dict = { "error.reloadAmountMin": "Yükleme tutarı en az ${{amount}} olmalıdır", "error.reloadTriggerMin": "Bakiye tetikleyicisi en az ${{amount}} olmalıdır", + "app.meta.description": "OpenCode - Açık kaynaklı kodlama ajanı.", + "home.title": "OpenCode | Açık kaynaklı yapay zeka kodlama ajanı", "temp.title": "opencode | Terminal için geliştirilmiş yapay zeka kodlama ajanı", @@ -91,9 +98,11 @@ export const dict = { "temp.feature.models.afterLink": " üzerinden destekler", "temp.screenshot.caption": "opencode TUI ve tokyonight teması", "temp.screenshot.alt": "tokyonight temalı opencode TUI", + "temp.logoLightAlt": "opencode açık logo", + "temp.logoDarkAlt": "opencode koyu logo", "home.banner.badge": "Yeni", - "home.banner.text": "Masaüstü uygulaması beta olarak kullanılabilir", + "home.banner.text": "Masaüstü uygulaması beta olarak mevcut", "home.banner.platforms": "macOS, Windows ve Linux'ta", "home.banner.downloadNow": "Şimdi indir", "home.banner.downloadBetaNow": "Masaüstü betayı şimdi indir", @@ -130,7 +139,7 @@ export const dict = { "home.growth.contributors": "Katılımcılar", "home.growth.monthlyDevs": "Aylık Geliştiriciler", - "home.privacy.title": "Önce gizlilik için tasarlandı", + "home.privacy.title": "Gizlilik öncelikli tasarlandı", "home.privacy.body": "OpenCode kodunuzu veya bağlam verilerinizi saklamaz; bu sayede gizliliğe duyarlı ortamlarda çalışabilir.", "home.privacy.learnMore": "Hakkında daha fazla bilgi:", @@ -148,12 +157,12 @@ export const dict = { "home.faq.a3.p2.afterZen": " hesabı oluşturabilirsiniz.", "home.faq.a3.p3": "Zen'i öneriyoruz, ancak OpenCode OpenAI, Anthropic, xAI gibi popüler sağlayıcılarla da çalışır.", "home.faq.a3.p4.beforeLocal": "Hatta", - "home.faq.a3.p4.localLink": "yerel modellerinizi", + "home.faq.a3.p4.localLink": "yerel modellerinizi bağlayabilirsiniz", "home.faq.q4": "Mevcut AI aboneliklerimi OpenCode ile kullanabilir miyim?", "home.faq.a4.p1": "Evet. OpenCode tüm büyük sağlayıcıların aboneliklerini destekler. Claude Pro/Max, ChatGPT Plus/Pro veya GitHub Copilot kullanabilirsiniz.", "home.faq.q5": "OpenCode'u sadece terminalde mi kullanabilirim?", - "home.faq.a5.beforeDesktop": "Artık hayır! OpenCode şimdi", + "home.faq.a5.beforeDesktop": "Artık hayır! OpenCode artık sizin bu cihazlarınıza", "home.faq.a5.desktop": "masaüstü", "home.faq.a5.and": "ve", "home.faq.a5.web": "web", @@ -169,10 +178,10 @@ export const dict = { "home.faq.a7.p2.shareLink": "paylaşım sayfaları", "home.faq.q8": "OpenCode açık kaynak mı?", "home.faq.a8.p1": "Evet, OpenCode tamamen açık kaynaktır. Kaynak kodu", - "home.faq.a8.p2": "altında", + "home.faq.a8.p2": "'da", "home.faq.a8.mitLicense": "MIT Lisansı", "home.faq.a8.p3": - ", yani herkes kullanabilir, değiştirebilir veya geliştirmeye katkıda bulunabilir. Topluluktan herkes issue açabilir, pull request gönderebilir ve işlevselliği genişletebilir.", + "altında herkese açıktır, yani herkes kullanabilir, değiştirebilir veya geliştirmeye katkıda bulunabilir. Topluluktan herkes issue açabilir, pull request gönderebilir ve işlevselliği genişletebilir.", "home.zenCta.title": "Kodlama ajanları için güvenilir, optimize modeller", "home.zenCta.body": @@ -242,11 +251,131 @@ export const dict = { "Tüm Zen modelleri ABD'de barındırılmaktadır. Sağlayıcılar sıfır saklama politikası izler ve verilerinizi model eğitimi için kullanmaz; şu", "zen.privacy.exceptionsLink": "aşağıdaki istisnalar", + "go.title": "OpenCode Go | Herkes için düşük maliyetli kodlama modelleri", + "go.meta.description": + "Go, GLM-5, Kimi K2.5 ve MiniMax M2.5 için cömert 5 saatlik istek limitleri sunan aylık 10$'lık bir aboneliktir.", + "go.hero.title": "Herkes için düşük maliyetli kodlama modelleri", + "go.hero.body": + "Go, dünya çapındaki programcılara ajan tabanlı kodlama getiriyor. En yetenekli açık kaynaklı modellere cömert limitler ve güvenilir erişim sunarak, maliyet veya erişilebilirlik konusunda endişelenmeden güçlü ajanlarla geliştirme yapmanızı sağlar.", + + "go.cta.start": "Go'ya abone ol", + "go.cta.template": "{{text}} {{price}}", + "go.cta.text": "Go'ya abone ol", + "go.cta.price": "Ayda 10$", + "go.pricing.body": "Herhangi bir ajanla kullanın. Gerekirse kredi yükleyin. İstediğiniz zaman iptal edin.", + "go.graph.free": "Ücretsiz", + "go.graph.freePill": "Big Pickle ve ücretsiz modeller", + "go.graph.go": "Go", + "go.graph.label": "5 saat başına istekler", + "go.graph.usageLimits": "Kullanım limitleri", + "go.graph.tick": "{{n}}x", + "go.graph.aria": "5 saatlik istekler: {{free}} vs {{go}}", + + "go.testimonials.brand.zen": "Zen", + "go.testimonials.brand.go": "Go", + "go.testimonials.handle": "@OpenCode", + "go.testimonials.dax.name": "Dax Raad", + "go.testimonials.dax.title": "Eski CEO, Terminal Ürünleri", + "go.testimonials.dax.quoteAfter": "hayat değiştirdi, gerçekten düşünmeye bile gerek yok.", + "go.testimonials.jay.name": "Jay V", + "go.testimonials.jay.title": "Eski Kurucu, SEED, PM, Melt, Pop, Dapt, Cadmus ve ViewPoint", + "go.testimonials.jay.quoteBefore": "Ekibimizdeki 5 kişiden 4'ü", + "go.testimonials.jay.quoteAfter": "kullanmayı seviyor.", + "go.testimonials.adam.name": "Adam Elmore", + "go.testimonials.adam.title": "Eski Hero, AWS", + "go.testimonials.adam.quoteBefore": "", + "go.testimonials.adam.quoteAfter": "için tavsiyem sonsuz. Cidden, gerçekten çok iyi.", + "go.testimonials.david.name": "David Hill", + "go.testimonials.david.title": "Eski Tasarım Başkanı, Laravel", + "go.testimonials.david.quoteBefore": "", + "go.testimonials.david.quoteAfter": + " ile modellerin test edildiğini ve kodlama ajanları için mükemmel olduğunu biliyorum.", + "go.testimonials.frank.name": "Frank Wang", + "go.testimonials.frank.title": "Eski Stajyer, Nvidia (4 kez)", + "go.testimonials.frank.quote": "Keşke hala Nvidia'da olsaydım.", + "go.problem.title": "Go hangi sorunu çözüyor?", + "go.problem.body": + "OpenCode deneyimini mümkün olduğunca çok kişiye ulaştırmaya odaklanıyoruz. OpenCode Go, ajan tabanlı kodlamayı dünya çapındaki programcılara sunmak için tasarlanmış düşük maliyetli (ayda 10$) bir aboneliktir. En yetenekli açık kaynaklı modellere cömert limitler ve güvenilir erişim sağlar.", + "go.problem.subtitle": " ", + "go.problem.item1": "Düşük maliyetli abonelik fiyatlandırması", + "go.problem.item2": "Cömert limitler ve güvenilir erişim", + "go.problem.item3": "Mümkün olduğunca çok programcı için geliştirildi", + "go.problem.item4": "GLM-5, Kimi K2.5 ve MiniMax M2.5 içerir", + "go.how.title": "Go nasıl çalışır?", + "go.how.body": "Go, OpenCode veya herhangi bir ajanla kullanabileceğiniz aylık 10$'lık bir aboneliktir.", + "go.how.step1.title": "Bir hesap oluşturun", + "go.how.step1.beforeLink": "takip edin", + "go.how.step1.link": "kurulum talimatları", + "go.how.step2.title": "Go'ya abone olun", + "go.how.step2.link": "Ayda 10$", + "go.how.step2.afterLink": ", cömert limitlerle", + "go.how.step3.title": "Kodlamaya başlayın", + "go.how.step3.body": "açık kaynaklı modellere güvenilir erişimle", + "go.privacy.title": "Gizliliğiniz bizim için önemlidir", + "go.privacy.body": + "Bu plan öncelikle uluslararası kullanıcılar için tasarlanmış olup, istikrarlı küresel erişim için modeller ABD, AB ve Singapur'da barındırılmaktadır.", + "go.privacy.contactAfter": "herhangi bir sorunuz varsa.", + "go.privacy.beforeExceptions": + "Go modelleri ABD'de barındırılmaktadır. Sağlayıcılar sıfır saklama politikası izler ve verilerinizi model eğitimi için kullanmaz; şu", + "go.privacy.exceptionsLink": "aşağıdaki istisnalar", + "go.faq.q1": "OpenCode Go nedir?", + "go.faq.a1": + "Go, ajan tabanlı kodlama için yetenekli açık kaynaklı modellere güvenilir erişim sağlayan düşük maliyetli bir aboneliktir.", + "go.faq.q2": "Go hangi modelleri içerir?", + "go.faq.a2": "Go, cömert limitler ve güvenilir erişim ile GLM-5, Kimi K2.5 ve MiniMax M2.5 modellerini içerir.", + "go.faq.q3": "Go, Zen ile aynı mı?", + "go.faq.a3": + "Hayır. Zen kullandıkça öde sistemidir; Go ise GLM-5, Kimi K2.5 ve MiniMax M2.5 açık kaynak modellerine cömert limitler ve güvenilir erişim sağlayan aylık 10$'lık bir aboneliktir.", + "go.faq.q4": "Go ne kadar?", + "go.faq.a4.p1.beforePricing": "Go'nun maliyeti", + "go.faq.a4.p1.pricingLink": "ayda 10$", + "go.faq.a4.p1.afterPricing": ", cömert limitlerle.", + "go.faq.a4.p2.beforeAccount": "Aboneliğinizi", + "go.faq.a4.p2.accountLink": "hesabınızdan", + "go.faq.a4.p3": "yönetebilirsiniz. İstediğiniz zaman iptal edin.", + "go.faq.q5": "Veri ve gizlilik ne olacak?", + "go.faq.a5.body": + "Bu plan öncelikle uluslararası kullanıcılar için tasarlanmış olup, istikrarlı küresel erişim için modeller ABD, AB ve Singapur'da barındırılmaktadır.", + "go.faq.a5.contactAfter": "herhangi bir sorunuz varsa.", + "go.faq.a5.beforeExceptions": + "Go modelleri ABD'de barındırılmaktadır. Sağlayıcılar sıfır saklama politikası izler ve verilerinizi model eğitimi için kullanmaz; şu", + "go.faq.a5.exceptionsLink": "aşağıdaki istisnalar", + "go.faq.q6": "Kredi yükleyebilir miyim?", + "go.faq.a6": "Daha fazla kullanıma ihtiyacınız varsa, hesabınıza kredi yükleyebilirsiniz.", + "go.faq.q7": "İptal edebilir miyim?", + "go.faq.a7": "Evet, istediğiniz zaman iptal edebilirsiniz.", + "go.faq.q8": "Go'yu diğer kodlama ajanlarıyla kullanabilir miyim?", + "go.faq.a8": + "Evet, Go'yu herhangi bir ajanla kullanabilirsiniz. Tercih ettiğiniz kodlama ajanındaki kurulum talimatlarını izleyin.", + + "go.faq.q9": "Ücretsiz modeller ve Go arasındaki fark nedir?", + "go.faq.a9": + "Ücretsiz modeller, günlük 200 istek kotası ile Big Pickle ve o sırada mevcut olan promosyonel modelleri içerir. Go ise GLM-5, Kimi K2.5 ve MiniMax M2.5 modellerini; yuvarlanan pencereler (5 saatlik, haftalık ve aylık) üzerinden uygulanan daha yüksek istek kotalarıyla içerir. Bu kotalar kabaca her 5 saatte 12$, haftada 30$ ve ayda 60$ değerine eşdeğerdir (gerçek istek sayıları modele ve kullanıma göre değişir).", + + "zen.api.error.rateLimitExceeded": "İstek limiti aşıldı. Lütfen daha sonra tekrar deneyin.", + "zen.api.error.modelNotSupported": "{{model}} modeli desteklenmiyor", + "zen.api.error.modelFormatNotSupported": "{{model}} modeli {{format}} formatı için desteklenmiyor", + "zen.api.error.noProviderAvailable": "Kullanılabilir sağlayıcı yok", + "zen.api.error.providerNotSupported": "{{provider}} sağlayıcısı desteklenmiyor", + "zen.api.error.missingApiKey": "API anahtarı eksik.", + "zen.api.error.invalidApiKey": "Geçersiz API anahtarı.", + "zen.api.error.subscriptionQuotaExceeded": "Abonelik kotası aşıldı. {{retryIn}} içinde tekrar deneyin.", + "zen.api.error.subscriptionQuotaExceededUseFreeModels": + "Abonelik kotası aşıldı. Ücretsiz modelleri kullanmaya devam edebilirsiniz.", + "zen.api.error.noPaymentMethod": "Ödeme yöntemi bulunamadı. Buradan bir ödeme yöntemi ekleyin: {{billingUrl}}", + "zen.api.error.insufficientBalance": "Yetersiz bakiye. Faturalandırmanızı buradan yönetin: {{billingUrl}}", + "zen.api.error.workspaceMonthlyLimitReached": + "Çalışma alanınız aylık ${{amount}} harcama limitine ulaştı. Limitlerinizi buradan yönetin: {{billingUrl}}", + "zen.api.error.userMonthlyLimitReached": + "Aylık ${{amount}} harcama limitinize ulaştınız. Limitlerinizi buradan yönetin: {{membersUrl}}", + "zen.api.error.modelDisabled": "Model devre dışı", + "black.meta.title": "OpenCode Black | Dünyanın en iyi kodlama modellerine erişin", "black.meta.description": "OpenCode Black abonelik planlarıyla Claude, GPT, Gemini ve daha fazlasına erişin.", "black.hero.title": "Dünyanın en iyi kodlama modellerine erişin", "black.hero.subtitle": "Claude, GPT, Gemini ve daha fazlası dahil", "black.title": "OpenCode Black | Fiyatlandırma", + "black.paused": "Black plan kaydı geçici olarak duraklatıldı.", "black.plan.icon20": "Black 20 planı", "black.plan.icon100": "Black 100 planı", "black.plan.icon200": "Black 200 planı", @@ -342,12 +471,15 @@ export const dict = { "workspace.usage.table.input": "Giriş", "workspace.usage.table.output": "Çıkış", "workspace.usage.table.cost": "Maliyet", + "workspace.usage.table.session": "Oturum", "workspace.usage.breakdown.input": "Giriş", "workspace.usage.breakdown.cacheRead": "Önbellek Okuması", "workspace.usage.breakdown.cacheWrite": "Önbellek Yazma", "workspace.usage.breakdown.output": "Çıkış", "workspace.usage.breakdown.reasoning": "Muhakeme", - "workspace.usage.subscription": "abonelik (${{amount}})", + "workspace.usage.subscription": "Black (${{amount}})", + "workspace.usage.lite": "Go (${{amount}})", + "workspace.usage.byok": "BYOK (${{amount}})", "workspace.cost.title": "Maliyet", "workspace.cost.subtitle": "Modele göre ayrılmış kullanım maliyetleri.", @@ -446,6 +578,7 @@ export const dict = { "workspace.reload.updatePaymentMethod": "Lütfen ödeme yönteminizi güncelleyin ve tekrar deneyin.", "workspace.reload.retrying": "Yeniden deneniyor...", "workspace.reload.retry": "Yeniden dene", + "workspace.reload.error.paymentFailed": "Ödeme başarısız.", "workspace.payments.title": "Ödeme Geçmişi", "workspace.payments.subtitle": "Son ödeme işlemleri.", @@ -484,6 +617,36 @@ export const dict = { "workspace.black.waitlist.enrollNote": "Kayıt Ol'a tıkladığınızda aboneliğiniz hemen başlar ve kartınızdan çekim yapılır.", + "workspace.lite.loading": "Yükleniyor...", + "workspace.lite.time.day": "gün", + "workspace.lite.time.days": "gün", + "workspace.lite.time.hour": "saat", + "workspace.lite.time.hours": "saat", + "workspace.lite.time.minute": "dakika", + "workspace.lite.time.minutes": "dakika", + "workspace.lite.time.fewSeconds": "birkaç saniye", + "workspace.lite.subscription.title": "Go Aboneliği", + "workspace.lite.subscription.message": "OpenCode Go abonesisiniz.", + "workspace.lite.subscription.manage": "Aboneliği Yönet", + "workspace.lite.subscription.rollingUsage": "Devam Eden Kullanım", + "workspace.lite.subscription.weeklyUsage": "Haftalık Kullanım", + "workspace.lite.subscription.monthlyUsage": "Aylık Kullanım", + "workspace.lite.subscription.resetsIn": "Sıfırlama süresi", + "workspace.lite.subscription.useBalance": "Kullanım limitlerine ulaştıktan sonra mevcut bakiyenizi kullanın", + "workspace.lite.subscription.selectProvider": + 'Go modellerini kullanmak için opencode yapılandırmanızda "OpenCode Go"\'yu sağlayıcı olarak seçin.', + "workspace.lite.other.title": "Go Aboneliği", + "workspace.lite.other.message": + "Bu çalışma alanındaki başka bir üye zaten OpenCode Go abonesi. Çalışma alanı başına yalnızca bir üye abone olabilir.", + "workspace.lite.promo.title": "OpenCode Go", + "workspace.lite.promo.description": + "OpenCode Go, cömert kullanım limitleriyle popüler açık kodlama modellerine güvenilir erişim sağlayan aylık 10$'lık bir aboneliktir.", + "workspace.lite.promo.modelsTitle": "Neler Dahil", + "workspace.lite.promo.footer": + "Plan öncelikle uluslararası kullanıcılar için tasarlanmıştır; modeller istikrarlı küresel erişim için ABD, AB ve Singapur'da barındırılmaktadır. Erken kullanımdan öğrendikçe ve geri bildirim topladıkça fiyatlandırma ve kullanım limitleri değişebilir.", + "workspace.lite.promo.subscribe": "Go'ya Abone Ol", + "workspace.lite.promo.subscribing": "Yönlendiriliyor...", + "download.title": "OpenCode | İndir", "download.meta.description": "OpenCode'u macOS, Windows ve Linux için indirin", "download.hero.title": "OpenCode'u İndir", @@ -536,6 +699,10 @@ export const dict = { "enterprise.form.send": "Gönder", "enterprise.form.sending": "Gönderiliyor...", "enterprise.form.success": "Mesaj gönderildi, yakında size dönüş yapacağız.", + "enterprise.form.success.submitted": "Form başarıyla gönderildi.", + "enterprise.form.error.allFieldsRequired": "Tüm alanlar gereklidir.", + "enterprise.form.error.invalidEmailFormat": "Geçersiz e-posta formatı.", + "enterprise.form.error.internalServer": "İç sunucu hatası.", "enterprise.faq.title": "SSS", "enterprise.faq.q1": "OpenCode Enterprise nedir?", "enterprise.faq.a1": @@ -568,6 +735,7 @@ export const dict = { "bench.list.table.agent": "Ajan", "bench.list.table.model": "Model", "bench.list.table.score": "Puan", + "bench.submission.error.allFieldsRequired": "Tüm alanlar gereklidir.", "bench.detail.title": "Benchmark - {{task}}", "bench.detail.notFound": "Görev bulunamadı", diff --git a/packages/console/app/src/i18n/zh.ts b/packages/console/app/src/i18n/zh.ts index c31b9ea661..87ba1b2450 100644 --- a/packages/console/app/src/i18n/zh.ts +++ b/packages/console/app/src/i18n/zh.ts @@ -15,6 +15,7 @@ export const dict = { "nav.home": "首页", "nav.openMenu": "打开菜单", "nav.getStartedFree": "免费开始", + "nav.logoAlt": "OpenCode", "nav.context.copyLogo": "复制 Logo (SVG)", "nav.context.copyWordmark": "复制商标 (SVG)", @@ -42,9 +43,13 @@ export const dict = { "notFound.docs": "文档", "notFound.github": "GitHub", "notFound.discord": "Discord", + "notFound.logoLightAlt": "opencode logo 亮色", + "notFound.logoDarkAlt": "opencode logo 暗色", "user.logout": "退出登录", + "auth.callback.error.codeMissing": "未找到授权码。", + "workspace.select": "选择工作区", "workspace.createNew": "+ 新建工作区", "workspace.modal.title": "新建工作区", @@ -76,6 +81,8 @@ export const dict = { "error.reloadAmountMin": "充值金额必须至少为 ${{amount}}", "error.reloadTriggerMin": "余额触发阈值必须至少为 ${{amount}}", + "app.meta.description": "OpenCode - 开源编程代理。", + "home.title": "OpenCode | 开源 AI 编程代理", "temp.title": "OpenCode | 专为终端打造的 AI 编程代理", @@ -91,6 +98,8 @@ export const dict = { "temp.feature.models.afterLink": ",包括本地模型", "temp.screenshot.caption": "使用 Tokyonight 主题的 OpenCode TUI", "temp.screenshot.alt": "使用 Tokyonight 主题的 OpenCode TUI", + "temp.logoLightAlt": "opencode logo 亮色", + "temp.logoDarkAlt": "opencode logo 暗色", "home.banner.badge": "新", "home.banner.text": "桌面应用 Beta 版现已推出", @@ -229,11 +238,121 @@ export const dict = { "zen.privacy.beforeExceptions": "所有 Zen 模型均托管在美国。提供商遵循零留存政策,不使用您的数据进行模型训练,", "zen.privacy.exceptionsLink": "以下例外情况除外", + "go.title": "OpenCode Go | 人人可用的低成本编程模型", + "go.meta.description": "Go 是每月 $10 的订阅服务,提供对 GLM-5, Kimi K2.5, 和 MiniMax M2.5 的 5 小时内充裕请求限额。", + "go.hero.title": "人人可用的低成本编程模型", + "go.hero.body": + "Go 将代理编程带给全世界的程序员。提供充裕的限额和对最强大的开源模型的可靠访问,让您可以利用强大的代理进行构建,而无需担心成本或可用性。", + + "go.cta.start": "订阅 Go", + "go.cta.template": "{{text}} {{price}}", + "go.cta.text": "订阅 Go", + "go.cta.price": "$10/月", + "go.pricing.body": "可配合任何代理使用。按需充值。随时取消。", + "go.graph.free": "免费", + "go.graph.freePill": "Big Pickle 和免费模型", + "go.graph.go": "Go", + "go.graph.label": "每 5 小时请求数", + "go.graph.usageLimits": "使用限制", + "go.graph.tick": "{{n}}x", + "go.graph.aria": "每 5 小时请求数: {{free}} vs {{go}}", + + "go.testimonials.brand.zen": "Zen", + "go.testimonials.brand.go": "Go", + "go.testimonials.handle": "@OpenCode", + "go.testimonials.dax.name": "Dax Raad", + "go.testimonials.dax.title": "前 CEO, Terminal Products", + "go.testimonials.dax.quoteAfter": "彻底改变了我的生活,这绝对是不二之选。", + "go.testimonials.jay.name": "Jay V", + "go.testimonials.jay.title": "前创始人, SEED, PM, Melt, Pop, Dapt, Cadmus, 和 ViewPoint", + "go.testimonials.jay.quoteBefore": "我们团队 5 个人里有 4 个都爱用", + "go.testimonials.jay.quoteAfter": "。", + "go.testimonials.adam.name": "Adam Elmore", + "go.testimonials.adam.title": "前 Hero, AWS", + "go.testimonials.adam.quoteBefore": "我强烈推荐", + "go.testimonials.adam.quoteAfter": "。真的,非常好用。", + "go.testimonials.david.name": "David Hill", + "go.testimonials.david.title": "前设计主管, Laravel", + "go.testimonials.david.quoteBefore": "有了", + "go.testimonials.david.quoteAfter": "我知道所有模型都经过测试,非常适合编程代理。", + "go.testimonials.frank.name": "Frank Wang", + "go.testimonials.frank.title": "前实习生, Nvidia (4 次)", + "go.testimonials.frank.quote": "我希望我还在 Nvidia。", + "go.problem.title": "Go 解决了什么问题?", + "go.problem.body": + "我们致力于将 OpenCode 体验带给尽可能多的人。OpenCode Go 是一个低成本 ($10/月) 的订阅服务,旨在将代理编程带给全世界的程序员。它提供充裕的限额和对最强大的开源模型的可靠访问。", + "go.problem.subtitle": " ", + "go.problem.item1": "低成本订阅定价", + "go.problem.item2": "充裕的限额和可靠的访问", + "go.problem.item3": "为尽可能多的程序员打造", + "go.problem.item4": "包含 GLM-5, Kimi K2.5, 和 MiniMax M2.5", + "go.how.title": "Go 如何工作", + "go.how.body": "Go 是每月 $10 的订阅服务,您可以配合 OpenCode 或任何代理使用。", + "go.how.step1.title": "创建账户", + "go.how.step1.beforeLink": "遵循", + "go.how.step1.link": "设置说明", + "go.how.step2.title": "订阅 Go", + "go.how.step2.link": "$10/月", + "go.how.step2.afterLink": "享受充裕限额", + "go.how.step3.title": "开始编程", + "go.how.step3.body": "可靠访问开源模型", + "go.privacy.title": "您的隐私对我们很重要", + "go.privacy.body": "该计划主要面向国际用户设计,模型部署在美国、欧盟和新加坡,以确保稳定的全球访问。", + "go.privacy.contactAfter": "如果您有任何问题。", + "go.privacy.beforeExceptions": "Go 模型托管在美国。提供商遵循零留存政策,不使用您的数据进行模型训练,", + "go.privacy.exceptionsLink": "以下例外情况除外", + "go.faq.q1": "什么是 OpenCode Go?", + "go.faq.a1": "Go 是一项低成本订阅服务,为您提供对强大的开源模型的可靠访问,用于代理编程。", + "go.faq.q2": "Go 包含哪些模型?", + "go.faq.a2": "Go 包含 GLM-5, Kimi K2.5, 和 MiniMax M2.5,并提供充裕的限额和可靠的访问。", + "go.faq.q3": "Go 和 Zen 一样吗?", + "go.faq.a3": + "不一样。Zen 是即用即付,而 Go 是每月 $10 的订阅服务,提供对开源模型 GLM-5, Kimi K2.5, 和 MiniMax M2.5 的充裕限额和可靠访问。", + "go.faq.q4": "Go 多少钱?", + "go.faq.a4.p1.beforePricing": "Go 费用为", + "go.faq.a4.p1.pricingLink": "$10/月", + "go.faq.a4.p1.afterPricing": "包含充裕限额。", + "go.faq.a4.p2.beforeAccount": "您可以在您的", + "go.faq.a4.p2.accountLink": "账户", + "go.faq.a4.p3": "中管理订阅。随时取消。", + "go.faq.q5": "数据和隐私如何?", + "go.faq.a5.body": "该计划主要面向国际用户设计,模型部署在美国、欧盟和新加坡,以确保稳定的全球访问。", + "go.faq.a5.contactAfter": "如果您有任何问题。", + "go.faq.a5.beforeExceptions": "Go 模型托管在美国。提供商遵循零留存政策,不使用您的数据进行模型训练,", + "go.faq.a5.exceptionsLink": "以下例外情况除外", + "go.faq.q6": "我可以充值余额吗?", + "go.faq.a6": "如果您需要更多用量,可以在账户中充值余额。", + "go.faq.q7": "我可以取消吗?", + "go.faq.a7": "可以,您可以随时取消。", + "go.faq.q8": "我可以在其他编程代理中使用 Go 吗?", + "go.faq.a8": "可以,您可以在任何代理中使用 Go。请遵循您首选编程代理中的设置说明。", + + "go.faq.q9": "免费模型和 Go 之间的区别是什么?", + "go.faq.a9": + "免费模型包含 Big Pickle 加上当时可用的促销模型,每天有 200 次请求的配额。Go 包含 GLM-5, Kimi K2.5, 和 MiniMax M2.5,并在滚动窗口(5 小时、每周和每月)内执行更高的请求配额,大致相当于每 5 小时 $12、每周 $30 和每月 $60(实际请求计数因模型和使用情况而异)。", + + "zen.api.error.rateLimitExceeded": "超出速率限制。请稍后重试。", + "zen.api.error.modelNotSupported": "不支持模型 {{model}}", + "zen.api.error.modelFormatNotSupported": "格式 {{format}} 不支持模型 {{model}}", + "zen.api.error.noProviderAvailable": "没有可用的提供商", + "zen.api.error.providerNotSupported": "不支持提供商 {{provider}}", + "zen.api.error.missingApiKey": "缺少 API 密钥。", + "zen.api.error.invalidApiKey": "无效的 API 密钥。", + "zen.api.error.subscriptionQuotaExceeded": "超出订阅配额。请在 {{retryIn}} 后重试。", + "zen.api.error.subscriptionQuotaExceededUseFreeModels": "超出订阅配额。您可以继续使用免费模型。", + "zen.api.error.noPaymentMethod": "没有付款方式。请在此处添加付款方式:{{billingUrl}}", + "zen.api.error.insufficientBalance": "余额不足。请在此处管理您的计费:{{billingUrl}}", + "zen.api.error.workspaceMonthlyLimitReached": + "您的工作区已达到每月支出限额 ${{amount}}。请在此处管理您的限额:{{billingUrl}}", + "zen.api.error.userMonthlyLimitReached": "您已达到每月支出限额 ${{amount}}。请在此处管理您的限额:{{membersUrl}}", + "zen.api.error.modelDisabled": "模型已禁用", + "black.meta.title": "OpenCode Black | 访问全球顶尖编程模型", "black.meta.description": "通过 OpenCode Black 订阅计划使用 Claude, GPT, Gemini 等模型。", "black.hero.title": "访问全球顶尖编程模型", "black.hero.subtitle": "包括 Claude, GPT, Gemini 等", "black.title": "OpenCode Black | 定价", + "black.paused": "Black 订阅已暂时暂停注册。", "black.plan.icon20": "Black 20 计划", "black.plan.icon100": "Black 100 计划", "black.plan.icon200": "Black 200 计划", @@ -327,12 +446,15 @@ export const dict = { "workspace.usage.table.input": "输入", "workspace.usage.table.output": "输出", "workspace.usage.table.cost": "成本", + "workspace.usage.table.session": "会话", "workspace.usage.breakdown.input": "输入", "workspace.usage.breakdown.cacheRead": "缓存读取", "workspace.usage.breakdown.cacheWrite": "缓存写入", "workspace.usage.breakdown.output": "输出", "workspace.usage.breakdown.reasoning": "推理", - "workspace.usage.subscription": "订阅 (${{amount}})", + "workspace.usage.subscription": "Black (${{amount}})", + "workspace.usage.lite": "Go (${{amount}})", + "workspace.usage.byok": "BYOK (${{amount}})", "workspace.cost.title": "成本", "workspace.cost.subtitle": "按模型细分的使用成本。", @@ -431,6 +553,7 @@ export const dict = { "workspace.reload.updatePaymentMethod": "请更新您的付款方式并重试。", "workspace.reload.retrying": "正在重试...", "workspace.reload.retry": "重试", + "workspace.reload.error.paymentFailed": "支付失败。", "workspace.payments.title": "支付历史", "workspace.payments.subtitle": "近期支付交易。", @@ -468,6 +591,35 @@ export const dict = { "workspace.black.waitlist.enrolled": "已加入", "workspace.black.waitlist.enrollNote": "点击加入后,您的订阅将立即开始,并将从您的卡中扣费。", + "workspace.lite.loading": "加载中...", + "workspace.lite.time.day": "天", + "workspace.lite.time.days": "天", + "workspace.lite.time.hour": "小时", + "workspace.lite.time.hours": "小时", + "workspace.lite.time.minute": "分钟", + "workspace.lite.time.minutes": "分钟", + "workspace.lite.time.fewSeconds": "几秒钟", + "workspace.lite.subscription.title": "Go 订阅", + "workspace.lite.subscription.message": "您已订阅 OpenCode Go。", + "workspace.lite.subscription.manage": "管理订阅", + "workspace.lite.subscription.rollingUsage": "滚动用量", + "workspace.lite.subscription.weeklyUsage": "每周用量", + "workspace.lite.subscription.monthlyUsage": "每月用量", + "workspace.lite.subscription.resetsIn": "重置于", + "workspace.lite.subscription.useBalance": "达到使用限额后使用您的可用余额", + "workspace.lite.subscription.selectProvider": + "在你的 opencode 配置中选择「OpenCode Go」作为提供商,即可使用 Go 模型。", + "workspace.lite.other.title": "Go 订阅", + "workspace.lite.other.message": "此工作区中的另一位成员已经订阅了 OpenCode Go。每个工作区只有一名成员可以订阅。", + "workspace.lite.promo.title": "OpenCode Go", + "workspace.lite.promo.description": + "OpenCode Go 是一个每月 $10 的订阅计划,提供对主流开源编码模型的稳定访问,并配备充足的使用额度。", + "workspace.lite.promo.modelsTitle": "包含模型", + "workspace.lite.promo.footer": + "该计划主要面向国际用户设计,模型部署在美国、欧盟和新加坡,以确保全球范围内的稳定访问体验。定价和使用额度可能会根据早期用户的使用情况和反馈持续调整与优化。", + "workspace.lite.promo.subscribe": "订阅 Go", + "workspace.lite.promo.subscribing": "正在重定向...", + "download.title": "OpenCode | 下载", "download.meta.description": "下载适用于 macOS, Windows, 和 Linux 的 OpenCode", "download.hero.title": "下载 OpenCode", @@ -518,6 +670,10 @@ export const dict = { "enterprise.form.send": "发送", "enterprise.form.sending": "正在发送...", "enterprise.form.success": "消息已发送,我们会尽快与您联系。", + "enterprise.form.success.submitted": "表单提交成功。", + "enterprise.form.error.allFieldsRequired": "所有字段均为必填项。", + "enterprise.form.error.invalidEmailFormat": "邮箱格式无效。", + "enterprise.form.error.internalServer": "内部服务器错误。", "enterprise.faq.title": "常见问题", "enterprise.faq.q1": "什么是 OpenCode 企业版?", "enterprise.faq.a1": @@ -550,6 +706,7 @@ export const dict = { "bench.list.table.agent": "代理", "bench.list.table.model": "模型", "bench.list.table.score": "分数", + "bench.submission.error.allFieldsRequired": "所有字段均为必填项。", "bench.detail.title": "基准测试 - {{task}}", "bench.detail.notFound": "未找到任务", diff --git a/packages/console/app/src/i18n/zht.ts b/packages/console/app/src/i18n/zht.ts index c7b411ca5b..b3f1db0124 100644 --- a/packages/console/app/src/i18n/zht.ts +++ b/packages/console/app/src/i18n/zht.ts @@ -15,6 +15,7 @@ export const dict = { "nav.home": "首頁", "nav.openMenu": "開啟選單", "nav.getStartedFree": "免費開始使用", + "nav.logoAlt": "OpenCode", "nav.context.copyLogo": "複製標誌(SVG)", "nav.context.copyWordmark": "複製字標(SVG)", @@ -42,9 +43,13 @@ export const dict = { "notFound.docs": "文件", "notFound.github": "GitHub", "notFound.discord": "Discord", + "notFound.logoLightAlt": "opencode 淺色標誌", + "notFound.logoDarkAlt": "opencode 深色標誌", "user.logout": "登出", + "auth.callback.error.codeMissing": "找不到授權碼。", + "workspace.select": "選取工作區", "workspace.createNew": "+ 建立新工作區", "workspace.modal.title": "建立新工作區", @@ -76,6 +81,8 @@ export const dict = { "error.reloadAmountMin": "儲值金額必須至少為 ${{amount}}", "error.reloadTriggerMin": "餘額觸發門檻必須至少為 ${{amount}}", + "app.meta.description": "OpenCode - 開源編碼代理。", + "home.title": "OpenCode | 開源 AI 編碼代理", "temp.title": "OpenCode | 專為終端打造的 AI 編碼代理", @@ -91,6 +98,8 @@ export const dict = { "temp.feature.models.afterLink": "支援 75+ 家 LLM 供應商,包括本地模型", "temp.screenshot.caption": "使用 tokyonight 主題的 OpenCode TUI", "temp.screenshot.alt": "使用 tokyonight 主題的 OpenCode TUI", + "temp.logoLightAlt": "opencode 淺色標誌", + "temp.logoDarkAlt": "opencode 深色標誌", "home.banner.badge": "新", "home.banner.text": "桌面應用已推出 Beta", @@ -229,11 +238,122 @@ export const dict = { "zen.privacy.beforeExceptions": "所有 Zen 模型均在美國託管。供應商遵循零留存政策,不會將你的資料用於模型訓練,並且有", "zen.privacy.exceptionsLink": "以下例外情況", + "go.title": "OpenCode Go | 低成本全民編碼模型", + "go.meta.description": + "Go 是一個每月 $10 的訂閱方案,提供對 GLM-5、Kimi K2.5 與 MiniMax M2.5 的 5 小時寬裕使用限額。", + "go.hero.title": "低成本全民編碼模型", + "go.hero.body": + "Go 將代理編碼帶給全世界的程式設計師。提供寬裕的限額以及對最強大開源模型的穩定存取,讓你可以使用強大的代理進行構建,而無需擔心成本或可用性。", + + "go.cta.start": "訂閱 Go", + "go.cta.template": "{{text}} {{price}}", + "go.cta.text": "訂閱 Go", + "go.cta.price": "$10/月", + "go.pricing.body": "可與任何代理一起使用。需要時可儲值額度。隨時取消。", + "go.graph.free": "免費", + "go.graph.freePill": "Big Pickle 與免費模型", + "go.graph.go": "Go", + "go.graph.label": "每 5 小時請求數", + "go.graph.usageLimits": "使用限制", + "go.graph.tick": "{{n}}x", + "go.graph.aria": "每 5 小時請求數:{{free}} vs {{go}}", + + "go.testimonials.brand.zen": "Zen", + "go.testimonials.brand.go": "Go", + "go.testimonials.handle": "@OpenCode", + "go.testimonials.dax.name": "Dax Raad", + "go.testimonials.dax.title": "前 Terminal Products CEO", + "go.testimonials.dax.quoteAfter": "改變了我的生活,這絕對是不二之選。", + "go.testimonials.jay.name": "Jay V", + "go.testimonials.jay.title": "前 SEED、Melt、Pop、Dapt、Cadmus 與 ViewPoint 創辦人", + "go.testimonials.jay.quoteBefore": "我們團隊中 5 個人有 4 個人喜歡使用", + "go.testimonials.jay.quoteAfter": "。", + "go.testimonials.adam.name": "Adam Elmore", + "go.testimonials.adam.title": "前 AWS Hero", + "go.testimonials.adam.quoteBefore": "我強烈推薦", + "go.testimonials.adam.quoteAfter": "。認真說,真的很好用。", + "go.testimonials.david.name": "David Hill", + "go.testimonials.david.title": "前 Laravel 設計總監", + "go.testimonials.david.quoteBefore": "有了", + "go.testimonials.david.quoteAfter": ",我知道所有模型都經過測試並且完美適用於編碼代理。", + "go.testimonials.frank.name": "Frank Wang", + "go.testimonials.frank.title": "前 Nvidia 實習生(4 次)", + "go.testimonials.frank.quote": "我希望我還在 Nvidia。", + "go.problem.title": "Go 正在解決什麼問題?", + "go.problem.body": + "我們致力於將 OpenCode 體驗帶給盡可能多的人。OpenCode Go 是一個低成本(每月 $10)的訂閱方案,旨在將代理編碼帶給全世界的程式設計師。它提供寬裕的限額以及對最強大開源模型的穩定存取。", + "go.problem.subtitle": " ", + "go.problem.item1": "低成本訂閱定價", + "go.problem.item2": "寬裕的限額與穩定存取", + "go.problem.item3": "專為盡可能多的程式設計師打造", + "go.problem.item4": "包含 GLM-5、Kimi K2.5 與 MiniMax M2.5", + "go.how.title": "Go 如何運作", + "go.how.body": "Go 是一個每月 $10 的訂閱方案,你可以將其與 OpenCode 或任何代理一起使用。", + "go.how.step1.title": "建立帳號", + "go.how.step1.beforeLink": "遵循", + "go.how.step1.link": "設定說明", + "go.how.step2.title": "訂閱 Go", + "go.how.step2.link": "$10/月", + "go.how.step2.afterLink": "享寬裕限額", + "go.how.step3.title": "開始編碼", + "go.how.step3.body": "穩定存取開源模型", + "go.privacy.title": "你的隱私對我們很重要", + "go.privacy.body": "該方案主要面向國際用戶設計,模型託管在美國、歐盟和新加坡,以確保全球穩定存取。", + "go.privacy.contactAfter": "如果你有任何問題。", + "go.privacy.beforeExceptions": "Go 模型託管在美國。供應商遵循零留存政策,不會將你的資料用於模型訓練,但有", + "go.privacy.exceptionsLink": "以下例外", + "go.faq.q1": "什麼是 OpenCode Go?", + "go.faq.a1": "Go 是一個低成本訂閱方案,讓你穩定存取強大的開源模型以進行代理編碼。", + "go.faq.q2": "Go 包含哪些模型?", + "go.faq.a2": "Go 包含 GLM-5、Kimi K2.5 與 MiniMax M2.5,並提供寬裕的限額與穩定存取。", + "go.faq.q3": "Go 與 Zen 一樣嗎?", + "go.faq.a3": + "不一樣。Zen 是按量付費,而 Go 是每月 $10 的訂閱方案,提供對開源模型 GLM-5、Kimi K2.5 與 MiniMax M2.5 的寬裕限額與穩定存取。", + "go.faq.q4": "Go 費用是多少?", + "go.faq.a4.p1.beforePricing": "Go 費用為", + "go.faq.a4.p1.pricingLink": "$10/月", + "go.faq.a4.p1.afterPricing": "享寬裕限額。", + "go.faq.a4.p2.beforeAccount": "你可以在你的", + "go.faq.a4.p2.accountLink": "帳戶", + "go.faq.a4.p3": "中管理訂閱。隨時取消。", + "go.faq.q5": "資料與隱私怎麼辦?", + "go.faq.a5.body": "該方案主要面向國際用戶設計,模型託管在美國、歐盟和新加坡,以確保全球穩定存取。", + "go.faq.a5.contactAfter": "如果你有任何問題。", + "go.faq.a5.beforeExceptions": "Go 模型託管在美國。供應商遵循零留存政策,不會將你的資料用於模型訓練,但有", + "go.faq.a5.exceptionsLink": "以下例外", + "go.faq.q6": "我可以儲值額度嗎?", + "go.faq.a6": "如果你需要更多使用量,可以在帳戶中儲值額度。", + "go.faq.q7": "我可以取消嗎?", + "go.faq.a7": "可以,你可以隨時取消。", + "go.faq.q8": "我可以在其他編碼代理中使用 Go 嗎?", + "go.faq.a8": "可以,你可以將 Go 與任何代理一起使用。請在你偏好的編碼代理中按照設定說明進行配置。", + + "go.faq.q9": "免費模型與 Go 有什麼區別?", + "go.faq.a9": + "免費模型包括 Big Pickle 以及當時可用的促銷模型,配額為 200 次請求/天。Go 包括 GLM-5、Kimi K2.5 與 MiniMax M2.5,並在滾動視窗(5 小時、每週和每月)內執行更高的請求配額,大約相當於每 5 小時 $12、每週 $30 和每月 $60(實際請求數因模型和使用情況而異)。", + + "zen.api.error.rateLimitExceeded": "超出頻率限制。請稍後再試。", + "zen.api.error.modelNotSupported": "不支援模型 {{model}}", + "zen.api.error.modelFormatNotSupported": "模型 {{model}} 不支援格式 {{format}}", + "zen.api.error.noProviderAvailable": "無可用的供應商", + "zen.api.error.providerNotSupported": "不支援供應商 {{provider}}", + "zen.api.error.missingApiKey": "缺少 API 金鑰。", + "zen.api.error.invalidApiKey": "無效的 API 金鑰。", + "zen.api.error.subscriptionQuotaExceeded": "超出訂閱配額。請在 {{retryIn}} 後重試。", + "zen.api.error.subscriptionQuotaExceededUseFreeModels": "超出訂閱配額。你可以繼續使用免費模型。", + "zen.api.error.noPaymentMethod": "無付款方式。請在此處新增付款方式:{{billingUrl}}", + "zen.api.error.insufficientBalance": "餘額不足。請在此處管理你的帳務:{{billingUrl}}", + "zen.api.error.workspaceMonthlyLimitReached": + "你的工作區已達到每月支出限額 ${{amount}}。請在此處管理你的限額:{{billingUrl}}", + "zen.api.error.userMonthlyLimitReached": "你已達到每月支出限額 ${{amount}}。請在此處管理你的限額:{{membersUrl}}", + "zen.api.error.modelDisabled": "模型已停用", + "black.meta.title": "OpenCode Black | 存取全球最佳編碼模型", "black.meta.description": "透過 OpenCode Black 訂閱方案存取 Claude、GPT、Gemini 等模型。", "black.hero.title": "存取全球最佳編碼模型", "black.hero.subtitle": "包括 Claude、GPT、Gemini 等", "black.title": "OpenCode Black | 定價", + "black.paused": "Black 訂閱暫時暫停註冊。", "black.plan.icon20": "Black 20 方案", "black.plan.icon100": "Black 100 方案", "black.plan.icon200": "Black 200 方案", @@ -327,12 +447,15 @@ export const dict = { "workspace.usage.table.input": "輸入", "workspace.usage.table.output": "輸出", "workspace.usage.table.cost": "成本", + "workspace.usage.table.session": "會話", "workspace.usage.breakdown.input": "輸入", "workspace.usage.breakdown.cacheRead": "快取讀取", "workspace.usage.breakdown.cacheWrite": "快取寫入", "workspace.usage.breakdown.output": "輸出", "workspace.usage.breakdown.reasoning": "推理", - "workspace.usage.subscription": "訂閱 (${{amount}})", + "workspace.usage.subscription": "Black (${{amount}})", + "workspace.usage.lite": "Go (${{amount}})", + "workspace.usage.byok": "BYOK (${{amount}})", "workspace.cost.title": "成本", "workspace.cost.subtitle": "按模型細分的使用成本。", @@ -431,6 +554,7 @@ export const dict = { "workspace.reload.updatePaymentMethod": "請更新你的付款方式並重試。", "workspace.reload.retrying": "重試中...", "workspace.reload.retry": "重試", + "workspace.reload.error.paymentFailed": "付款失敗。", "workspace.payments.title": "付款紀錄", "workspace.payments.subtitle": "最近的付款交易。", @@ -468,6 +592,35 @@ export const dict = { "workspace.black.waitlist.enrolled": "已加入", "workspace.black.waitlist.enrollNote": "當你點選「加入」後,你的訂閱將立即開始,並且將從你的卡片中扣款。", + "workspace.lite.loading": "載入中...", + "workspace.lite.time.day": "天", + "workspace.lite.time.days": "天", + "workspace.lite.time.hour": "小時", + "workspace.lite.time.hours": "小時", + "workspace.lite.time.minute": "分鐘", + "workspace.lite.time.minutes": "分鐘", + "workspace.lite.time.fewSeconds": "幾秒", + "workspace.lite.subscription.title": "Go 訂閱", + "workspace.lite.subscription.message": "您已訂閱 OpenCode Go。", + "workspace.lite.subscription.manage": "管理訂閱", + "workspace.lite.subscription.rollingUsage": "滾動使用量", + "workspace.lite.subscription.weeklyUsage": "每週使用量", + "workspace.lite.subscription.monthlyUsage": "每月使用量", + "workspace.lite.subscription.resetsIn": "重置時間:", + "workspace.lite.subscription.useBalance": "達到使用限制後使用您的可用餘額", + "workspace.lite.subscription.selectProvider": + "在您的 opencode 設定中選擇「OpenCode Go」作為提供商,即可使用 Go 模型。", + "workspace.lite.other.title": "Go 訂閱", + "workspace.lite.other.message": "此工作區中的另一位成員已訂閱 OpenCode Go。每個工作區只能有一位成員訂閱。", + "workspace.lite.promo.title": "OpenCode Go", + "workspace.lite.promo.description": + "OpenCode Go 是一個每月 $10 的訂閱方案,提供對主流開放原始碼編碼模型的穩定存取,並配備充足的使用額度。", + "workspace.lite.promo.modelsTitle": "包含模型", + "workspace.lite.promo.footer": + "該計畫主要面向國際用戶設計,模型部署在美國、歐盟和新加坡,以確保全球範圍內的穩定存取體驗。定價和使用額度可能會根據早期用戶的使用情況和回饋持續調整與優化。", + "workspace.lite.promo.subscribe": "訂閱 Go", + "workspace.lite.promo.subscribing": "重新導向中...", + "download.title": "OpenCode | 下載", "download.meta.description": "下載適用於 macOS、Windows 與 Linux 的 OpenCode", "download.hero.title": "下載 OpenCode", @@ -517,6 +670,10 @@ export const dict = { "enterprise.form.send": "傳送", "enterprise.form.sending": "傳送中...", "enterprise.form.success": "訊息已傳送,我們會盡快與你聯絡。", + "enterprise.form.success.submitted": "表單已成功送出。", + "enterprise.form.error.allFieldsRequired": "所有欄位均為必填。", + "enterprise.form.error.invalidEmailFormat": "無效的電子郵件格式。", + "enterprise.form.error.internalServer": "內部伺服器錯誤。", "enterprise.faq.title": "常見問題", "enterprise.faq.q1": "什麼是 OpenCode Enterprise?", "enterprise.faq.a1": @@ -549,6 +706,7 @@ export const dict = { "bench.list.table.agent": "代理", "bench.list.table.model": "模型", "bench.list.table.score": "分數", + "bench.submission.error.allFieldsRequired": "所有欄位均為必填。", "bench.detail.title": "評測 - {{task}}", "bench.detail.notFound": "找不到任務", diff --git a/packages/console/app/src/lib/form-error.ts b/packages/console/app/src/lib/form-error.ts index 1f6e2ea1e6..d643a98f14 100644 --- a/packages/console/app/src/lib/form-error.ts +++ b/packages/console/app/src/lib/form-error.ts @@ -48,6 +48,9 @@ const map = { "Provider is required": "error.providerRequired", "API key is required": "error.apiKeyRequired", "Model is required": "error.modelRequired", + "workspace.reload.error.paymentFailed": "workspace.reload.error.paymentFailed", + "Payment failed": "workspace.reload.error.paymentFailed", + "Payment failed.": "workspace.reload.error.paymentFailed", } as const satisfies Record export function formErrorReloadAmountMin(amount: number) { diff --git a/packages/console/app/src/lib/language.ts b/packages/console/app/src/lib/language.ts index 54321d2343..5e80179e47 100644 --- a/packages/console/app/src/lib/language.ts +++ b/packages/console/app/src/lib/language.ts @@ -108,6 +108,26 @@ const DOCS_SEGMENT = new Set([ "zh-tw", ]) +const DOCS_LOCALE = { + ar: "ar", + da: "da", + de: "de", + en: "en", + es: "es", + fr: "fr", + it: "it", + ja: "ja", + ko: "ko", + nb: "no", + "pt-br": "br", + root: "en", + ru: "ru", + th: "th", + tr: "tr", + "zh-cn": "zh", + "zh-tw": "zht", +} as const satisfies Record + function suffix(pathname: string) { const index = pathname.search(/[?#]/) if (index === -1) { @@ -130,7 +150,12 @@ export function docs(locale: Locale, pathname: string) { return `${next.path}${next.suffix}` } - if (value === "root") return `${next.path}${next.suffix}` + if (value === "root") { + if (next.path === "/docs/en") return `/docs${next.suffix}` + if (next.path === "/docs/en/") return `/docs/${next.suffix}` + if (next.path.startsWith("/docs/en/")) return `/docs/${next.path.slice("/docs/en/".length)}${next.suffix}` + return `${next.path}${next.suffix}` + } if (next.path === "/docs") return `/docs/${value}${next.suffix}` if (next.path === "/docs/") return `/docs/${value}/${next.suffix}` @@ -154,6 +179,15 @@ export function fromPathname(pathname: string) { return parseLocale(fix(pathname).split("/")[1]) } +export function fromDocsPathname(pathname: string) { + const next = fix(pathname) + const value = next.split("/")[2]?.toLowerCase() + if (!value) return null + if (!next.startsWith("/docs/")) return null + if (!(value in DOCS_LOCALE)) return null + return DOCS_LOCALE[value as keyof typeof DOCS_LOCALE] +} + export function strip(pathname: string) { const locale = fromPathname(pathname) if (!locale) return fix(pathname) @@ -272,6 +306,9 @@ export function localeFromRequest(request: Request) { const fromPath = fromPathname(new URL(request.url).pathname) if (fromPath) return fromPath + const fromDocsPath = fromDocsPathname(new URL(request.url).pathname) + if (fromDocsPath) return fromDocsPath + return ( localeFromCookieHeader(request.headers.get("cookie")) ?? detectFromAcceptLanguage(request.headers.get("accept-language")) diff --git a/packages/console/app/src/routes/[...404].tsx b/packages/console/app/src/routes/[...404].tsx index 414491f9d1..e20ec36fd6 100644 --- a/packages/console/app/src/routes/[...404].tsx +++ b/packages/console/app/src/routes/[...404].tsx @@ -16,8 +16,8 @@ export default function NotFound() {
    - opencode logo light - opencode logo dark + {i18n.t("notFound.logoLightAlt")} + {i18n.t("notFound.logoDarkAlt")}

    {i18n.t("notFound.heading")}

    diff --git a/packages/console/app/src/routes/api/enterprise.ts b/packages/console/app/src/routes/api/enterprise.ts index 6776a7b3c7..27e2dc4938 100644 --- a/packages/console/app/src/routes/api/enterprise.ts +++ b/packages/console/app/src/routes/api/enterprise.ts @@ -1,5 +1,7 @@ import type { APIEvent } from "@solidjs/start/server" import { AWS } from "@opencode-ai/console-core/aws.js" +import { i18n } from "~/i18n" +import { localeFromRequest } from "~/lib/language" interface EnterpriseFormData { name: string @@ -9,18 +11,19 @@ interface EnterpriseFormData { } export async function POST(event: APIEvent) { + const dict = i18n(localeFromRequest(event.request)) try { const body = (await event.request.json()) as EnterpriseFormData // Validate required fields if (!body.name || !body.role || !body.email || !body.message) { - return Response.json({ error: "All fields are required" }, { status: 400 }) + return Response.json({ error: dict["enterprise.form.error.allFieldsRequired"] }, { status: 400 }) } // Validate email format const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/ if (!emailRegex.test(body.email)) { - return Response.json({ error: "Invalid email format" }, { status: 400 }) + return Response.json({ error: dict["enterprise.form.error.invalidEmailFormat"] }, { status: 400 }) } // Create email content @@ -39,9 +42,9 @@ ${body.email}`.trim() replyTo: body.email, }) - return Response.json({ success: true, message: "Form submitted successfully" }, { status: 200 }) + return Response.json({ success: true, message: dict["enterprise.form.success.submitted"] }, { status: 200 }) } catch (error) { console.error("Error processing enterprise form:", error) - return Response.json({ error: "Internal server error" }, { status: 500 }) + return Response.json({ error: dict["enterprise.form.error.internalServer"] }, { status: 500 }) } } diff --git a/packages/console/app/src/routes/auth/[...callback].ts b/packages/console/app/src/routes/auth/[...callback].ts index 664f6cc6d1..00bb89406f 100644 --- a/packages/console/app/src/routes/auth/[...callback].ts +++ b/packages/console/app/src/routes/auth/[...callback].ts @@ -2,15 +2,17 @@ import { redirect } from "@solidjs/router" import type { APIEvent } from "@solidjs/start/server" import { AuthClient } from "~/context/auth" import { useAuthSession } from "~/context/auth" +import { i18n } from "~/i18n" import { localeFromRequest, route } from "~/lib/language" export async function GET(input: APIEvent) { const url = new URL(input.request.url) const locale = localeFromRequest(input.request) + const dict = i18n(locale) try { const code = url.searchParams.get("code") - if (!code) throw new Error("No code found") + if (!code) throw new Error(dict["auth.callback.error.codeMissing"]) const result = await AuthClient.exchange(code, `${url.origin}${url.pathname}`) if (result.err) throw new Error(result.err.message) const decoded = AuthClient.decode(result.tokens.access, {} as any) diff --git a/packages/console/app/src/routes/bench/submission.ts b/packages/console/app/src/routes/bench/submission.ts index 94639439b1..969ff16593 100644 --- a/packages/console/app/src/routes/bench/submission.ts +++ b/packages/console/app/src/routes/bench/submission.ts @@ -2,6 +2,8 @@ import type { APIEvent } from "@solidjs/start/server" import { Database } from "@opencode-ai/console-core/drizzle/index.js" import { BenchmarkTable } from "@opencode-ai/console-core/schema/benchmark.sql.js" import { Identifier } from "@opencode-ai/console-core/identifier.js" +import { i18n } from "~/i18n" +import { localeFromRequest } from "~/lib/language" interface SubmissionBody { model: string @@ -10,10 +12,11 @@ interface SubmissionBody { } export async function POST(event: APIEvent) { + const dict = i18n(localeFromRequest(event.request)) const body = (await event.request.json()) as SubmissionBody if (!body.model || !body.agent || !body.result) { - return Response.json({ error: "All fields are required" }, { status: 400 }) + return Response.json({ error: dict["bench.submission.error.allFieldsRequired"] }, { status: 400 }) } await Database.use((tx) => diff --git a/packages/console/app/src/routes/black.css b/packages/console/app/src/routes/black.css index 66bffea599..4031a78fc3 100644 --- a/packages/console/app/src/routes/black.css +++ b/packages/console/app/src/routes/black.css @@ -335,6 +335,19 @@ } } + [data-slot="paused"] { + flex: 1; + display: flex; + align-items: center; + justify-content: center; + color: rgba(255, 255, 255, 0.59); + font-size: 18px; + font-style: normal; + font-weight: 400; + line-height: 160%; + padding: 120px 20px; + } + [data-slot="pricing-card"] { display: flex; flex-direction: column; diff --git a/packages/console/app/src/routes/black/index.tsx b/packages/console/app/src/routes/black/index.tsx index 72b196f571..8bce3cd464 100644 --- a/packages/console/app/src/routes/black/index.tsx +++ b/packages/console/app/src/routes/black/index.tsx @@ -1,14 +1,21 @@ -import { A, useSearchParams } from "@solidjs/router" +import { A, createAsync, query, useSearchParams } from "@solidjs/router" import { Title } from "@solidjs/meta" import { createMemo, createSignal, For, Match, onMount, Show, Switch } from "solid-js" import { PlanIcon, plans } from "./common" import { useI18n } from "~/context/i18n" import { useLanguage } from "~/context/language" +import { Resource } from "@opencode-ai/console-resource" + +const getPaused = query(async () => { + "use server" + return Resource.App.stage === "production" +}, "black.paused") export default function Black() { const [params] = useSearchParams() const i18n = useI18n() const language = useLanguage() + const paused = createAsync(() => getPaused()) const [selected, setSelected] = createSignal((params.plan as string) || null) const [mounted, setMounted] = createSignal(false) const selectedPlan = createMemo(() => plans.find((p) => p.id === selected())) @@ -42,72 +49,76 @@ export default function Black() { <> {i18n.t("black.title")}
    - - -
    - - {(plan) => ( - + )} + +
    +
    + + {(plan) => ( +
    +
    - +

    - ${plan.id}{" "} - {i18n.t("black.price.perMonth")} - + ${plan().id}{" "} + {i18n.t("black.price.perPersonBilledMonthly")} + {(multiplier) => {i18n.t(multiplier())}}

    - - )} - -
    - - - {(plan) => ( -
    -
    -
    - -
    -

    - ${plan().id}{" "} - {i18n.t("black.price.perPersonBilledMonthly")} - - {(multiplier) => {i18n.t(multiplier())}} - -

    -
      -
    • {i18n.t("black.terms.1")}
    • -
    • {i18n.t("black.terms.2")}
    • -
    • {i18n.t("black.terms.3")}
    • -
    • {i18n.t("black.terms.4")}
    • -
    • {i18n.t("black.terms.5")}
    • -
    • {i18n.t("black.terms.6")}
    • -
    • {i18n.t("black.terms.7")}
    • -
    -
    - - - {i18n.t("black.action.continue")} - +
      +
    • {i18n.t("black.terms.1")}
    • +
    • {i18n.t("black.terms.2")}
    • +
    • {i18n.t("black.terms.3")}
    • +
    • {i18n.t("black.terms.4")}
    • +
    • {i18n.t("black.terms.5")}
    • +
    • {i18n.t("black.terms.6")}
    • +
    • {i18n.t("black.terms.7")}
    • +
    +
    + + + {i18n.t("black.action.continue")} + +
    -
    - )} -
    - -

    - {i18n.t("black.finePrint.beforeTerms")} ·{" "} - {i18n.t("black.finePrint.terms")} -

    + )} + + + + +

    + {i18n.t("black.finePrint.beforeTerms")} ·{" "} + {i18n.t("black.finePrint.terms")} +

    +
    ) diff --git a/packages/console/app/src/routes/black/subscribe/[plan].tsx b/packages/console/app/src/routes/black/subscribe/[plan].tsx index 644d87d9b3..19b56eabe6 100644 --- a/packages/console/app/src/routes/black/subscribe/[plan].tsx +++ b/packages/console/app/src/routes/black/subscribe/[plan].tsx @@ -17,6 +17,12 @@ import { Billing } from "@opencode-ai/console-core/billing.js" import { useI18n } from "~/context/i18n" import { useLanguage } from "~/context/language" import { formError } from "~/lib/form-error" +import { Resource } from "@opencode-ai/console-resource" + +const getEnabled = query(async () => { + "use server" + return Resource.App.stage !== "production" +}, "black.subscribe.enabled") const plansMap = Object.fromEntries(plans.map((p) => [p.id, p])) as Record const stripePromise = loadStripe(import.meta.env.VITE_STRIPE_PUBLISHABLE_KEY!) @@ -269,6 +275,7 @@ export default function BlackSubscribe() { const params = useParams() const i18n = useI18n() const language = useLanguage() + const enabled = createAsync(() => getEnabled()) const planData = plansMap[(params.plan as PlanID) ?? "20"] ?? plansMap["20"] const plan = planData.id @@ -359,7 +366,7 @@ export default function BlackSubscribe() { } return ( - <> + {i18n.t("black.subscribe.title")}
    @@ -472,6 +479,6 @@ export default function BlackSubscribe() { {i18n.t("black.finePrint.terms")}

    - +
    ) } diff --git a/packages/console/app/src/routes/brand/index.css b/packages/console/app/src/routes/brand/index.css index 6fe7c9a8d5..8a32651591 100644 --- a/packages/console/app/src/routes/brand/index.css +++ b/packages/console/app/src/routes/brand/index.css @@ -86,10 +86,10 @@ display: flex; justify-content: space-between; align-items: center; - gap: 48px; + gap: 32px; @media (max-width: 55rem) { - gap: 32px; + gap: 24px; } @media (max-width: 48rem) { diff --git a/packages/console/app/src/routes/brand/index.tsx b/packages/console/app/src/routes/brand/index.tsx index 9140462c79..af89f49851 100644 --- a/packages/console/app/src/routes/brand/index.tsx +++ b/packages/console/app/src/routes/brand/index.tsx @@ -33,6 +33,7 @@ const brandAssets = "/opencode-brand-assets.zip" export default function Brand() { const i18n = useI18n() + const alt = i18n.t("brand.meta.description") const downloadFile = async (url: string, filename: string) => { try { const response = await fetch(url) @@ -88,7 +89,7 @@ export default function Brand() {
    - OpenCode brand guidelines + {alt}
    - OpenCode brand guidelines + {alt}
    - OpenCode brand guidelines + {alt}
    - OpenCode brand guidelines + {alt}
    - OpenCode brand guidelines + {alt}
    - OpenCode brand guidelines + {alt}
    - OpenCode brand guidelines + {alt}
    - OpenCode brand guidelines + {alt}
  • Phone: +1 415 794-0209
  • +
  • Address: 2443 Fillmore St #380-6343, San Francisco, CA 94115, United States
  • diff --git a/packages/console/app/src/routes/legal/terms-of-service/index.tsx b/packages/console/app/src/routes/legal/terms-of-service/index.tsx index f770aa7a06..55a9fd42f1 100644 --- a/packages/console/app/src/routes/legal/terms-of-service/index.tsx +++ b/packages/console/app/src/routes/legal/terms-of-service/index.tsx @@ -21,12 +21,12 @@ export default function TermsOfService() {

    Terms of Use

    -

    Effective date: Dec 16, 2025

    +

    Effective date: Mar 6, 2026

    - Welcome to OpenCode. Please read on to learn the rules and restrictions that govern your use of OpenCode - (the "Services"). If you have any questions, comments, or concerns regarding these terms or the - Services, please contact us at: + Welcome to OpenCode. Please read on to learn the rules and restrictions that govern your use of + OpenCode's website, inference product and hosted software offering (the "Services"). If you have + any questions, comments, or concerns regarding these terms or the Services, please contact us at:

    @@ -44,7 +44,10 @@ export default function TermsOfService() { and/or conditions ("Additional Terms"), which are incorporated herein by reference, and you understand and agree that by using or participating in any such Services, you agree to also comply with these Additional Terms. - + {" "} + For clarity, our open source software that is not provided to you on a hosted basis is subject to the + open source license and terms set forth on the applicable repository where you access such open source + software, and such license and terms will exclusively govern your use of such open source software.

    @@ -460,10 +463,10 @@ export default function TermsOfService() {

    Opt-out

    You have the right to opt out of the provisions of this Section by sending written notice of your - decision to opt out to the following address: [ADDRESS], [CITY], Canada [ZIP CODE] postmarked within - thirty (30) days of first accepting these Terms. You must include (i) your name and residence address, - (ii) the email address and/or telephone number associated with your account, and (iii) a clear statement - that you want to opt out of these Terms' arbitration agreement. + decision to opt out to the following address: 2443 Fillmore St #380-6343, San Francisco, CA 94115, + United States postmarked within thirty (30) days of first accepting these Terms. You must include (i) + your name and residence address, (ii) the email address and/or telephone number associated with your + account, and (iii) a clear statement that you want to opt out of these Terms' arbitration agreement.

    Exclusive Venue

    diff --git a/packages/console/app/src/routes/s/[id].ts b/packages/console/app/src/routes/s/[id].ts index 60f8d8ba87..374fd79ad0 100644 --- a/packages/console/app/src/routes/s/[id].ts +++ b/packages/console/app/src/routes/s/[id].ts @@ -1,6 +1,6 @@ import type { APIEvent } from "@solidjs/start/server" import { Resource } from "@opencode-ai/console-resource" -import { docs, localeFromRequest, tag } from "~/lib/language" +import { cookie, docs, localeFromRequest, tag } from "~/lib/language" async function handler(evt: APIEvent) { const req = evt.request.clone() @@ -17,7 +17,9 @@ async function handler(evt: APIEvent) { headers, body: req.body, }) - return response + const next = new Response(response.body, response) + next.headers.append("set-cookie", cookie(locale)) + return next } export const GET = handler diff --git a/packages/console/app/src/routes/stripe/webhook.ts b/packages/console/app/src/routes/stripe/webhook.ts index 828eb4c711..95cd9da21b 100644 --- a/packages/console/app/src/routes/stripe/webhook.ts +++ b/packages/console/app/src/routes/stripe/webhook.ts @@ -1,13 +1,13 @@ import { Billing } from "@opencode-ai/console-core/billing.js" import type { APIEvent } from "@solidjs/start/server" -import { and, Database, eq, isNull, sql } from "@opencode-ai/console-core/drizzle/index.js" -import { BillingTable, PaymentTable, SubscriptionTable } from "@opencode-ai/console-core/schema/billing.sql.js" +import { and, Database, eq, sql } from "@opencode-ai/console-core/drizzle/index.js" +import { BillingTable, LiteTable, PaymentTable } from "@opencode-ai/console-core/schema/billing.sql.js" import { Identifier } from "@opencode-ai/console-core/identifier.js" import { centsToMicroCents } from "@opencode-ai/console-core/util/price.js" import { Actor } from "@opencode-ai/console-core/actor.js" import { Resource } from "@opencode-ai/console-resource" -import { UserTable } from "@opencode-ai/console-core/schema/user.sql.js" -import { AuthTable } from "@opencode-ai/console-core/schema/auth.sql.js" +import { LiteData } from "@opencode-ai/console-core/lite.js" +import { BlackData } from "@opencode-ai/console-core/black.js" export async function POST(input: APIEvent) { const body = await Billing.stripe().webhooks.constructEventAsync( @@ -103,310 +103,93 @@ export async function POST(input: APIEvent) { }) }) } - if (body.type === "checkout.session.completed" && body.data.object.mode === "subscription") { - const workspaceID = body.data.object.custom_fields.find((f) => f.key === "workspaceid")?.text?.value - const amountInCents = body.data.object.amount_total as number - const customerID = body.data.object.customer as string - const customerEmail = body.data.object.customer_details?.email as string - const invoiceID = body.data.object.invoice as string - const subscriptionID = body.data.object.subscription as string - const promoCode = body.data.object.discounts?.[0]?.promotion_code as string + if (body.type === "customer.subscription.created") { + const type = body.data.object.metadata?.type + if (type === "lite") { + const workspaceID = body.data.object.metadata?.workspaceID + const userID = body.data.object.metadata?.userID + const customerID = body.data.object.customer as string + const invoiceID = body.data.object.latest_invoice as string + const subscriptionID = body.data.object.id as string - if (!workspaceID) throw new Error("Workspace ID not found") - if (!customerID) throw new Error("Customer ID not found") - if (!amountInCents) throw new Error("Amount not found") - if (!invoiceID) throw new Error("Invoice ID not found") - if (!subscriptionID) throw new Error("Subscription ID not found") + if (!workspaceID) throw new Error("Workspace ID not found") + if (!userID) throw new Error("User ID not found") + if (!customerID) throw new Error("Customer ID not found") + if (!invoiceID) throw new Error("Invoice ID not found") + if (!subscriptionID) throw new Error("Subscription ID not found") - // get payment id from invoice - const invoice = await Billing.stripe().invoices.retrieve(invoiceID, { - expand: ["payments"], - }) - const paymentID = invoice.payments?.data[0].payment.payment_intent as string - if (!paymentID) throw new Error("Payment ID not found") + // get payment id from invoice + const invoice = await Billing.stripe().invoices.retrieve(invoiceID, { + expand: ["payments"], + }) + const paymentID = invoice.payments?.data[0].payment.payment_intent as string + if (!paymentID) throw new Error("Payment ID not found") - // get payment method for the payment intent - const paymentIntent = await Billing.stripe().paymentIntents.retrieve(paymentID, { - expand: ["payment_method"], - }) - const paymentMethod = paymentIntent.payment_method - if (!paymentMethod || typeof paymentMethod === "string") throw new Error("Payment method not expanded") + // get payment method for the payment intent + const paymentIntent = await Billing.stripe().paymentIntents.retrieve(paymentID, { + expand: ["payment_method"], + }) + const paymentMethod = paymentIntent.payment_method + if (!paymentMethod || typeof paymentMethod === "string") throw new Error("Payment method not expanded") - // get coupon id from promotion code - const couponID = await (async () => { - if (!promoCode) return - const coupon = await Billing.stripe().promotionCodes.retrieve(promoCode) - const couponID = coupon.coupon.id - if (!couponID) throw new Error("Coupon not found for promotion code") - return couponID - })() + await Actor.provide("system", { workspaceID }, async () => { + // look up current billing + const billing = await Billing.get() + if (!billing) throw new Error(`Workspace with ID ${workspaceID} not found`) + if (billing.customerID && billing.customerID !== customerID) throw new Error("Customer ID mismatch") - await Actor.provide("system", { workspaceID }, async () => { - // look up current billing - const billing = await Billing.get() - if (!billing) throw new Error(`Workspace with ID ${workspaceID} not found`) - - // Temporarily skip this check because during Black drop, user can checkout - // as a new customer - //if (billing.customerID !== customerID) throw new Error("Customer ID mismatch") - - // Temporarily check the user to apply to. After Black drop, we will allow - // look up the user to apply to - const users = await Database.use((tx) => - tx - .select({ id: UserTable.id, email: AuthTable.subject }) - .from(UserTable) - .innerJoin(AuthTable, and(eq(AuthTable.accountID, UserTable.accountID), eq(AuthTable.provider, "email"))) - .where(and(eq(UserTable.workspaceID, workspaceID), isNull(UserTable.timeDeleted))), - ) - const user = users.find((u) => u.email === customerEmail) ?? users[0] - if (!user) { - console.error(`Error: User with email ${customerEmail} not found in workspace ${workspaceID}`) - process.exit(1) - } - - // set customer metadata - if (!billing?.customerID) { - await Billing.stripe().customers.update(customerID, { - metadata: { - workspaceID, - }, - }) - } - - await Database.transaction(async (tx) => { - await tx - .update(BillingTable) - .set({ - customerID, - subscriptionID, - subscription: { - status: "subscribed", - coupon: couponID, - seats: 1, - plan: "200", + // set customer metadata + if (!billing?.customerID) { + await Billing.stripe().customers.update(customerID, { + metadata: { + workspaceID, }, - paymentMethodID: paymentMethod.id, - paymentMethodLast4: paymentMethod.card?.last4 ?? null, - paymentMethodType: paymentMethod.type, }) - .where(eq(BillingTable.workspaceID, workspaceID)) + } - await tx.insert(SubscriptionTable).values({ - workspaceID, - id: Identifier.create("subscription"), - userID: user.id, - }) + await Database.transaction(async (tx) => { + await tx + .update(BillingTable) + .set({ + customerID, + liteSubscriptionID: subscriptionID, + lite: {}, + paymentMethodID: paymentMethod.id, + paymentMethodLast4: paymentMethod.card?.last4 ?? null, + paymentMethodType: paymentMethod.type, + }) + .where(eq(BillingTable.workspaceID, workspaceID)) - await tx.insert(PaymentTable).values({ - workspaceID, - id: Identifier.create("payment"), - amount: centsToMicroCents(amountInCents), - paymentID, - invoiceID, - customerID, - enrichment: { - type: "subscription", - couponID, - }, + await tx.insert(LiteTable).values({ + workspaceID, + id: Identifier.create("lite"), + userID: userID, + }) }) }) - }) - } - if (body.type === "customer.subscription.created") { - /* -{ - id: "evt_1Smq802SrMQ2Fneksse5FMNV", - object: "event", - api_version: "2025-07-30.basil", - created: 1767766916, - data: { - object: { - id: "sub_1Smq7x2SrMQ2Fnek8F1yf3ZD", - object: "subscription", - application: null, - application_fee_percent: null, - automatic_tax: { - disabled_reason: null, - enabled: false, - liability: null, - }, - billing_cycle_anchor: 1770445200, - billing_cycle_anchor_config: null, - billing_mode: { - flexible: { - proration_discounts: "included", - }, - type: "flexible", - updated_at: 1770445200, - }, - billing_thresholds: null, - cancel_at: null, - cancel_at_period_end: false, - canceled_at: null, - cancellation_details: { - comment: null, - feedback: null, - reason: null, - }, - collection_method: "charge_automatically", - created: 1770445200, - currency: "usd", - customer: "cus_TkKmZZvysJ2wej", - customer_account: null, - days_until_due: null, - default_payment_method: null, - default_source: "card_1Smq7u2SrMQ2FneknjyOa7sq", - default_tax_rates: [], - description: null, - discounts: [], - ended_at: null, - invoice_settings: { - account_tax_ids: null, - issuer: { - type: "self", - }, - }, - items: { - object: "list", - data: [ - { - id: "si_TkKnBKXFX76t0O", - object: "subscription_item", - billing_thresholds: null, - created: 1770445200, - current_period_end: 1772864400, - current_period_start: 1770445200, - discounts: [], - metadata: {}, - plan: { - id: "price_1SmfFG2SrMQ2FnekJuzwHMea", - object: "plan", - active: true, - amount: 20000, - amount_decimal: "20000", - billing_scheme: "per_unit", - created: 1767725082, - currency: "usd", - interval: "month", - interval_count: 1, - livemode: false, - metadata: {}, - meter: null, - nickname: null, - product: "prod_Tk9LjWT1n0DgYm", - tiers_mode: null, - transform_usage: null, - trial_period_days: null, - usage_type: "licensed", - }, - price: { - id: "price_1SmfFG2SrMQ2FnekJuzwHMea", - object: "price", - active: true, - billing_scheme: "per_unit", - created: 1767725082, - currency: "usd", - custom_unit_amount: null, - livemode: false, - lookup_key: null, - metadata: {}, - nickname: null, - product: "prod_Tk9LjWT1n0DgYm", - recurring: { - interval: "month", - interval_count: 1, - meter: null, - trial_period_days: null, - usage_type: "licensed", - }, - tax_behavior: "unspecified", - tiers_mode: null, - transform_quantity: null, - type: "recurring", - unit_amount: 20000, - unit_amount_decimal: "20000", - }, - quantity: 1, - subscription: "sub_1Smq7x2SrMQ2Fnek8F1yf3ZD", - tax_rates: [], - }, - ], - has_more: false, - total_count: 1, - url: "/v1/subscription_items?subscription=sub_1Smq7x2SrMQ2Fnek8F1yf3ZD", - }, - latest_invoice: "in_1Smq7x2SrMQ2FnekSJesfPwE", - livemode: false, - metadata: {}, - next_pending_invoice_item_invoice: null, - on_behalf_of: null, - pause_collection: null, - payment_settings: { - payment_method_options: null, - payment_method_types: null, - save_default_payment_method: "off", - }, - pending_invoice_item_interval: null, - pending_setup_intent: null, - pending_update: null, - plan: { - id: "price_1SmfFG2SrMQ2FnekJuzwHMea", - object: "plan", - active: true, - amount: 20000, - amount_decimal: "20000", - billing_scheme: "per_unit", - created: 1767725082, - currency: "usd", - interval: "month", - interval_count: 1, - livemode: false, - metadata: {}, - meter: null, - nickname: null, - product: "prod_Tk9LjWT1n0DgYm", - tiers_mode: null, - transform_usage: null, - trial_period_days: null, - usage_type: "licensed", - }, - quantity: 1, - schedule: null, - start_date: 1770445200, - status: "active", - test_clock: "clock_1Smq6n2SrMQ2FnekQw4yt2PZ", - transfer_data: null, - trial_end: null, - trial_settings: { - end_behavior: { - missing_payment_method: "create_invoice", - }, - }, - trial_start: null, - }, - }, - livemode: false, - pending_webhooks: 0, - request: { - id: "req_6YO9stvB155WJD", - idempotency_key: "581ba059-6f86-49b2-9c49-0d8450255322", - }, - type: "customer.subscription.created", -} - */ + } } if (body.type === "customer.subscription.updated" && body.data.object.status === "incomplete_expired") { const subscriptionID = body.data.object.id if (!subscriptionID) throw new Error("Subscription ID not found") - await Billing.unsubscribe({ subscriptionID }) + const productID = body.data.object.items.data[0].price.product as string + if (productID === LiteData.productID()) { + await Billing.unsubscribeLite({ subscriptionID }) + } else if (productID === BlackData.productID()) { + await Billing.unsubscribeBlack({ subscriptionID }) + } } if (body.type === "customer.subscription.deleted") { const subscriptionID = body.data.object.id if (!subscriptionID) throw new Error("Subscription ID not found") - await Billing.unsubscribe({ subscriptionID }) + const productID = body.data.object.items.data[0].price.product as string + if (productID === LiteData.productID()) { + await Billing.unsubscribeLite({ subscriptionID }) + } else if (productID === BlackData.productID()) { + await Billing.unsubscribeBlack({ subscriptionID }) + } } if (body.type === "invoice.payment_succeeded") { if ( @@ -430,6 +213,7 @@ export async function POST(input: APIEvent) { typeof subscriptionData.discounts[0] === "string" ? subscriptionData.discounts[0] : subscriptionData.discounts[0]?.coupon?.id + const productID = subscriptionData.items.data[0].price.product as string // get payment id from invoice const invoice = await Billing.stripe().invoices.retrieve(invoiceID, { @@ -459,7 +243,7 @@ export async function POST(input: APIEvent) { invoiceID, customerID, enrichment: { - type: "subscription", + type: productID === LiteData.productID() ? "lite" : "subscription", couponID, }, }), @@ -522,7 +306,7 @@ export async function POST(input: APIEvent) { .update(BillingTable) .set({ reload: false, - reloadError: errorMessage ?? "Payment failed.", + reloadError: errorMessage ?? "workspace.reload.error.paymentFailed", timeReloadError: sql`now()`, }) .where(eq(BillingTable.workspaceID, Actor.workspace())), diff --git a/packages/console/app/src/routes/temp.tsx b/packages/console/app/src/routes/temp.tsx index ac506928eb..4eed47857a 100644 --- a/packages/console/app/src/routes/temp.tsx +++ b/packages/console/app/src/routes/temp.tsx @@ -47,8 +47,8 @@ export default function Home() {
    - opencode logo light - opencode logo dark + {i18n.t("temp.logoLightAlt")} + {i18n.t("temp.logoDarkAlt")}

    {i18n.t("temp.hero.title")}

    {i18n.t("temp.zen")} diff --git a/packages/console/app/src/routes/workspace/[id]/billing/black-section.tsx b/packages/console/app/src/routes/workspace/[id]/billing/black-section.tsx index ce0eb2c6a1..b8f089864d 100644 --- a/packages/console/app/src/routes/workspace/[id]/billing/black-section.tsx +++ b/packages/console/app/src/routes/workspace/[id]/billing/black-section.tsx @@ -5,7 +5,8 @@ import { Billing } from "@opencode-ai/console-core/billing.js" import { Database, eq, and, isNull, sql } from "@opencode-ai/console-core/drizzle/index.js" import { BillingTable, SubscriptionTable } from "@opencode-ai/console-core/schema/billing.sql.js" import { Actor } from "@opencode-ai/console-core/actor.js" -import { Black } from "@opencode-ai/console-core/black.js" +import { Subscription } from "@opencode-ai/console-core/subscription.js" +import { BlackData } from "@opencode-ai/console-core/black.js" import { withActor } from "~/context/auth.withActor" import { queryBillingInfo } from "../../common" import styles from "./black-section.module.css" @@ -31,17 +32,19 @@ const querySubscription = query(async (workspaceID: string) => { .then((r) => r[0]), ) if (!row?.subscription) return null + const blackData = BlackData.getLimits({ plan: row.subscription.plan }) return { plan: row.subscription.plan, useBalance: row.subscription.useBalance ?? false, - rollingUsage: Black.analyzeRollingUsage({ - plan: row.subscription.plan, + rollingUsage: Subscription.analyzeRollingUsage({ + limit: blackData.rollingLimit, + window: blackData.rollingWindow, usage: row.rollingUsage ?? 0, timeUpdated: row.timeRollingUpdated ?? new Date(), }), - weeklyUsage: Black.analyzeWeeklyUsage({ - plan: row.subscription.plan, + weeklyUsage: Subscription.analyzeWeeklyUsage({ + limit: blackData.fixedLimit, usage: row.fixedUsage ?? 0, timeUpdated: row.timeFixedUpdated ?? new Date(), }), @@ -87,7 +90,7 @@ const enroll = action(async (workspaceID: string) => { "use server" return json( await withActor(async () => { - await Billing.subscribe({ seats: 1 }) + await Billing.subscribeBlack({ seats: 1 }) return { error: undefined } }, workspaceID).catch((e) => ({ error: e.message as string })), { revalidate: [queryBillingInfo.key, querySubscription.key] }, diff --git a/packages/console/app/src/routes/workspace/[id]/billing/index.tsx b/packages/console/app/src/routes/workspace/[id]/billing/index.tsx index a252a02344..e039a09ef8 100644 --- a/packages/console/app/src/routes/workspace/[id]/billing/index.tsx +++ b/packages/console/app/src/routes/workspace/[id]/billing/index.tsx @@ -3,7 +3,8 @@ import { BillingSection } from "./billing-section" import { ReloadSection } from "./reload-section" import { PaymentSection } from "./payment-section" import { BlackSection } from "./black-section" -import { Show } from "solid-js" +import { LiteSection } from "./lite-section" +import { createMemo, Show } from "solid-js" import { createAsync, useParams } from "@solidjs/router" import { queryBillingInfo, querySessionInfo } from "../../common" @@ -11,14 +12,18 @@ export default function () { const params = useParams() const sessionInfo = createAsync(() => querySessionInfo(params.id!)) const billingInfo = createAsync(() => queryBillingInfo(params.id!)) + const isBlack = createMemo(() => billingInfo()?.subscriptionID || billingInfo()?.timeSubscriptionBooked) return (
    - + + + + diff --git a/packages/console/app/src/routes/workspace/[id]/billing/lite-section.module.css b/packages/console/app/src/routes/workspace/[id]/billing/lite-section.module.css new file mode 100644 index 0000000000..76d9bcfb09 --- /dev/null +++ b/packages/console/app/src/routes/workspace/[id]/billing/lite-section.module.css @@ -0,0 +1,190 @@ +.root { + [data-slot="title-row"] { + display: flex; + justify-content: space-between; + align-items: center; + gap: var(--space-4); + } + + [data-slot="usage"] { + display: flex; + gap: var(--space-6); + margin-top: var(--space-4); + + @media (max-width: 40rem) { + flex-direction: column; + gap: var(--space-4); + } + } + + [data-slot="usage-item"] { + flex: 1; + display: flex; + flex-direction: column; + gap: var(--space-2); + } + + [data-slot="usage-header"] { + display: flex; + justify-content: space-between; + align-items: baseline; + } + + [data-slot="usage-label"] { + font-size: var(--font-size-md); + font-weight: 500; + color: var(--color-text); + } + + [data-slot="usage-value"] { + font-size: var(--font-size-sm); + color: var(--color-text-muted); + } + + [data-slot="progress"] { + height: 8px; + background-color: var(--color-bg-surface); + border-radius: var(--border-radius-sm); + overflow: hidden; + } + + [data-slot="progress-bar"] { + height: 100%; + background-color: var(--color-accent); + border-radius: var(--border-radius-sm); + transition: width 0.3s ease; + } + + [data-slot="reset-time"] { + font-size: var(--font-size-sm); + color: var(--color-text-muted); + } + + [data-slot="setting-row"] { + display: flex; + align-items: center; + justify-content: space-between; + gap: var(--space-3); + margin-top: var(--space-4); + + p { + font-size: var(--font-size-sm); + line-height: 1.5; + color: var(--color-text-secondary); + margin: 0; + } + } + + [data-slot="toggle-label"] { + position: relative; + display: inline-block; + width: 2.5rem; + height: 1.5rem; + cursor: pointer; + flex-shrink: 0; + + input { + opacity: 0; + width: 0; + height: 0; + } + + span { + position: absolute; + inset: 0; + background-color: #ccc; + border: 1px solid #bbb; + border-radius: 1.5rem; + transition: all 0.3s ease; + cursor: pointer; + + &::before { + content: ""; + position: absolute; + top: 50%; + left: 0.125rem; + width: 1.25rem; + height: 1.25rem; + background-color: white; + border: 1px solid #ddd; + border-radius: 50%; + transform: translateY(-50%); + transition: all 0.3s ease; + } + } + + input:checked + span { + background-color: #21ad0e; + border-color: #148605; + + &::before { + transform: translateX(1rem) translateY(-50%); + } + } + + &:hover span { + box-shadow: 0 0 0 2px rgba(34, 197, 94, 0.2); + } + + input:checked:hover + span { + box-shadow: 0 0 0 2px rgba(34, 197, 94, 0.3); + } + + &:has(input:disabled) { + cursor: not-allowed; + } + + input:disabled + span { + opacity: 0.5; + cursor: not-allowed; + } + } + + [data-slot="beta-notice"] { + padding: var(--space-3) var(--space-4); + border: 1px solid var(--color-border); + border-radius: var(--border-radius-sm); + background-color: var(--color-bg-surface); + font-size: var(--font-size-sm); + color: var(--color-text-secondary); + line-height: 1.5; + margin-top: var(--space-3); + + a { + color: var(--color-accent); + text-decoration: none; + } + } + + [data-slot="other-message"] { + font-size: var(--font-size-sm); + color: var(--color-text-muted); + line-height: 1.5; + } + + [data-slot="promo-description"] { + font-size: var(--font-size-md); + color: var(--color-text-secondary); + line-height: 1.5; + margin-top: var(--space-2); + } + + [data-slot="promo-models-title"] { + font-size: var(--font-size-md); + font-weight: 600; + margin-top: var(--space-4); + } + + [data-slot="promo-models"] { + margin: var(--space-2) 0 0 var(--space-4); + padding: 0; + font-size: var(--font-size-md); + color: var(--color-text-secondary); + line-height: 1.4; + } + + [data-slot="subscribe-button"] { + align-self: flex-start; + margin-top: var(--space-4); + } +} diff --git a/packages/console/app/src/routes/workspace/[id]/billing/lite-section.tsx b/packages/console/app/src/routes/workspace/[id]/billing/lite-section.tsx new file mode 100644 index 0000000000..f67775d79c --- /dev/null +++ b/packages/console/app/src/routes/workspace/[id]/billing/lite-section.tsx @@ -0,0 +1,286 @@ +import { action, useParams, useAction, useSubmission, json, query, createAsync } from "@solidjs/router" +import { createStore } from "solid-js/store" +import { Show } from "solid-js" +import { Billing } from "@opencode-ai/console-core/billing.js" +import { Database, eq, and, isNull } from "@opencode-ai/console-core/drizzle/index.js" +import { BillingTable, LiteTable } from "@opencode-ai/console-core/schema/billing.sql.js" +import { Actor } from "@opencode-ai/console-core/actor.js" +import { Subscription } from "@opencode-ai/console-core/subscription.js" +import { LiteData } from "@opencode-ai/console-core/lite.js" +import { withActor } from "~/context/auth.withActor" +import { queryBillingInfo } from "../../common" +import styles from "./lite-section.module.css" +import { useI18n } from "~/context/i18n" +import { useLanguage } from "~/context/language" +import { formError } from "~/lib/form-error" + +const queryLiteSubscription = query(async (workspaceID: string) => { + "use server" + return withActor(async () => { + const row = await Database.use((tx) => + tx + .select({ + userID: LiteTable.userID, + rollingUsage: LiteTable.rollingUsage, + weeklyUsage: LiteTable.weeklyUsage, + monthlyUsage: LiteTable.monthlyUsage, + timeRollingUpdated: LiteTable.timeRollingUpdated, + timeWeeklyUpdated: LiteTable.timeWeeklyUpdated, + timeMonthlyUpdated: LiteTable.timeMonthlyUpdated, + timeCreated: LiteTable.timeCreated, + lite: BillingTable.lite, + }) + .from(BillingTable) + .innerJoin(LiteTable, eq(LiteTable.workspaceID, BillingTable.workspaceID)) + .where(and(eq(LiteTable.workspaceID, Actor.workspace()), isNull(LiteTable.timeDeleted))) + .then((r) => r[0]), + ) + if (!row) return null + + const limits = LiteData.getLimits() + const mine = row.userID === Actor.userID() + + return { + mine, + useBalance: row.lite?.useBalance ?? false, + rollingUsage: Subscription.analyzeRollingUsage({ + limit: limits.rollingLimit, + window: limits.rollingWindow, + usage: row.rollingUsage ?? 0, + timeUpdated: row.timeRollingUpdated ?? new Date(), + }), + weeklyUsage: Subscription.analyzeWeeklyUsage({ + limit: limits.weeklyLimit, + usage: row.weeklyUsage ?? 0, + timeUpdated: row.timeWeeklyUpdated ?? new Date(), + }), + monthlyUsage: Subscription.analyzeMonthlyUsage({ + limit: limits.monthlyLimit, + usage: row.monthlyUsage ?? 0, + timeUpdated: row.timeMonthlyUpdated ?? new Date(), + timeSubscribed: row.timeCreated, + }), + } + }, workspaceID) +}, "lite.subscription.get") + +function formatResetTime(seconds: number, i18n: ReturnType) { + const days = Math.floor(seconds / 86400) + if (days >= 1) { + const hours = Math.floor((seconds % 86400) / 3600) + return `${days} ${days === 1 ? i18n.t("workspace.lite.time.day") : i18n.t("workspace.lite.time.days")} ${hours} ${hours === 1 ? i18n.t("workspace.lite.time.hour") : i18n.t("workspace.lite.time.hours")}` + } + const hours = Math.floor(seconds / 3600) + const minutes = Math.floor((seconds % 3600) / 60) + if (hours >= 1) + return `${hours} ${hours === 1 ? i18n.t("workspace.lite.time.hour") : i18n.t("workspace.lite.time.hours")} ${minutes} ${minutes === 1 ? i18n.t("workspace.lite.time.minute") : i18n.t("workspace.lite.time.minutes")}` + if (minutes === 0) return i18n.t("workspace.lite.time.fewSeconds") + return `${minutes} ${minutes === 1 ? i18n.t("workspace.lite.time.minute") : i18n.t("workspace.lite.time.minutes")}` +} + +const createLiteCheckoutUrl = action(async (workspaceID: string, successUrl: string, cancelUrl: string) => { + "use server" + return json( + await withActor( + () => + Billing.generateLiteCheckoutUrl({ successUrl, cancelUrl }) + .then((data) => ({ error: undefined, data })) + .catch((e) => ({ + error: e.message as string, + data: undefined, + })), + workspaceID, + ), + { revalidate: [queryBillingInfo.key, queryLiteSubscription.key] }, + ) +}, "liteCheckoutUrl") + +const createSessionUrl = action(async (workspaceID: string, returnUrl: string) => { + "use server" + return json( + await withActor( + () => + Billing.generateSessionUrl({ returnUrl }) + .then((data) => ({ error: undefined, data })) + .catch((e) => ({ + error: e.message as string, + data: undefined, + })), + workspaceID, + ), + { revalidate: [queryBillingInfo.key, queryLiteSubscription.key] }, + ) +}, "liteSessionUrl") + +const setLiteUseBalance = action(async (form: FormData) => { + "use server" + const workspaceID = form.get("workspaceID")?.toString() + if (!workspaceID) return { error: formError.workspaceRequired } + const useBalance = form.get("useBalance")?.toString() === "true" + + return json( + await withActor(async () => { + await Database.use((tx) => + tx + .update(BillingTable) + .set({ + lite: useBalance ? { useBalance: true } : {}, + }) + .where(eq(BillingTable.workspaceID, workspaceID)), + ) + return { error: undefined } + }, workspaceID).catch((e) => ({ error: e.message as string })), + { revalidate: [queryBillingInfo.key, queryLiteSubscription.key] }, + ) +}, "setLiteUseBalance") + +export function LiteSection() { + const params = useParams() + const i18n = useI18n() + const language = useLanguage() + const lite = createAsync(() => queryLiteSubscription(params.id!)) + const sessionAction = useAction(createSessionUrl) + const sessionSubmission = useSubmission(createSessionUrl) + const checkoutAction = useAction(createLiteCheckoutUrl) + const checkoutSubmission = useSubmission(createLiteCheckoutUrl) + const useBalanceSubmission = useSubmission(setLiteUseBalance) + const [store, setStore] = createStore({ + redirecting: false, + }) + + async function onClickSession() { + const result = await sessionAction(params.id!, window.location.href) + if (result.data) { + setStore("redirecting", true) + window.location.href = result.data + } + } + + async function onClickSubscribe() { + const result = await checkoutAction(params.id!, window.location.href, window.location.href) + if (result.data) { + setStore("redirecting", true) + window.location.href = result.data + } + } + + return ( + <> + + {(sub) => ( +
    +
    +

    {i18n.t("workspace.lite.subscription.title")}

    +
    +

    {i18n.t("workspace.lite.subscription.message")}

    + +
    +
    +
    + {i18n.t("workspace.lite.subscription.selectProvider")}{" "} + + {i18n.t("common.learnMore")} + + . +
    +
    +
    +
    + {i18n.t("workspace.lite.subscription.rollingUsage")} + {sub().rollingUsage.usagePercent}% +
    +
    +
    +
    + + {i18n.t("workspace.lite.subscription.resetsIn")}{" "} + {formatResetTime(sub().rollingUsage.resetInSec, i18n)} + +
    +
    +
    + {i18n.t("workspace.lite.subscription.weeklyUsage")} + {sub().weeklyUsage.usagePercent}% +
    +
    +
    +
    + + {i18n.t("workspace.lite.subscription.resetsIn")} {formatResetTime(sub().weeklyUsage.resetInSec, i18n)} + +
    +
    +
    + {i18n.t("workspace.lite.subscription.monthlyUsage")} + {sub().monthlyUsage.usagePercent}% +
    +
    +
    +
    + + {i18n.t("workspace.lite.subscription.resetsIn")}{" "} + {formatResetTime(sub().monthlyUsage.resetInSec, i18n)} + +
    +
    +
    +

    {i18n.t("workspace.lite.subscription.useBalance")}

    + + + +
    +
    + )} +
    + +
    +
    +

    {i18n.t("workspace.lite.other.title")}

    +
    +

    {i18n.t("workspace.lite.other.message")}

    +
    +
    + +
    +
    +

    {i18n.t("workspace.lite.promo.title")}

    +
    +

    {i18n.t("workspace.lite.promo.description")}

    +

    {i18n.t("workspace.lite.promo.modelsTitle")}

    +
      +
    • Kimi K2.5
    • +
    • GLM-5
    • +
    • MiniMax M2.5
    • +
    +

    {i18n.t("workspace.lite.promo.footer")}

    + +
    +
    + + ) +} diff --git a/packages/console/app/src/routes/workspace/[id]/billing/reload-section.tsx b/packages/console/app/src/routes/workspace/[id]/billing/reload-section.tsx index 7084be1338..90c9d7a2e4 100644 --- a/packages/console/app/src/routes/workspace/[id]/billing/reload-section.tsx +++ b/packages/console/app/src/routes/workspace/[id]/billing/reload-section.tsx @@ -202,7 +202,8 @@ export function ReloadSection() { minute: "2-digit", second: "2-digit", })} - . {i18n.t("workspace.reload.reason")} {billingInfo()?.reloadError?.replace(/\.$/, "")}.{" "} + . {i18n.t("workspace.reload.reason")}{" "} + {localizeError(i18n.t, billingInfo()?.reloadError ?? undefined).replace(/\.$/, "")}.{" "} {i18n.t("workspace.reload.updatePaymentMethod")}

    diff --git a/packages/console/app/src/routes/workspace/[id]/graph-section.tsx b/packages/console/app/src/routes/workspace/[id]/graph-section.tsx index f26c7291d8..bb4b4f4cfd 100644 --- a/packages/console/app/src/routes/workspace/[id]/graph-section.tsx +++ b/packages/console/app/src/routes/workspace/[id]/graph-section.tsx @@ -36,7 +36,7 @@ async function getCosts(workspaceID: string, year: number, month: number) { model: UsageTable.model, totalCost: sum(UsageTable.cost), keyId: UsageTable.keyID, - subscription: sql`COALESCE(JSON_EXTRACT(${UsageTable.enrichment}, '$.plan') = 'sub', false)`, + plan: sql`JSON_EXTRACT(${UsageTable.enrichment}, '$.plan')`, }) .from(UsageTable) .where( @@ -50,13 +50,13 @@ async function getCosts(workspaceID: string, year: number, month: number) { sql`DATE(${UsageTable.timeCreated})`, UsageTable.model, UsageTable.keyID, - sql`COALESCE(JSON_EXTRACT(${UsageTable.enrichment}, '$.plan') = 'sub', false)`, + sql`JSON_EXTRACT(${UsageTable.enrichment}, '$.plan')`, ) .then((x) => x.map((r) => ({ ...r, totalCost: r.totalCost ? parseInt(r.totalCost) : 0, - subscription: Boolean(r.subscription), + plan: r.plan as "sub" | "lite" | "byok" | null, })), ), ) @@ -218,18 +218,21 @@ export function GraphSection() { const colorTextSecondary = styles.getPropertyValue("--color-text-secondary").trim() const colorBorder = styles.getPropertyValue("--color-border").trim() const subSuffix = ` (${i18n.t("workspace.cost.subscriptionShort")})` + const liteSuffix = " (go)" + const dailyDataRegular = new Map>() const dailyDataSub = new Map>() - const dailyDataNonSub = new Map>() + const dailyDataLite = new Map>() for (const dateKey of dates) { + dailyDataRegular.set(dateKey, new Map()) dailyDataSub.set(dateKey, new Map()) - dailyDataNonSub.set(dateKey, new Map()) + dailyDataLite.set(dateKey, new Map()) } data.usage .filter((row) => (store.key ? row.keyId === store.key : true)) .forEach((row) => { - const targetMap = row.subscription ? dailyDataSub : dailyDataNonSub + const targetMap = row.plan === "sub" ? dailyDataSub : row.plan === "lite" ? dailyDataLite : dailyDataRegular const dayMap = targetMap.get(row.date) if (!dayMap) return dayMap.set(row.model, (dayMap.get(row.model) ?? 0) + row.totalCost) @@ -237,15 +240,15 @@ export function GraphSection() { const filteredModels = store.model === null ? getModels() : [store.model] - // Create datasets: non-subscription first, then subscription (with hatched pattern effect via opacity) + // Create datasets: regular first, then subscription, then lite (with visual distinction via opacity) const datasets = [ ...filteredModels - .filter((model) => dates.some((date) => (dailyDataNonSub.get(date)?.get(model) || 0) > 0)) + .filter((model) => dates.some((date) => (dailyDataRegular.get(date)?.get(model) || 0) > 0)) .map((model) => { const color = getModelColor(model) return { label: model, - data: dates.map((date) => (dailyDataNonSub.get(date)?.get(model) || 0) / 100_000_000), + data: dates.map((date) => (dailyDataRegular.get(date)?.get(model) || 0) / 100_000_000), backgroundColor: color, hoverBackgroundColor: color, borderWidth: 0, @@ -266,6 +269,21 @@ export function GraphSection() { stack: "subscription", } }), + ...filteredModels + .filter((model) => dates.some((date) => (dailyDataLite.get(date)?.get(model) || 0) > 0)) + .map((model) => { + const color = getModelColor(model) + return { + label: `${model}${liteSuffix}`, + data: dates.map((date) => (dailyDataLite.get(date)?.get(model) || 0) / 100_000_000), + backgroundColor: addOpacityToColor(color, 0.35), + hoverBackgroundColor: addOpacityToColor(color, 0.55), + borderWidth: 1, + borderColor: addOpacityToColor(color, 0.7), + borderDash: [4, 2], + stack: "lite", + } + }), ] return { @@ -347,9 +365,18 @@ export function GraphSection() { const meta = chart.getDatasetMeta(i) const label = dataset.label || "" const isSub = label.endsWith(subSuffix) - const model = isSub ? label.slice(0, -subSuffix.length) : label + const isLite = label.endsWith(liteSuffix) + const model = isSub + ? label.slice(0, -subSuffix.length) + : isLite + ? label.slice(0, -liteSuffix.length) + : label const baseColor = getModelColor(model) - const originalColor = isSub ? addOpacityToColor(baseColor, 0.5) : baseColor + const originalColor = isSub + ? addOpacityToColor(baseColor, 0.5) + : isLite + ? addOpacityToColor(baseColor, 0.35) + : baseColor const color = i === legendItem.datasetIndex ? originalColor : addOpacityToColor(baseColor, 0.15) meta.data.forEach((bar: any) => { bar.options.backgroundColor = color @@ -363,9 +390,18 @@ export function GraphSection() { const meta = chart.getDatasetMeta(i) const label = dataset.label || "" const isSub = label.endsWith(subSuffix) - const model = isSub ? label.slice(0, -subSuffix.length) : label + const isLite = label.endsWith(liteSuffix) + const model = isSub + ? label.slice(0, -subSuffix.length) + : isLite + ? label.slice(0, -liteSuffix.length) + : label const baseColor = getModelColor(model) - const color = isSub ? addOpacityToColor(baseColor, 0.5) : baseColor + const color = isSub + ? addOpacityToColor(baseColor, 0.5) + : isLite + ? addOpacityToColor(baseColor, 0.35) + : baseColor meta.data.forEach((bar: any) => { bar.options.backgroundColor = color }) diff --git a/packages/console/app/src/routes/workspace/[id]/model-section.tsx b/packages/console/app/src/routes/workspace/[id]/model-section.tsx index 97f95278a1..a4b64889ca 100644 --- a/packages/console/app/src/routes/workspace/[id]/model-section.tsx +++ b/packages/console/app/src/routes/workspace/[id]/model-section.tsx @@ -36,7 +36,7 @@ const getModelsInfo = query(async (workspaceID: string) => { "use server" return withActor(async () => { return { - all: Object.entries(ZenData.list().models) + all: Object.entries(ZenData.list("full").models) .filter(([id, _model]) => !["claude-3-5-haiku"].includes(id)) .filter(([id, _model]) => !id.startsWith("alpha-")) .sort(([idA, modelA], [idB, modelB]) => { diff --git a/packages/console/app/src/routes/workspace/[id]/usage-section.tsx b/packages/console/app/src/routes/workspace/[id]/usage-section.tsx index 079a27c3ca..a20a5bf0d1 100644 --- a/packages/console/app/src/routes/workspace/[id]/usage-section.tsx +++ b/packages/console/app/src/routes/workspace/[id]/usage-section.tsx @@ -1,6 +1,6 @@ import { Billing } from "@opencode-ai/console-core/billing.js" import { createAsync, query, useParams } from "@solidjs/router" -import { createMemo, For, Show, createEffect, createSignal } from "solid-js" +import { createMemo, For, Show, Switch, Match, createEffect, createSignal } from "solid-js" import { formatDateUTC, formatDateForTable } from "../common" import { withActor } from "~/context/auth.withActor" import { IconChevronLeft, IconChevronRight, IconBreakdown } from "~/component/icon" @@ -94,6 +94,7 @@ export function UsageSection() { {i18n.t("workspace.usage.table.input")} {i18n.t("workspace.usage.table.output")} {i18n.t("workspace.usage.table.cost")} + {i18n.t("workspace.usage.table.session")} @@ -174,15 +175,25 @@ export function UsageSection() {
    - ${((usage.cost ?? 0) / 100000000).toFixed(4)}} - > - {i18n.t("workspace.usage.subscription", { - amount: ((usage.cost ?? 0) / 100000000).toFixed(4), - })} - + ${((usage.cost ?? 0) / 100000000).toFixed(4)}}> + + {i18n.t("workspace.usage.subscription", { + amount: ((usage.cost ?? 0) / 100000000).toFixed(4), + })} + + + {i18n.t("workspace.usage.lite", { + amount: ((usage.cost ?? 0) / 100000000).toFixed(4), + })} + + + {i18n.t("workspace.usage.byok", { + amount: ((usage.cost ?? 0) / 100000000).toFixed(4), + })} + + + {usage.sessionID?.slice(-8) ?? "-"} ) }} diff --git a/packages/console/app/src/routes/workspace/common.tsx b/packages/console/app/src/routes/workspace/common.tsx index 5cbd671835..d41793dd92 100644 --- a/packages/console/app/src/routes/workspace/common.tsx +++ b/packages/console/app/src/routes/workspace/common.tsx @@ -115,6 +115,8 @@ export const queryBillingInfo = query(async (workspaceID: string) => { subscriptionPlan: billing.subscriptionPlan, timeSubscriptionBooked: billing.timeSubscriptionBooked, timeSubscriptionSelected: billing.timeSubscriptionSelected, + lite: billing.lite, + liteSubscriptionID: billing.liteSubscriptionID, } }, workspaceID) }, "billing.get") diff --git a/packages/console/app/src/routes/zen/go/v1/chat/completions.ts b/packages/console/app/src/routes/zen/go/v1/chat/completions.ts new file mode 100644 index 0000000000..9a57e893fb --- /dev/null +++ b/packages/console/app/src/routes/zen/go/v1/chat/completions.ts @@ -0,0 +1,12 @@ +import type { APIEvent } from "@solidjs/start/server" +import { handler } from "~/routes/zen/util/handler" + +export function POST(input: APIEvent) { + return handler(input, { + format: "oa-compat", + modelList: "lite", + parseApiKey: (headers: Headers) => headers.get("authorization")?.split(" ")[1], + parseModel: (url: string, body: any) => body.model, + parseIsStream: (url: string, body: any) => !!body.stream, + }) +} diff --git a/packages/console/app/src/routes/zen/go/v1/messages.ts b/packages/console/app/src/routes/zen/go/v1/messages.ts new file mode 100644 index 0000000000..ee401e6aa2 --- /dev/null +++ b/packages/console/app/src/routes/zen/go/v1/messages.ts @@ -0,0 +1,12 @@ +import type { APIEvent } from "@solidjs/start/server" +import { handler } from "~/routes/zen/util/handler" + +export function POST(input: APIEvent) { + return handler(input, { + format: "anthropic", + modelList: "lite", + parseApiKey: (headers: Headers) => headers.get("x-api-key") ?? undefined, + parseModel: (url: string, body: any) => body.model, + parseIsStream: (url: string, body: any) => !!body.stream, + }) +} diff --git a/packages/console/app/src/routes/zen/index.css b/packages/console/app/src/routes/zen/index.css index acdfbe85d8..1b57552882 100644 --- a/packages/console/app/src/routes/zen/index.css +++ b/packages/console/app/src/routes/zen/index.css @@ -148,10 +148,10 @@ body { display: flex; justify-content: space-between; align-items: center; - gap: 48px; + gap: 32px; @media (max-width: 55rem) { - gap: 32px; + gap: 24px; } @media (max-width: 48rem) { diff --git a/packages/console/app/src/routes/zen/util/handler.ts b/packages/console/app/src/routes/zen/util/handler.ts index ee717ba5ff..429ce00185 100644 --- a/packages/console/app/src/routes/zen/util/handler.ts +++ b/packages/console/app/src/routes/zen/util/handler.ts @@ -1,15 +1,16 @@ import type { APIEvent } from "@solidjs/start/server" import { and, Database, eq, isNull, lt, or, sql } from "@opencode-ai/console-core/drizzle/index.js" import { KeyTable } from "@opencode-ai/console-core/schema/key.sql.js" -import { BillingTable, SubscriptionTable, UsageTable } from "@opencode-ai/console-core/schema/billing.sql.js" +import { BillingTable, LiteTable, SubscriptionTable, UsageTable } from "@opencode-ai/console-core/schema/billing.sql.js" import { centsToMicroCents } from "@opencode-ai/console-core/util/price.js" -import { getWeekBounds } from "@opencode-ai/console-core/util/date.js" +import { getMonthlyBounds, getWeekBounds } from "@opencode-ai/console-core/util/date.js" import { Identifier } from "@opencode-ai/console-core/identifier.js" import { Billing } from "@opencode-ai/console-core/billing.js" import { Actor } from "@opencode-ai/console-core/actor.js" import { WorkspaceTable } from "@opencode-ai/console-core/schema/workspace.sql.js" import { ZenData } from "@opencode-ai/console-core/model.js" -import { Black, BlackData } from "@opencode-ai/console-core/black.js" +import { Subscription } from "@opencode-ai/console-core/subscription.js" +import { BlackData } from "@opencode-ai/console-core/black.js" import { UserTable } from "@opencode-ai/console-core/schema/user.sql.js" import { ModelTable } from "@opencode-ai/console-core/schema/model.sql.js" import { ProviderTable } from "@opencode-ai/console-core/schema/provider.sql.js" @@ -32,18 +33,32 @@ import { createRateLimiter } from "./rateLimiter" import { createDataDumper } from "./dataDumper" import { createTrialLimiter } from "./trialLimiter" import { createStickyTracker } from "./stickyProviderTracker" +import { LiteData } from "@opencode-ai/console-core/lite.js" +import { Resource } from "@opencode-ai/console-resource" +import { i18n, type Key } from "~/i18n" +import { localeFromRequest } from "~/lib/language" type ZenData = Awaited> type RetryOptions = { excludeProviders: string[] retryCount: number } -type BillingSource = "anonymous" | "free" | "byok" | "subscription" | "balance" +type BillingSource = "anonymous" | "free" | "byok" | "subscription" | "lite" | "balance" + +function resolve(text: string, params?: Record) { + if (!params) return text + return text.replace(/\{\{(\w+)\}\}/g, (raw, key) => { + const value = params[key] + if (value === undefined || value === null) return raw + return String(value) + }) +} export async function handler( input: APIEvent, opts: { format: ZenData.Format + modelList: "lite" | "full" parseApiKey: (headers: Headers) => string | undefined parseModel: (url: string, body: any) => string parseIsStream: (url: string, body: any) => boolean @@ -56,7 +71,9 @@ export async function handler( const MAX_FAILOVER_RETRIES = 3 const MAX_429_RETRIES = 3 - const FREE_WORKSPACES = [ + const dict = i18n(localeFromRequest(input.request)) + const t = (key: Key, params?: Record) => resolve(dict[key], params) + const ADMIN_WORKSPACES = [ "wrk_01K46JDFR0E75SG2Q8K172KF3Y", // frank "wrk_01K6W1A3VE0KMNVSCQT43BG2SX", // opencode bench ] @@ -77,17 +94,18 @@ export async function handler( request: requestId, client: ocClient, }) - const zenData = ZenData.list() + const zenData = ZenData.list(opts.modelList) const modelInfo = validateModel(zenData, model) const dataDumper = createDataDumper(sessionId, requestId, projectId) - const trialLimiter = createTrialLimiter(modelInfo.trial, ip, ocClient) - const isTrial = await trialLimiter?.isTrial() - const rateLimiter = createRateLimiter(modelInfo.rateLimit, ip, input.request.headers) + const trialLimiter = createTrialLimiter(modelInfo.trialProvider, ip) + const trialProvider = await trialLimiter?.check() + const rateLimiter = createRateLimiter(modelInfo.allowAnonymous, ip, input.request) await rateLimiter?.check() const stickyTracker = createStickyTracker(modelInfo.stickyProvider, sessionId) const stickyProvider = await stickyTracker?.get() const authInfo = await authenticate(modelInfo) const billingSource = validateBilling(authInfo, modelInfo) + logger.metric({ source: billingSource }) const retriableRequest = async (retry: RetryOptions = { excludeProviders: [], retryCount: 0 }) => { const providerInfo = selectProvider( @@ -96,7 +114,7 @@ export async function handler( authInfo, modelInfo, sessionId, - isTrial ?? false, + trialProvider, retry, stickyProvider, ) @@ -126,9 +144,6 @@ export async function handler( Object.entries(providerInfo.headerMappings ?? {}).forEach(([k, v]) => { headers.set(k, headers.get(v)!) }) - Object.entries(providerInfo.headers ?? {}).forEach(([k, v]) => { - headers.set(k, v) - }) headers.delete("host") headers.delete("content-length") headers.delete("x-opencode-request") @@ -195,7 +210,7 @@ export async function handler( const costInfo = calculateCost(modelInfo, usageInfo) await trialLimiter?.track(usageInfo) await rateLimiter?.track() - await trackUsage(billingSource, authInfo, modelInfo, providerInfo, usageInfo, costInfo) + await trackUsage(sessionId, billingSource, authInfo, modelInfo, providerInfo, usageInfo, costInfo) await reload(billingSource, authInfo, costInfo) const responseConverter = createResponseConverter(providerInfo.format, opts.format) @@ -240,16 +255,15 @@ export async function handler( dataDumper?.flush() await rateLimiter?.track() const usage = usageParser.retrieve() - let cost = "0" if (usage) { const usageInfo = providerInfo.normalizeUsage(usage) const costInfo = calculateCost(modelInfo, usageInfo) await trialLimiter?.track(usageInfo) - await trackUsage(billingSource, authInfo, modelInfo, providerInfo, usageInfo, costInfo) + await trackUsage(sessionId, billingSource, authInfo, modelInfo, providerInfo, usageInfo, costInfo) await reload(billingSource, authInfo, costInfo) - cost = calculateOccuredCost(billingSource, costInfo) + const cost = calculateOccuredCost(billingSource, costInfo) + c.enqueue(encoder.encode(usageParser.buidlCostChunk(cost))) } - c.enqueue(encoder.encode(usageParser.buidlCostChunk(cost))) c.close() return } @@ -278,18 +292,13 @@ export async function handler( part = part.trim() usageParser.parse(part) - if (providerInfo.responseModifier) { - for (const [k, v] of Object.entries(providerInfo.responseModifier)) { - part = part.replace(k, v) - } - c.enqueue(encoder.encode(part + "\n\n")) - } else if (providerInfo.format !== opts.format) { + if (providerInfo.format !== opts.format) { part = streamConverter(part) c.enqueue(encoder.encode(part + "\n\n")) } } - if (!providerInfo.responseModifier && providerInfo.format === opts.format) { + if (providerInfo.format === opts.format) { c.enqueue(value) } @@ -355,14 +364,20 @@ export async function handler( } function validateModel(zenData: ZenData, reqModel: string) { - if (!(reqModel in zenData.models)) throw new ModelError(`Model ${reqModel} not supported`) + if (!(reqModel in zenData.models)) throw new ModelError(t("zen.api.error.modelNotSupported", { model: reqModel })) const modelId = reqModel as keyof typeof zenData.models const modelData = Array.isArray(zenData.models[modelId]) ? zenData.models[modelId].find((model) => opts.format === model.formatFilter) : zenData.models[modelId] - if (!modelData) throw new ModelError(`Model ${reqModel} not supported for format ${opts.format}`) + if (!modelData) + throw new ModelError( + t("zen.api.error.modelFormatNotSupported", { + model: reqModel, + format: opts.format, + }), + ) logger.metric({ model: modelId }) @@ -375,7 +390,7 @@ export async function handler( authInfo: AuthInfo, modelInfo: ModelInfo, sessionId: string, - isTrial: boolean, + trialProvider: string | undefined, retry: RetryOptions, stickyProvider: string | undefined, ) { @@ -384,8 +399,8 @@ export async function handler( return modelInfo.providers.find((provider) => provider.id === modelInfo.byokProvider) } - if (isTrial) { - return modelInfo.providers.find((provider) => provider.id === modelInfo.trial!.provider) + if (trialProvider) { + return modelInfo.providers.find((provider) => provider.id === trialProvider) } if (stickyProvider) { @@ -414,8 +429,9 @@ export async function handler( return modelInfo.providers.find((provider) => provider.id === modelInfo.fallbackProvider) })() - if (!modelProvider) throw new ModelError("No provider available") - if (!(modelProvider.id in zenData.providers)) throw new ModelError(`Provider ${modelProvider.id} not supported`) + if (!modelProvider) throw new ModelError(t("zen.api.error.noProviderAvailable")) + if (!(modelProvider.id in zenData.providers)) + throw new ModelError(t("zen.api.error.providerNotSupported", { provider: modelProvider.id })) return { ...modelProvider, @@ -435,7 +451,7 @@ export async function handler( const apiKey = opts.parseApiKey(input.request.headers) if (!apiKey || apiKey === "public") { if (modelInfo.allowAnonymous) return - throw new AuthError("Missing API key.") + throw new AuthError(t("zen.api.error.missingApiKey")) } const data = await Database.use((tx) => @@ -452,6 +468,7 @@ export async function handler( reloadTrigger: BillingTable.reloadTrigger, timeReloadLockedTill: BillingTable.timeReloadLockedTill, subscription: BillingTable.subscription, + lite: BillingTable.lite, }, user: { id: UserTable.id, @@ -459,13 +476,23 @@ export async function handler( monthlyUsage: UserTable.monthlyUsage, timeMonthlyUsageUpdated: UserTable.timeMonthlyUsageUpdated, }, - subscription: { + black: { id: SubscriptionTable.id, rollingUsage: SubscriptionTable.rollingUsage, fixedUsage: SubscriptionTable.fixedUsage, timeRollingUpdated: SubscriptionTable.timeRollingUpdated, timeFixedUpdated: SubscriptionTable.timeFixedUpdated, }, + lite: { + id: LiteTable.id, + timeCreated: LiteTable.timeCreated, + rollingUsage: LiteTable.rollingUsage, + weeklyUsage: LiteTable.weeklyUsage, + monthlyUsage: LiteTable.monthlyUsage, + timeRollingUpdated: LiteTable.timeRollingUpdated, + timeWeeklyUpdated: LiteTable.timeWeeklyUpdated, + timeMonthlyUpdated: LiteTable.timeMonthlyUpdated, + }, provider: { credentials: ProviderTable.credentials, }, @@ -493,16 +520,42 @@ export async function handler( isNull(SubscriptionTable.timeDeleted), ), ) + .leftJoin( + LiteTable, + and( + eq(LiteTable.workspaceID, KeyTable.workspaceID), + eq(LiteTable.userID, KeyTable.userID), + isNull(LiteTable.timeDeleted), + ), + ) .where(and(eq(KeyTable.key, apiKey), isNull(KeyTable.timeDeleted))) .then((rows) => rows[0]), ) - if (!data) throw new AuthError("Invalid API key.") + if (!data) throw new AuthError(t("zen.api.error.invalidApiKey")) + if ( + modelInfo.id.startsWith("alpha-") && + Resource.App.stage === "production" && + !ADMIN_WORKSPACES.includes(data.workspaceID) + ) + throw new AuthError(t("zen.api.error.modelNotSupported", { model: modelInfo.id })) + logger.metric({ api_key: data.apiKey, workspace: data.workspaceID, - isSubscription: data.subscription ? true : false, - subscription: data.billing.subscription?.plan, + ...(() => { + if (data.billing.subscription) + return { + isSubscription: true, + subscription: data.billing.subscription.plan, + } + if (data.billing.lite) + return { + isSubscription: true, + subscription: "lite", + } + return {} + })(), }) return { @@ -510,9 +563,10 @@ export async function handler( workspaceID: data.workspaceID, billing: data.billing, user: data.user, - subscription: data.subscription, + black: data.black, + lite: data.lite, provider: data.provider, - isFree: FREE_WORKSPACES.includes(data.workspaceID), + isFree: ADMIN_WORKSPACES.includes(data.workspaceID), isDisabled: !!data.timeDisabled, } } @@ -523,45 +577,52 @@ export async function handler( if (authInfo.isFree) return "free" if (modelInfo.allowAnonymous) return "free" - // Validate subscription billing - if (authInfo.billing.subscription && authInfo.subscription) { - try { - const sub = authInfo.subscription - const plan = authInfo.billing.subscription.plan + const formatRetryTime = (seconds: number) => { + const days = Math.floor(seconds / 86400) + if (days >= 1) return `${days} day${days > 1 ? "s" : ""}` + const hours = Math.floor(seconds / 3600) + const minutes = Math.ceil((seconds % 3600) / 60) + if (hours >= 1) return `${hours}hr ${minutes}min` + return `${minutes}min` + } - const formatRetryTime = (seconds: number) => { - const days = Math.floor(seconds / 86400) - if (days >= 1) return `${days} day${days > 1 ? "s" : ""}` - const hours = Math.floor(seconds / 3600) - const minutes = Math.ceil((seconds % 3600) / 60) - if (hours >= 1) return `${hours}hr ${minutes}min` - return `${minutes}min` - } + // Validate black subscription billing + if (authInfo.billing.subscription && authInfo.black) { + try { + const sub = authInfo.black + const plan = authInfo.billing.subscription.plan // Check weekly limit if (sub.fixedUsage && sub.timeFixedUpdated) { - const result = Black.analyzeWeeklyUsage({ - plan, + const blackData = BlackData.getLimits({ plan }) + const result = Subscription.analyzeWeeklyUsage({ + limit: blackData.fixedLimit, usage: sub.fixedUsage, timeUpdated: sub.timeFixedUpdated, }) if (result.status === "rate-limited") throw new SubscriptionUsageLimitError( - `Subscription quota exceeded. Retry in ${formatRetryTime(result.resetInSec)}.`, + t("zen.api.error.subscriptionQuotaExceeded", { + retryIn: formatRetryTime(result.resetInSec), + }), result.resetInSec, ) } // Check rolling limit if (sub.rollingUsage && sub.timeRollingUpdated) { - const result = Black.analyzeRollingUsage({ - plan, + const blackData = BlackData.getLimits({ plan }) + const result = Subscription.analyzeRollingUsage({ + limit: blackData.rollingLimit, + window: blackData.rollingWindow, usage: sub.rollingUsage, timeUpdated: sub.timeRollingUpdated, }) if (result.status === "rate-limited") throw new SubscriptionUsageLimitError( - `Subscription quota exceeded. Retry in ${formatRetryTime(result.resetInSec)}.`, + t("zen.api.error.subscriptionQuotaExceeded", { + retryIn: formatRetryTime(result.resetInSec), + }), result.resetInSec, ) } @@ -572,16 +633,68 @@ export async function handler( } } + // Validate lite subscription billing + if (opts.modelList === "lite" && authInfo.billing.lite && authInfo.lite) { + try { + const sub = authInfo.lite + const liteData = LiteData.getLimits() + + // Check weekly limit + if (sub.weeklyUsage && sub.timeWeeklyUpdated) { + const result = Subscription.analyzeWeeklyUsage({ + limit: liteData.weeklyLimit, + usage: sub.weeklyUsage, + timeUpdated: sub.timeWeeklyUpdated, + }) + if (result.status === "rate-limited") + throw new SubscriptionUsageLimitError( + t("zen.api.error.subscriptionQuotaExceededUseFreeModels"), + result.resetInSec, + ) + } + + // Check monthly limit + if (sub.monthlyUsage && sub.timeMonthlyUpdated) { + const result = Subscription.analyzeMonthlyUsage({ + limit: liteData.monthlyLimit, + usage: sub.monthlyUsage, + timeUpdated: sub.timeMonthlyUpdated, + timeSubscribed: sub.timeCreated, + }) + if (result.status === "rate-limited") + throw new SubscriptionUsageLimitError( + t("zen.api.error.subscriptionQuotaExceededUseFreeModels"), + result.resetInSec, + ) + } + + // Check rolling limit + if (sub.rollingUsage && sub.timeRollingUpdated) { + const result = Subscription.analyzeRollingUsage({ + limit: liteData.rollingLimit, + window: liteData.rollingWindow, + usage: sub.rollingUsage, + timeUpdated: sub.timeRollingUpdated, + }) + if (result.status === "rate-limited") + throw new SubscriptionUsageLimitError( + t("zen.api.error.subscriptionQuotaExceededUseFreeModels"), + result.resetInSec, + ) + } + + return "lite" + } catch (e) { + if (!authInfo.billing.lite.useBalance) throw e + } + } + // Validate pay as you go billing const billing = authInfo.billing - if (!billing.paymentMethodID) - throw new CreditsError( - `No payment method. Add a payment method here: https://opencode.ai/workspace/${authInfo.workspaceID}/billing`, - ) - if (billing.balance <= 0) - throw new CreditsError( - `Insufficient balance. Manage your billing here: https://opencode.ai/workspace/${authInfo.workspaceID}/billing`, - ) + const billingUrl = `https://opencode.ai/workspace/${authInfo.workspaceID}/billing` + const membersUrl = `https://opencode.ai/workspace/${authInfo.workspaceID}/members` + if (!billing.paymentMethodID) throw new CreditsError(t("zen.api.error.noPaymentMethod", { billingUrl })) + if (billing.balance <= 0) throw new CreditsError(t("zen.api.error.insufficientBalance", { billingUrl })) const now = new Date() const currentYear = now.getUTCFullYear() @@ -595,7 +708,10 @@ export async function handler( currentMonth === billing.timeMonthlyUsageUpdated.getUTCMonth() ) throw new MonthlyLimitError( - `Your workspace has reached its monthly spending limit of $${billing.monthlyLimit}. Manage your limits here: https://opencode.ai/workspace/${authInfo.workspaceID}/billing`, + t("zen.api.error.workspaceMonthlyLimitReached", { + amount: billing.monthlyLimit, + billingUrl, + }), ) if ( @@ -607,7 +723,10 @@ export async function handler( currentMonth === authInfo.user.timeMonthlyUsageUpdated.getUTCMonth() ) throw new UserLimitError( - `You have reached your monthly spending limit of $${authInfo.user.monthlyLimit}. Manage your limits here: https://opencode.ai/workspace/${authInfo.workspaceID}/members`, + t("zen.api.error.userMonthlyLimitReached", { + amount: authInfo.user.monthlyLimit, + membersUrl, + }), ) return "balance" @@ -615,7 +734,7 @@ export async function handler( function validateModelSettings(authInfo: AuthInfo) { if (!authInfo) return - if (authInfo.isDisabled) throw new ModelError("Model is disabled") + if (authInfo.isDisabled) throw new ModelError(t("zen.api.error.modelDisabled")) } function updateProviderKey(authInfo: AuthInfo, providerInfo: ProviderInfo) { @@ -686,6 +805,7 @@ export async function handler( } async function trackUsage( + sessionId: string, billingSource: BillingSource, authInfo: AuthInfo, modelInfo: ModelInfo, @@ -733,79 +853,127 @@ export async function handler( cacheWrite1hTokens, cost, keyID: authInfo.apiKeyId, - enrichment: billingSource === "subscription" ? { plan: "sub" } : undefined, + sessionID: sessionId.substring(0, 30), + enrichment: (() => { + if (billingSource === "subscription") return { plan: "sub" } + if (billingSource === "byok") return { plan: "byok" } + if (billingSource === "lite") return { plan: "lite" } + return undefined + })(), }), db .update(KeyTable) .set({ timeUsed: sql`now()` }) .where(and(eq(KeyTable.workspaceID, authInfo.workspaceID), eq(KeyTable.id, authInfo.apiKeyId))), - ...(billingSource === "subscription" - ? (() => { - const plan = authInfo.billing.subscription!.plan - const black = BlackData.getLimits({ plan }) - const week = getWeekBounds(new Date()) - const rollingWindowSeconds = black.rollingWindow * 3600 - return [ - db - .update(SubscriptionTable) - .set({ - fixedUsage: sql` + ...(() => { + if (billingSource === "subscription") { + const plan = authInfo.billing.subscription!.plan + const black = BlackData.getLimits({ plan }) + const week = getWeekBounds(new Date()) + const rollingWindowSeconds = black.rollingWindow * 3600 + return [ + db + .update(SubscriptionTable) + .set({ + fixedUsage: sql` CASE WHEN ${SubscriptionTable.timeFixedUpdated} >= ${week.start} THEN ${SubscriptionTable.fixedUsage} + ${cost} ELSE ${cost} END `, - timeFixedUpdated: sql`now()`, - rollingUsage: sql` + timeFixedUpdated: sql`now()`, + rollingUsage: sql` CASE WHEN UNIX_TIMESTAMP(${SubscriptionTable.timeRollingUpdated}) >= UNIX_TIMESTAMP(now()) - ${rollingWindowSeconds} THEN ${SubscriptionTable.rollingUsage} + ${cost} ELSE ${cost} END `, - timeRollingUpdated: sql` + timeRollingUpdated: sql` CASE WHEN UNIX_TIMESTAMP(${SubscriptionTable.timeRollingUpdated}) >= UNIX_TIMESTAMP(now()) - ${rollingWindowSeconds} THEN ${SubscriptionTable.timeRollingUpdated} ELSE now() END `, - }) - .where( - and( - eq(SubscriptionTable.workspaceID, authInfo.workspaceID), - eq(SubscriptionTable.userID, authInfo.user.id), - ), + }) + .where( + and( + eq(SubscriptionTable.workspaceID, authInfo.workspaceID), + eq(SubscriptionTable.userID, authInfo.user.id), ), - ] - })() - : [ + ), + ] + } + if (billingSource === "lite") { + const lite = LiteData.getLimits() + const week = getWeekBounds(new Date()) + const month = getMonthlyBounds(new Date(), authInfo.lite!.timeCreated) + const rollingWindowSeconds = lite.rollingWindow * 3600 + return [ db - .update(BillingTable) + .update(LiteTable) .set({ - balance: authInfo.isFree + monthlyUsage: sql` + CASE + WHEN ${LiteTable.timeMonthlyUpdated} >= ${month.start} THEN ${LiteTable.monthlyUsage} + ${cost} + ELSE ${cost} + END + `, + timeMonthlyUpdated: sql`now()`, + weeklyUsage: sql` + CASE + WHEN ${LiteTable.timeWeeklyUpdated} >= ${week.start} THEN ${LiteTable.weeklyUsage} + ${cost} + ELSE ${cost} + END + `, + timeWeeklyUpdated: sql`now()`, + rollingUsage: sql` + CASE + WHEN UNIX_TIMESTAMP(${LiteTable.timeRollingUpdated}) >= UNIX_TIMESTAMP(now()) - ${rollingWindowSeconds} THEN ${LiteTable.rollingUsage} + ${cost} + ELSE ${cost} + END + `, + timeRollingUpdated: sql` + CASE + WHEN UNIX_TIMESTAMP(${LiteTable.timeRollingUpdated}) >= UNIX_TIMESTAMP(now()) - ${rollingWindowSeconds} THEN ${LiteTable.timeRollingUpdated} + ELSE now() + END + `, + }) + .where(and(eq(LiteTable.workspaceID, authInfo.workspaceID), eq(LiteTable.userID, authInfo.user.id))), + ] + } + + return [ + db + .update(BillingTable) + .set({ + balance: + billingSource === "free" || billingSource === "byok" ? sql`${BillingTable.balance} - ${0}` : sql`${BillingTable.balance} - ${cost}`, - monthlyUsage: sql` + monthlyUsage: sql` CASE WHEN MONTH(${BillingTable.timeMonthlyUsageUpdated}) = MONTH(now()) AND YEAR(${BillingTable.timeMonthlyUsageUpdated}) = YEAR(now()) THEN ${BillingTable.monthlyUsage} + ${cost} ELSE ${cost} END `, - timeMonthlyUsageUpdated: sql`now()`, - }) - .where(eq(BillingTable.workspaceID, authInfo.workspaceID)), - db - .update(UserTable) - .set({ - monthlyUsage: sql` + timeMonthlyUsageUpdated: sql`now()`, + }) + .where(eq(BillingTable.workspaceID, authInfo.workspaceID)), + db + .update(UserTable) + .set({ + monthlyUsage: sql` CASE WHEN MONTH(${UserTable.timeMonthlyUsageUpdated}) = MONTH(now()) AND YEAR(${UserTable.timeMonthlyUsageUpdated}) = YEAR(now()) THEN ${UserTable.monthlyUsage} + ${cost} ELSE ${cost} END `, - timeMonthlyUsageUpdated: sql`now()`, - }) - .where(and(eq(UserTable.workspaceID, authInfo.workspaceID), eq(UserTable.id, authInfo.user.id))), - ]), + timeMonthlyUsageUpdated: sql`now()`, + }) + .where(and(eq(UserTable.workspaceID, authInfo.workspaceID), eq(UserTable.id, authInfo.user.id))), + ] + })(), ]), ) diff --git a/packages/console/app/src/routes/zen/util/provider/anthropic.ts b/packages/console/app/src/routes/zen/util/provider/anthropic.ts index e2803459e0..95c50fbdbf 100644 --- a/packages/console/app/src/routes/zen/util/provider/anthropic.ts +++ b/packages/console/app/src/routes/zen/util/provider/anthropic.ts @@ -43,7 +43,7 @@ export const anthropicHelper: ProviderHelper = ({ reqModel, providerModel }) => ...(isBedrock ? { anthropic_version: "bedrock-2023-05-31", - anthropic_beta: supports1m ? "context-1m-2025-08-07" : undefined, + anthropic_beta: supports1m ? ["context-1m-2025-08-07"] : undefined, model: undefined, stream: undefined, } diff --git a/packages/console/app/src/routes/zen/util/rateLimiter.ts b/packages/console/app/src/routes/zen/util/rateLimiter.ts index 5e4f31e676..019e68754d 100644 --- a/packages/console/app/src/routes/zen/util/rateLimiter.ts +++ b/packages/console/app/src/routes/zen/util/rateLimiter.ts @@ -2,26 +2,28 @@ import { Database, eq, and, sql, inArray } from "@opencode-ai/console-core/drizz import { IpRateLimitTable } from "@opencode-ai/console-core/schema/ip.sql.js" import { FreeUsageLimitError } from "./error" import { logger } from "./logger" -import { ZenData } from "@opencode-ai/console-core/model.js" +import { i18n } from "~/i18n" +import { localeFromRequest } from "~/lib/language" +import { Subscription } from "@opencode-ai/console-core/subscription.js" -export function createRateLimiter(limit: ZenData.RateLimit | undefined, rawIp: string, headers: Headers) { - if (!limit) return +export function createRateLimiter(allowAnonymous: boolean | undefined, rawIp: string, request: Request) { + if (!allowAnonymous) return + const dict = i18n(localeFromRequest(request)) - const limitValue = limit.checkHeader && !headers.get(limit.checkHeader) ? limit.fallbackValue! : limit.value + const limits = Subscription.getFreeLimits() + const limitValue = + limits.checkHeader && !request.headers.get(limits.checkHeader) ? limits.fallbackValue : limits.dailyRequests const ip = !rawIp.length ? "unknown" : rawIp const now = Date.now() - const intervals = - limit.period === "day" - ? [buildYYYYMMDD(now)] - : [buildYYYYMMDDHH(now), buildYYYYMMDDHH(now - 3_600_000), buildYYYYMMDDHH(now - 7_200_000)] + const interval = buildYYYYMMDD(now) return { track: async () => { await Database.use((tx) => tx .insert(IpRateLimitTable) - .values({ ip, interval: intervals[0], count: 1 }) + .values({ ip, interval, count: 1 }) .onDuplicateKeyUpdate({ set: { count: sql`${IpRateLimitTable.count} + 1` } }), ) }, @@ -30,15 +32,12 @@ export function createRateLimiter(limit: ZenData.RateLimit | undefined, rawIp: s tx .select({ interval: IpRateLimitTable.interval, count: IpRateLimitTable.count }) .from(IpRateLimitTable) - .where(and(eq(IpRateLimitTable.ip, ip), inArray(IpRateLimitTable.interval, intervals))), + .where(and(eq(IpRateLimitTable.ip, ip), inArray(IpRateLimitTable.interval, [interval]))), ) const total = rows.reduce((sum, r) => sum + r.count, 0) logger.debug(`rate limit total: ${total}`) if (total >= limitValue) - throw new FreeUsageLimitError( - `Rate limit exceeded. Please try again later.`, - limit.period === "day" ? getRetryAfterDay(now) : getRetryAfterHour(rows, intervals, limitValue, now), - ) + throw new FreeUsageLimitError(dict["zen.api.error.rateLimitExceeded"], getRetryAfterDay(now)) }, } } @@ -47,37 +46,9 @@ export function getRetryAfterDay(now: number) { return Math.ceil((86_400_000 - (now % 86_400_000)) / 1000) } -export function getRetryAfterHour( - rows: { interval: string; count: number }[], - intervals: string[], - limit: number, - now: number, -) { - const counts = new Map(rows.map((r) => [r.interval, r.count])) - // intervals are ordered newest to oldest: [current, -1h, -2h] - // simulate dropping oldest intervals one at a time - let running = intervals.reduce((sum, i) => sum + (counts.get(i) ?? 0), 0) - for (let i = intervals.length - 1; i >= 0; i--) { - running -= counts.get(intervals[i]) ?? 0 - if (running < limit) { - // interval at index i rolls out of the window (intervals.length - i) hours from the current hour start - const hours = intervals.length - i - return Math.ceil((hours * 3_600_000 - (now % 3_600_000)) / 1000) - } - } - return Math.ceil((3_600_000 - (now % 3_600_000)) / 1000) -} - function buildYYYYMMDD(timestamp: number) { return new Date(timestamp) .toISOString() .replace(/[^0-9]/g, "") .substring(0, 8) } - -function buildYYYYMMDDHH(timestamp: number) { - return new Date(timestamp) - .toISOString() - .replace(/[^0-9]/g, "") - .substring(0, 10) -} diff --git a/packages/console/app/src/routes/zen/util/trialLimiter.ts b/packages/console/app/src/routes/zen/util/trialLimiter.ts index 531e5cf0c3..1ae0ab3292 100644 --- a/packages/console/app/src/routes/zen/util/trialLimiter.ts +++ b/packages/console/app/src/routes/zen/util/trialLimiter.ts @@ -1,21 +1,18 @@ import { Database, eq, sql } from "@opencode-ai/console-core/drizzle/index.js" import { IpTable } from "@opencode-ai/console-core/schema/ip.sql.js" import { UsageInfo } from "./provider/provider" -import { ZenData } from "@opencode-ai/console-core/model.js" +import { Subscription } from "@opencode-ai/console-core/subscription.js" -export function createTrialLimiter(trial: ZenData.Trial | undefined, ip: string, client: string) { - if (!trial) return +export function createTrialLimiter(trialProvider: string | undefined, ip: string) { + if (!trialProvider) return if (!ip) return - const limit = - trial.limits.find((limit) => limit.client === client)?.limit ?? - trial.limits.find((limit) => limit.client === undefined)?.limit - if (!limit) return + const limit = Subscription.getFreeLimits().promoTokens let _isTrial: boolean return { - isTrial: async () => { + check: async () => { const data = await Database.use((tx) => tx .select({ @@ -27,7 +24,7 @@ export function createTrialLimiter(trial: ZenData.Trial | undefined, ip: string, ) _isTrial = (data?.usage ?? 0) < limit - return _isTrial + return _isTrial ? trialProvider : undefined }, track: async (usageInfo: UsageInfo) => { if (!_isTrial) return diff --git a/packages/console/app/src/routes/zen/v1/chat/completions.ts b/packages/console/app/src/routes/zen/v1/chat/completions.ts index 6554591293..e9e05197e2 100644 --- a/packages/console/app/src/routes/zen/v1/chat/completions.ts +++ b/packages/console/app/src/routes/zen/v1/chat/completions.ts @@ -4,6 +4,7 @@ import { handler } from "~/routes/zen/util/handler" export function POST(input: APIEvent) { return handler(input, { format: "oa-compat", + modelList: "full", parseApiKey: (headers: Headers) => headers.get("authorization")?.split(" ")[1], parseModel: (url: string, body: any) => body.model, parseIsStream: (url: string, body: any) => !!body.stream, diff --git a/packages/console/app/src/routes/zen/v1/messages.ts b/packages/console/app/src/routes/zen/v1/messages.ts index 54d223f95a..9c09315a6e 100644 --- a/packages/console/app/src/routes/zen/v1/messages.ts +++ b/packages/console/app/src/routes/zen/v1/messages.ts @@ -4,6 +4,7 @@ import { handler } from "~/routes/zen/util/handler" export function POST(input: APIEvent) { return handler(input, { format: "anthropic", + modelList: "full", parseApiKey: (headers: Headers) => headers.get("x-api-key") ?? undefined, parseModel: (url: string, body: any) => body.model, parseIsStream: (url: string, body: any) => !!body.stream, diff --git a/packages/console/app/src/routes/zen/v1/models.ts b/packages/console/app/src/routes/zen/v1/models.ts index ee2b3ab541..d2592d20b0 100644 --- a/packages/console/app/src/routes/zen/v1/models.ts +++ b/packages/console/app/src/routes/zen/v1/models.ts @@ -17,7 +17,7 @@ export async function OPTIONS(input: APIEvent) { } export async function GET(input: APIEvent) { - const zenData = ZenData.list() + const zenData = ZenData.list("full") const disabledModels = await authenticate() return new Response( @@ -25,6 +25,7 @@ export async function GET(input: APIEvent) { object: "list", data: Object.entries(zenData.models) .filter(([id]) => !disabledModels.includes(id)) + .filter(([id]) => !id.startsWith("alpha-")) .map(([id, _model]) => ({ id, object: "model", diff --git a/packages/console/app/src/routes/zen/v1/models/[model].ts b/packages/console/app/src/routes/zen/v1/models/[model].ts index b20378e379..a4edd5861a 100644 --- a/packages/console/app/src/routes/zen/v1/models/[model].ts +++ b/packages/console/app/src/routes/zen/v1/models/[model].ts @@ -4,6 +4,7 @@ import { handler } from "~/routes/zen/util/handler" export function POST(input: APIEvent) { return handler(input, { format: "google", + modelList: "full", parseApiKey: (headers: Headers) => headers.get("x-goog-api-key") ?? undefined, parseModel: (url: string, body: any) => url.split("/").pop()?.split(":")?.[0] ?? "", parseIsStream: (url: string, body: any) => diff --git a/packages/console/app/src/routes/zen/v1/responses.ts b/packages/console/app/src/routes/zen/v1/responses.ts index a82a667cc7..cae625cf6f 100644 --- a/packages/console/app/src/routes/zen/v1/responses.ts +++ b/packages/console/app/src/routes/zen/v1/responses.ts @@ -4,6 +4,7 @@ import { handler } from "~/routes/zen/util/handler" export function POST(input: APIEvent) { return handler(input, { format: "openai", + modelList: "full", parseApiKey: (headers: Headers) => headers.get("authorization")?.split(" ")[1], parseModel: (url: string, body: any) => body.model, parseIsStream: (url: string, body: any) => !!body.stream, diff --git a/packages/console/app/test/rateLimiter.test.ts b/packages/console/app/test/rateLimiter.test.ts index 864f907d66..5cc97dccf6 100644 --- a/packages/console/app/test/rateLimiter.test.ts +++ b/packages/console/app/test/rateLimiter.test.ts @@ -1,5 +1,5 @@ import { describe, expect, test } from "bun:test" -import { getRetryAfterDay, getRetryAfterHour } from "../src/routes/zen/util/rateLimiter" +import { getRetryAfterDay } from "../src/routes/zen/util/rateLimiter" describe("getRetryAfterDay", () => { test("returns full day at midnight UTC", () => { @@ -17,76 +17,3 @@ describe("getRetryAfterDay", () => { expect(getRetryAfterDay(almost)).toBe(1) }) }) - -describe("getRetryAfterHour", () => { - // 14:30:00 UTC — 30 minutes into the current hour - const now = Date.UTC(2026, 0, 15, 14, 30, 0, 0) - const intervals = ["2026011514", "2026011513", "2026011512"] - - test("waits 3 hours when all usage is in current hour", () => { - const rows = [{ interval: "2026011514", count: 10 }] - // only current hour has usage — it won't leave the window for 3 hours from hour start - // 3 * 3600 - 1800 = 9000s - expect(getRetryAfterHour(rows, intervals, 10, now)).toBe(9000) - }) - - test("waits 1 hour when dropping oldest interval is sufficient", () => { - const rows = [ - { interval: "2026011514", count: 2 }, - { interval: "2026011512", count: 10 }, - ] - // total=12, drop oldest (-2h, count=10) -> 2 < 10 - // hours = 3 - 2 = 1 -> 1 * 3600 - 1800 = 1800s - expect(getRetryAfterHour(rows, intervals, 10, now)).toBe(1800) - }) - - test("waits 2 hours when usage spans oldest two intervals", () => { - const rows = [ - { interval: "2026011513", count: 8 }, - { interval: "2026011512", count: 5 }, - ] - // total=13, drop -2h (5) -> 8, 8 >= 8, drop -1h (8) -> 0 < 8 - // hours = 3 - 1 = 2 -> 2 * 3600 - 1800 = 5400s - expect(getRetryAfterHour(rows, intervals, 8, now)).toBe(5400) - }) - - test("waits 1 hour when oldest interval alone pushes over limit", () => { - const rows = [ - { interval: "2026011514", count: 1 }, - { interval: "2026011513", count: 1 }, - { interval: "2026011512", count: 10 }, - ] - // total=12, drop -2h (10) -> 2 < 10 - // hours = 3 - 2 = 1 -> 1800s - expect(getRetryAfterHour(rows, intervals, 10, now)).toBe(1800) - }) - - test("waits 2 hours when middle interval keeps total over limit", () => { - const rows = [ - { interval: "2026011514", count: 4 }, - { interval: "2026011513", count: 4 }, - { interval: "2026011512", count: 4 }, - ] - // total=12, drop -2h (4) -> 8, 8 >= 5, drop -1h (4) -> 4 < 5 - // hours = 3 - 1 = 2 -> 5400s - expect(getRetryAfterHour(rows, intervals, 5, now)).toBe(5400) - }) - - test("rounds up to nearest second", () => { - const offset = Date.UTC(2026, 0, 15, 14, 30, 0, 500) - const rows = [ - { interval: "2026011514", count: 2 }, - { interval: "2026011512", count: 10 }, - ] - // hours=1 -> 3_600_000 - 1_800_500 = 1_799_500ms -> ceil(1799.5) = 1800 - expect(getRetryAfterHour(rows, intervals, 10, offset)).toBe(1800) - }) - - test("fallback returns time until next hour when rows are empty", () => { - // edge case: rows empty but function called (shouldn't happen in practice) - // loop drops all zeros, running stays 0 which is < any positive limit on first iteration - const rows: { interval: string; count: number }[] = [] - // drop -2h (0) -> 0 < 1 -> hours = 3 - 2 = 1 -> 1800s - expect(getRetryAfterHour(rows, intervals, 1, now)).toBe(1800) - }) -}) diff --git a/packages/console/core/migrations/0000_fluffy_raza.sql b/packages/console/core/migrations/20250902065410_fluffy_raza/migration.sql similarity index 100% rename from packages/console/core/migrations/0000_fluffy_raza.sql rename to packages/console/core/migrations/20250902065410_fluffy_raza/migration.sql diff --git a/packages/console/core/migrations/20250902065410_fluffy_raza/snapshot.json b/packages/console/core/migrations/20250902065410_fluffy_raza/snapshot.json new file mode 100644 index 0000000000..6b26128c66 --- /dev/null +++ b/packages/console/core/migrations/20250902065410_fluffy_raza/snapshot.json @@ -0,0 +1,967 @@ +{ + "version": "6", + "id": "aee779c5-db1d-4655-95ec-6451c18455be", + "prevIds": ["00000000-0000-0000-0000-000000000000"], + "dialect": "mysql", + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "account", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "account", + "entityType": "columns" + }, + { + "name": "billing", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(4)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_last4", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "balance", + "table": "billing", + "entityType": "columns" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload", + "table": "billing", + "entityType": "columns" + }, + { + "name": "payment", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "amount", + "table": "payment", + "entityType": "columns" + }, + { + "name": "usage", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "input_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "output_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reasoning_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_read_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cost", + "table": "usage", + "entityType": "columns" + }, + { + "name": "key", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "key", + "entityType": "columns" + }, + { + "type": "text", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "user_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_used", + "table": "key", + "entityType": "columns" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_seen", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "color", + "table": "user", + "entityType": "columns" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "slug", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "workspace", + "entityType": "columns" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "email", + "table": "account", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "billing", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "payment", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "usage", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "key", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_key", + "table": "key", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "key", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "user", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "slug", + "table": "workspace", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "workspace", + "entityType": "pks" + } + ], + "renames": [] +} diff --git a/packages/console/core/migrations/0001_serious_whistler.sql b/packages/console/core/migrations/20250903035359_serious_whistler/migration.sql similarity index 100% rename from packages/console/core/migrations/0001_serious_whistler.sql rename to packages/console/core/migrations/20250903035359_serious_whistler/migration.sql diff --git a/packages/console/core/migrations/20250903035359_serious_whistler/snapshot.json b/packages/console/core/migrations/20250903035359_serious_whistler/snapshot.json new file mode 100644 index 0000000000..8e0af76b5b --- /dev/null +++ b/packages/console/core/migrations/20250903035359_serious_whistler/snapshot.json @@ -0,0 +1,967 @@ +{ + "version": "6", + "id": "79b7ee25-1c1c-41ff-9bbf-754af257102b", + "prevIds": ["aee779c5-db1d-4655-95ec-6451c18455be"], + "dialect": "mysql", + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "account", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "account", + "entityType": "columns" + }, + { + "name": "billing", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(4)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_last4", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "balance", + "table": "billing", + "entityType": "columns" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload", + "table": "billing", + "entityType": "columns" + }, + { + "name": "payment", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "amount", + "table": "payment", + "entityType": "columns" + }, + { + "name": "usage", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "input_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "output_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reasoning_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_read_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cost", + "table": "usage", + "entityType": "columns" + }, + { + "name": "key", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "key", + "entityType": "columns" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "actor", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_used", + "table": "key", + "entityType": "columns" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_seen", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "color", + "table": "user", + "entityType": "columns" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "slug", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "workspace", + "entityType": "columns" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "email", + "table": "account", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "billing", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "payment", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "usage", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "key", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_key", + "table": "key", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "key", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "user", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "slug", + "table": "workspace", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "workspace", + "entityType": "pks" + } + ], + "renames": [] +} diff --git a/packages/console/core/migrations/0002_violet_loners.sql b/packages/console/core/migrations/20250911133331_violet_loners/migration.sql similarity index 100% rename from packages/console/core/migrations/0002_violet_loners.sql rename to packages/console/core/migrations/20250911133331_violet_loners/migration.sql diff --git a/packages/console/core/migrations/20250911133331_violet_loners/snapshot.json b/packages/console/core/migrations/20250911133331_violet_loners/snapshot.json new file mode 100644 index 0000000000..27f5a5dbbd --- /dev/null +++ b/packages/console/core/migrations/20250911133331_violet_loners/snapshot.json @@ -0,0 +1,981 @@ +{ + "version": "6", + "id": "9f51ef52-31ac-4ace-8b6d-39b35efe9c81", + "prevIds": ["79b7ee25-1c1c-41ff-9bbf-754af257102b"], + "dialect": "mysql", + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "account", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "account", + "entityType": "columns" + }, + { + "name": "billing", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(4)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_last4", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "balance", + "table": "billing", + "entityType": "columns" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload", + "table": "billing", + "entityType": "columns" + }, + { + "name": "payment", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "amount", + "table": "payment", + "entityType": "columns" + }, + { + "name": "usage", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "input_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "output_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reasoning_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_read_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cost", + "table": "usage", + "entityType": "columns" + }, + { + "name": "key", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "key", + "entityType": "columns" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "actor", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "old_name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_used", + "table": "key", + "entityType": "columns" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_seen", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "color", + "table": "user", + "entityType": "columns" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "slug", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "workspace", + "entityType": "columns" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "email", + "table": "account", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "billing", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "payment", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "usage", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "key", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_key", + "table": "key", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "key", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "user", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "slug", + "table": "workspace", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "workspace", + "entityType": "pks" + } + ], + "renames": [] +} diff --git a/packages/console/core/migrations/0003_dusty_clint_barton.sql b/packages/console/core/migrations/20250911141957_dusty_clint_barton/migration.sql similarity index 100% rename from packages/console/core/migrations/0003_dusty_clint_barton.sql rename to packages/console/core/migrations/20250911141957_dusty_clint_barton/migration.sql diff --git a/packages/console/core/migrations/20250911141957_dusty_clint_barton/snapshot.json b/packages/console/core/migrations/20250911141957_dusty_clint_barton/snapshot.json new file mode 100644 index 0000000000..da412fed41 --- /dev/null +++ b/packages/console/core/migrations/20250911141957_dusty_clint_barton/snapshot.json @@ -0,0 +1,1001 @@ +{ + "version": "6", + "id": "26cebd59-f553-441c-a2b2-2f9578a0ad2b", + "prevIds": ["9f51ef52-31ac-4ace-8b6d-39b35efe9c81"], + "dialect": "mysql", + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "account", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "account", + "entityType": "columns" + }, + { + "name": "billing", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(4)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_last4", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "balance", + "table": "billing", + "entityType": "columns" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload", + "table": "billing", + "entityType": "columns" + }, + { + "name": "payment", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "amount", + "table": "payment", + "entityType": "columns" + }, + { + "name": "usage", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "input_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "output_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reasoning_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_read_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cost", + "table": "usage", + "entityType": "columns" + }, + { + "name": "key", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "key", + "entityType": "columns" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "actor", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "old_name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_used", + "table": "key", + "entityType": "columns" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_seen", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "color", + "table": "user", + "entityType": "columns" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "slug", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "workspace", + "entityType": "columns" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "email", + "table": "account", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "billing", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "payment", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "usage", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "key", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_key", + "table": "key", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "name", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "name", + "table": "key", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "key", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "user", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "slug", + "table": "workspace", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "workspace", + "entityType": "pks" + } + ], + "renames": [] +} diff --git a/packages/console/core/migrations/0004_first_mockingbird.sql b/packages/console/core/migrations/20250911214917_first_mockingbird/migration.sql similarity index 100% rename from packages/console/core/migrations/0004_first_mockingbird.sql rename to packages/console/core/migrations/20250911214917_first_mockingbird/migration.sql diff --git a/packages/console/core/migrations/20250911214917_first_mockingbird/snapshot.json b/packages/console/core/migrations/20250911214917_first_mockingbird/snapshot.json new file mode 100644 index 0000000000..e0c84bb2d3 --- /dev/null +++ b/packages/console/core/migrations/20250911214917_first_mockingbird/snapshot.json @@ -0,0 +1,1015 @@ +{ + "version": "6", + "id": "06dc6226-bfbb-4ccc-b4bc-f26070c3bed5", + "prevIds": ["26cebd59-f553-441c-a2b2-2f9578a0ad2b"], + "dialect": "mysql", + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "account", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "account", + "entityType": "columns" + }, + { + "name": "billing", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(4)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_last4", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "balance", + "table": "billing", + "entityType": "columns" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload", + "table": "billing", + "entityType": "columns" + }, + { + "name": "payment", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "amount", + "table": "payment", + "entityType": "columns" + }, + { + "name": "usage", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "input_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "output_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reasoning_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_read_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cost", + "table": "usage", + "entityType": "columns" + }, + { + "name": "key", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "key", + "entityType": "columns" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "actor", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "old_name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_used", + "table": "key", + "entityType": "columns" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_seen", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "color", + "table": "user", + "entityType": "columns" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "slug", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "workspace", + "entityType": "columns" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "email", + "table": "account", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "billing", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "payment", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "usage", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "key", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_key", + "table": "key", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "name", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "name", + "table": "key", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "key", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "user", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "slug", + "table": "workspace", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "workspace", + "entityType": "pks" + } + ], + "renames": [] +} diff --git a/packages/console/core/migrations/0005_jazzy_skrulls.sql b/packages/console/core/migrations/20250911231144_jazzy_skrulls/migration.sql similarity index 100% rename from packages/console/core/migrations/0005_jazzy_skrulls.sql rename to packages/console/core/migrations/20250911231144_jazzy_skrulls/migration.sql diff --git a/packages/console/core/migrations/20250911231144_jazzy_skrulls/snapshot.json b/packages/console/core/migrations/20250911231144_jazzy_skrulls/snapshot.json new file mode 100644 index 0000000000..57ef218deb --- /dev/null +++ b/packages/console/core/migrations/20250911231144_jazzy_skrulls/snapshot.json @@ -0,0 +1,1015 @@ +{ + "version": "6", + "id": "d13af80e-3c70-4866-8f14-48e7ff6ff0ff", + "prevIds": ["06dc6226-bfbb-4ccc-b4bc-f26070c3bed5"], + "dialect": "mysql", + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "account", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "account", + "entityType": "columns" + }, + { + "name": "billing", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(4)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_last4", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "balance", + "table": "billing", + "entityType": "columns" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload", + "table": "billing", + "entityType": "columns" + }, + { + "name": "payment", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "amount", + "table": "payment", + "entityType": "columns" + }, + { + "name": "usage", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "input_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "output_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reasoning_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_read_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cost", + "table": "usage", + "entityType": "columns" + }, + { + "name": "key", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "key", + "entityType": "columns" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "actor", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "old_name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_used", + "table": "key", + "entityType": "columns" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_seen", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "color", + "table": "user", + "entityType": "columns" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "slug", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "workspace", + "entityType": "columns" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "email", + "table": "account", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "billing", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "payment", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "usage", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "key", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_key", + "table": "key", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "name", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "name", + "table": "key", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "key", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "user", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "slug", + "table": "workspace", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "workspace", + "entityType": "pks" + } + ], + "renames": [] +} diff --git a/packages/console/core/migrations/0006_parallel_gauntlet.sql b/packages/console/core/migrations/20250912021148_parallel_gauntlet/migration.sql similarity index 100% rename from packages/console/core/migrations/0006_parallel_gauntlet.sql rename to packages/console/core/migrations/20250912021148_parallel_gauntlet/migration.sql diff --git a/packages/console/core/migrations/20250912021148_parallel_gauntlet/snapshot.json b/packages/console/core/migrations/20250912021148_parallel_gauntlet/snapshot.json new file mode 100644 index 0000000000..75472504c3 --- /dev/null +++ b/packages/console/core/migrations/20250912021148_parallel_gauntlet/snapshot.json @@ -0,0 +1,1043 @@ +{ + "version": "6", + "id": "b0ad4b11-b607-46c7-8e2d-3b9823cdc5f7", + "prevIds": ["d13af80e-3c70-4866-8f14-48e7ff6ff0ff"], + "dialect": "mysql", + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "account", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "account", + "entityType": "columns" + }, + { + "name": "billing", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(4)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_last4", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "balance", + "table": "billing", + "entityType": "columns" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload", + "table": "billing", + "entityType": "columns" + }, + { + "name": "payment", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "amount", + "table": "payment", + "entityType": "columns" + }, + { + "name": "usage", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "input_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "output_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reasoning_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_read_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_5m_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_1h_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cost", + "table": "usage", + "entityType": "columns" + }, + { + "name": "key", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "key", + "entityType": "columns" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "actor", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "old_name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_used", + "table": "key", + "entityType": "columns" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_seen", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "color", + "table": "user", + "entityType": "columns" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "slug", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "workspace", + "entityType": "columns" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "email", + "table": "account", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "billing", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "payment", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "usage", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "key", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_key", + "table": "key", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "name", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "name", + "table": "key", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "key", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "user", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "slug", + "table": "workspace", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "workspace", + "entityType": "pks" + } + ], + "renames": [] +} diff --git a/packages/console/core/migrations/0007_familiar_nightshade.sql b/packages/console/core/migrations/20250912161749_familiar_nightshade/migration.sql similarity index 100% rename from packages/console/core/migrations/0007_familiar_nightshade.sql rename to packages/console/core/migrations/20250912161749_familiar_nightshade/migration.sql diff --git a/packages/console/core/migrations/20250912161749_familiar_nightshade/snapshot.json b/packages/console/core/migrations/20250912161749_familiar_nightshade/snapshot.json new file mode 100644 index 0000000000..5aa25052ab --- /dev/null +++ b/packages/console/core/migrations/20250912161749_familiar_nightshade/snapshot.json @@ -0,0 +1,1029 @@ +{ + "version": "6", + "id": "91067cc9-d492-47b3-932a-42dcc0920b3c", + "prevIds": ["b0ad4b11-b607-46c7-8e2d-3b9823cdc5f7"], + "dialect": "mysql", + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "account", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "account", + "entityType": "columns" + }, + { + "name": "billing", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(4)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_last4", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "balance", + "table": "billing", + "entityType": "columns" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload", + "table": "billing", + "entityType": "columns" + }, + { + "name": "payment", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "amount", + "table": "payment", + "entityType": "columns" + }, + { + "name": "usage", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "input_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "output_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reasoning_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_read_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_5m_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_1h_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cost", + "table": "usage", + "entityType": "columns" + }, + { + "name": "key", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "key", + "entityType": "columns" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "actor", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "old_name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_used", + "table": "key", + "entityType": "columns" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_seen", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "color", + "table": "user", + "entityType": "columns" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "slug", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "workspace", + "entityType": "columns" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "email", + "table": "account", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "billing", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "payment", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "usage", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "key", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_key", + "table": "key", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "name", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "name", + "table": "key", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "key", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "user", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "slug", + "table": "workspace", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "workspace", + "entityType": "pks" + } + ], + "renames": [] +} diff --git a/packages/console/core/migrations/0008_eminent_ultimatum.sql b/packages/console/core/migrations/20250914213824_eminent_ultimatum/migration.sql similarity index 100% rename from packages/console/core/migrations/0008_eminent_ultimatum.sql rename to packages/console/core/migrations/20250914213824_eminent_ultimatum/migration.sql diff --git a/packages/console/core/migrations/20250914213824_eminent_ultimatum/snapshot.json b/packages/console/core/migrations/20250914213824_eminent_ultimatum/snapshot.json new file mode 100644 index 0000000000..f7606b7862 --- /dev/null +++ b/packages/console/core/migrations/20250914213824_eminent_ultimatum/snapshot.json @@ -0,0 +1,1043 @@ +{ + "version": "6", + "id": "3e080fc0-9efd-411f-b764-ed3aa4abcee5", + "prevIds": ["91067cc9-d492-47b3-932a-42dcc0920b3c"], + "dialect": "mysql", + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "account", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "account", + "entityType": "columns" + }, + { + "name": "billing", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(4)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_last4", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "balance", + "table": "billing", + "entityType": "columns" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_locked_till", + "table": "billing", + "entityType": "columns" + }, + { + "name": "payment", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "amount", + "table": "payment", + "entityType": "columns" + }, + { + "name": "usage", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "input_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "output_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reasoning_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_read_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_5m_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_1h_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cost", + "table": "usage", + "entityType": "columns" + }, + { + "name": "key", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "key", + "entityType": "columns" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "actor", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "old_name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_used", + "table": "key", + "entityType": "columns" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_seen", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "color", + "table": "user", + "entityType": "columns" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "slug", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "workspace", + "entityType": "columns" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "email", + "table": "account", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "billing", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "payment", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "usage", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "key", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_key", + "table": "key", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "name", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "name", + "table": "key", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "key", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "user", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "slug", + "table": "workspace", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "workspace", + "entityType": "pks" + } + ], + "renames": [] +} diff --git a/packages/console/core/migrations/0009_redundant_piledriver.sql b/packages/console/core/migrations/20250914222302_redundant_piledriver/migration.sql similarity index 100% rename from packages/console/core/migrations/0009_redundant_piledriver.sql rename to packages/console/core/migrations/20250914222302_redundant_piledriver/migration.sql diff --git a/packages/console/core/migrations/20250914222302_redundant_piledriver/snapshot.json b/packages/console/core/migrations/20250914222302_redundant_piledriver/snapshot.json new file mode 100644 index 0000000000..9f4163f61c --- /dev/null +++ b/packages/console/core/migrations/20250914222302_redundant_piledriver/snapshot.json @@ -0,0 +1,1057 @@ +{ + "version": "6", + "id": "b0019e1e-d365-4f67-be3d-a2e69bdddc04", + "prevIds": ["3e080fc0-9efd-411f-b764-ed3aa4abcee5"], + "dialect": "mysql", + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "account", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "account", + "entityType": "columns" + }, + { + "name": "billing", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(4)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_last4", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "balance", + "table": "billing", + "entityType": "columns" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_locked_till", + "table": "billing", + "entityType": "columns" + }, + { + "name": "payment", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "amount", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "error", + "table": "payment", + "entityType": "columns" + }, + { + "name": "usage", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "input_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "output_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reasoning_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_read_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_5m_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_1h_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cost", + "table": "usage", + "entityType": "columns" + }, + { + "name": "key", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "key", + "entityType": "columns" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "actor", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "old_name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_used", + "table": "key", + "entityType": "columns" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_seen", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "color", + "table": "user", + "entityType": "columns" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "slug", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "workspace", + "entityType": "columns" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "email", + "table": "account", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "billing", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "payment", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "usage", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "key", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_key", + "table": "key", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "name", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "name", + "table": "key", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "key", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "user", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "slug", + "table": "workspace", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "workspace", + "entityType": "pks" + } + ], + "renames": [] +} diff --git a/packages/console/core/migrations/0010_needy_sue_storm.sql b/packages/console/core/migrations/20250914232505_needy_sue_storm/migration.sql similarity index 100% rename from packages/console/core/migrations/0010_needy_sue_storm.sql rename to packages/console/core/migrations/20250914232505_needy_sue_storm/migration.sql diff --git a/packages/console/core/migrations/20250914232505_needy_sue_storm/snapshot.json b/packages/console/core/migrations/20250914232505_needy_sue_storm/snapshot.json new file mode 100644 index 0000000000..835c27e597 --- /dev/null +++ b/packages/console/core/migrations/20250914232505_needy_sue_storm/snapshot.json @@ -0,0 +1,1073 @@ +{ + "version": "6", + "id": "1f08bd5a-436d-4905-a585-87b156847402", + "prevIds": ["b0019e1e-d365-4f67-be3d-a2e69bdddc04"], + "dialect": "mysql", + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "account", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "account", + "entityType": "columns" + }, + { + "name": "billing", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(4)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_last4", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "balance", + "table": "billing", + "entityType": "columns" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_locked_till", + "table": "billing", + "entityType": "columns" + }, + { + "name": "payment", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "amount", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "error", + "table": "payment", + "entityType": "columns" + }, + { + "name": "usage", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "input_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "output_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reasoning_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_read_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_5m_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_1h_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cost", + "table": "usage", + "entityType": "columns" + }, + { + "name": "key", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "key", + "entityType": "columns" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "actor", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "old_name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_used", + "table": "key", + "entityType": "columns" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_seen", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "color", + "table": "user", + "entityType": "columns" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "slug", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "workspace", + "entityType": "columns" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "email", + "table": "account", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "customer_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_customer_id", + "table": "billing", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "billing", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "payment", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "usage", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "key", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_key", + "table": "key", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "name", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "name", + "table": "key", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "key", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "user", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "slug", + "table": "workspace", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "workspace", + "entityType": "pks" + } + ], + "renames": [] +} diff --git a/packages/console/core/migrations/0011_freezing_phil_sheldon.sql b/packages/console/core/migrations/20250915150801_freezing_phil_sheldon/migration.sql similarity index 100% rename from packages/console/core/migrations/0011_freezing_phil_sheldon.sql rename to packages/console/core/migrations/20250915150801_freezing_phil_sheldon/migration.sql diff --git a/packages/console/core/migrations/20250915150801_freezing_phil_sheldon/snapshot.json b/packages/console/core/migrations/20250915150801_freezing_phil_sheldon/snapshot.json new file mode 100644 index 0000000000..e2f48178a8 --- /dev/null +++ b/packages/console/core/migrations/20250915150801_freezing_phil_sheldon/snapshot.json @@ -0,0 +1,1087 @@ +{ + "version": "6", + "id": "cd9c94c4-9167-4346-b716-1bd0cff10ffc", + "prevIds": ["1f08bd5a-436d-4905-a585-87b156847402"], + "dialect": "mysql", + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "account", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "account", + "entityType": "columns" + }, + { + "name": "billing", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(4)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_last4", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "balance", + "table": "billing", + "entityType": "columns" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_locked_till", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "last_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_last_error", + "table": "billing", + "entityType": "columns" + }, + { + "name": "payment", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "amount", + "table": "payment", + "entityType": "columns" + }, + { + "name": "usage", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "input_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "output_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reasoning_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_read_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_5m_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_1h_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cost", + "table": "usage", + "entityType": "columns" + }, + { + "name": "key", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "key", + "entityType": "columns" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "actor", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "old_name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_used", + "table": "key", + "entityType": "columns" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_seen", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "color", + "table": "user", + "entityType": "columns" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "slug", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "workspace", + "entityType": "columns" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "email", + "table": "account", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "customer_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_customer_id", + "table": "billing", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "billing", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "payment", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "usage", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "key", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_key", + "table": "key", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "name", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "name", + "table": "key", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "key", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "user", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "slug", + "table": "workspace", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "workspace", + "entityType": "pks" + } + ], + "renames": [] +} diff --git a/packages/console/core/migrations/0012_bright_photon.sql b/packages/console/core/migrations/20250915172014_bright_photon/migration.sql similarity index 100% rename from packages/console/core/migrations/0012_bright_photon.sql rename to packages/console/core/migrations/20250915172014_bright_photon/migration.sql diff --git a/packages/console/core/migrations/20250915172014_bright_photon/snapshot.json b/packages/console/core/migrations/20250915172014_bright_photon/snapshot.json new file mode 100644 index 0000000000..eae20d54c0 --- /dev/null +++ b/packages/console/core/migrations/20250915172014_bright_photon/snapshot.json @@ -0,0 +1,1129 @@ +{ + "version": "6", + "id": "ba801b30-747a-433e-ab43-b407c961a24c", + "prevIds": ["cd9c94c4-9167-4346-b716-1bd0cff10ffc"], + "dialect": "mysql", + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "account", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "account", + "entityType": "columns" + }, + { + "name": "billing", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(4)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_last4", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "balance", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_locked_till", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "last_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_last_error", + "table": "billing", + "entityType": "columns" + }, + { + "name": "payment", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "amount", + "table": "payment", + "entityType": "columns" + }, + { + "name": "usage", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "input_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "output_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reasoning_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_read_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_5m_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_1h_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cost", + "table": "usage", + "entityType": "columns" + }, + { + "name": "key", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "key", + "entityType": "columns" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "actor", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "old_name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_used", + "table": "key", + "entityType": "columns" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_seen", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "color", + "table": "user", + "entityType": "columns" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "slug", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "workspace", + "entityType": "columns" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "email", + "table": "account", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "customer_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_customer_id", + "table": "billing", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "billing", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "payment", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "usage", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "key", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_key", + "table": "key", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "name", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "name", + "table": "key", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "key", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "user", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "slug", + "table": "workspace", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "workspace", + "entityType": "pks" + } + ], + "renames": [] +} diff --git a/packages/console/core/migrations/0013_absurd_hobgoblin.sql b/packages/console/core/migrations/20250915172258_absurd_hobgoblin/migration.sql similarity index 100% rename from packages/console/core/migrations/0013_absurd_hobgoblin.sql rename to packages/console/core/migrations/20250915172258_absurd_hobgoblin/migration.sql diff --git a/packages/console/core/migrations/20250915172258_absurd_hobgoblin/snapshot.json b/packages/console/core/migrations/20250915172258_absurd_hobgoblin/snapshot.json new file mode 100644 index 0000000000..6c0a9b3836 --- /dev/null +++ b/packages/console/core/migrations/20250915172258_absurd_hobgoblin/snapshot.json @@ -0,0 +1,1129 @@ +{ + "version": "6", + "id": "28336c91-553c-4d1d-9875-1ee761e47582", + "prevIds": ["ba801b30-747a-433e-ab43-b407c961a24c"], + "dialect": "mysql", + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "account", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "account", + "entityType": "columns" + }, + { + "name": "billing", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(4)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_last4", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "balance", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_locked_till", + "table": "billing", + "entityType": "columns" + }, + { + "name": "payment", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "amount", + "table": "payment", + "entityType": "columns" + }, + { + "name": "usage", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "input_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "output_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reasoning_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_read_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_5m_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_1h_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cost", + "table": "usage", + "entityType": "columns" + }, + { + "name": "key", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "key", + "entityType": "columns" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "actor", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "old_name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_used", + "table": "key", + "entityType": "columns" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_seen", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "color", + "table": "user", + "entityType": "columns" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "slug", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "workspace", + "entityType": "columns" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "email", + "table": "account", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "customer_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_customer_id", + "table": "billing", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "billing", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "payment", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "usage", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "key", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_key", + "table": "key", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "name", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "name", + "table": "key", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "key", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "user", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "slug", + "table": "workspace", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "workspace", + "entityType": "pks" + } + ], + "renames": [] +} diff --git a/packages/console/core/migrations/0014_demonic_princess_powerful.sql b/packages/console/core/migrations/20250919135159_demonic_princess_powerful/migration.sql similarity index 100% rename from packages/console/core/migrations/0014_demonic_princess_powerful.sql rename to packages/console/core/migrations/20250919135159_demonic_princess_powerful/migration.sql diff --git a/packages/console/core/migrations/20250919135159_demonic_princess_powerful/snapshot.json b/packages/console/core/migrations/20250919135159_demonic_princess_powerful/snapshot.json new file mode 100644 index 0000000000..c94526e91a --- /dev/null +++ b/packages/console/core/migrations/20250919135159_demonic_princess_powerful/snapshot.json @@ -0,0 +1,1143 @@ +{ + "version": "6", + "id": "12189a4e-5083-4b17-b8e3-8279c9a3e61a", + "prevIds": ["28336c91-553c-4d1d-9875-1ee761e47582"], + "dialect": "mysql", + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "account", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "account", + "entityType": "columns" + }, + { + "name": "billing", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(4)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_last4", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "balance", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_locked_till", + "table": "billing", + "entityType": "columns" + }, + { + "name": "payment", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "amount", + "table": "payment", + "entityType": "columns" + }, + { + "name": "usage", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "input_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "output_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reasoning_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_read_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_5m_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_1h_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cost", + "table": "usage", + "entityType": "columns" + }, + { + "name": "key", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "key", + "entityType": "columns" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "actor", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "old_name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_used", + "table": "key", + "entityType": "columns" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_seen", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "color", + "table": "user", + "entityType": "columns" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "slug", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "data_share", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "workspace", + "entityType": "columns" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "email", + "table": "account", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "customer_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_customer_id", + "table": "billing", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "billing", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "payment", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "usage", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "key", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_key", + "table": "key", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "name", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "name", + "table": "key", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "key", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "user", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "slug", + "table": "workspace", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "workspace", + "entityType": "pks" + } + ], + "renames": [] +} diff --git a/packages/console/core/migrations/0015_cloudy_revanche.sql b/packages/console/core/migrations/20250921042124_cloudy_revanche/migration.sql similarity index 100% rename from packages/console/core/migrations/0015_cloudy_revanche.sql rename to packages/console/core/migrations/20250921042124_cloudy_revanche/migration.sql diff --git a/packages/console/core/migrations/20250921042124_cloudy_revanche/snapshot.json b/packages/console/core/migrations/20250921042124_cloudy_revanche/snapshot.json new file mode 100644 index 0000000000..9de034489b --- /dev/null +++ b/packages/console/core/migrations/20250921042124_cloudy_revanche/snapshot.json @@ -0,0 +1,1129 @@ +{ + "version": "6", + "id": "7f3989cb-3e8b-430e-a0f5-f87051d1d824", + "prevIds": ["12189a4e-5083-4b17-b8e3-8279c9a3e61a"], + "dialect": "mysql", + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "account", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "account", + "entityType": "columns" + }, + { + "name": "billing", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(4)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_last4", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "balance", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_locked_till", + "table": "billing", + "entityType": "columns" + }, + { + "name": "payment", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "amount", + "table": "payment", + "entityType": "columns" + }, + { + "name": "usage", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "input_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "output_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reasoning_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_read_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_5m_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_1h_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cost", + "table": "usage", + "entityType": "columns" + }, + { + "name": "key", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "key", + "entityType": "columns" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "actor", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "old_name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_used", + "table": "key", + "entityType": "columns" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_seen", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "color", + "table": "user", + "entityType": "columns" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "slug", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "workspace", + "entityType": "columns" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "email", + "table": "account", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "customer_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_customer_id", + "table": "billing", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "billing", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "payment", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "usage", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "key", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_key", + "table": "key", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "name", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "name", + "table": "key", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "key", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "user", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "slug", + "table": "workspace", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "workspace", + "entityType": "pks" + } + ], + "renames": [] +} diff --git a/packages/console/core/migrations/0016_cold_la_nuit.sql b/packages/console/core/migrations/20250923213126_cold_la_nuit/migration.sql similarity index 100% rename from packages/console/core/migrations/0016_cold_la_nuit.sql rename to packages/console/core/migrations/20250923213126_cold_la_nuit/migration.sql diff --git a/packages/console/core/migrations/20250923213126_cold_la_nuit/snapshot.json b/packages/console/core/migrations/20250923213126_cold_la_nuit/snapshot.json new file mode 100644 index 0000000000..8f513193ed --- /dev/null +++ b/packages/console/core/migrations/20250923213126_cold_la_nuit/snapshot.json @@ -0,0 +1,1143 @@ +{ + "version": "6", + "id": "45b67fb4-77ce-4aa2-b883-1971429c69f5", + "prevIds": ["7f3989cb-3e8b-430e-a0f5-f87051d1d824"], + "dialect": "mysql", + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "account", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "account", + "entityType": "columns" + }, + { + "name": "billing", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(4)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_last4", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "balance", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_locked_till", + "table": "billing", + "entityType": "columns" + }, + { + "name": "payment", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "amount", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_refunded", + "table": "payment", + "entityType": "columns" + }, + { + "name": "usage", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "input_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "output_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reasoning_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_read_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_5m_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_1h_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cost", + "table": "usage", + "entityType": "columns" + }, + { + "name": "key", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "key", + "entityType": "columns" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "actor", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "old_name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_used", + "table": "key", + "entityType": "columns" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_seen", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "color", + "table": "user", + "entityType": "columns" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "slug", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "workspace", + "entityType": "columns" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "email", + "table": "account", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "customer_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_customer_id", + "table": "billing", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "billing", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "payment", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "usage", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "key", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_key", + "table": "key", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "name", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "name", + "table": "key", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "key", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "user", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "slug", + "table": "workspace", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "workspace", + "entityType": "pks" + } + ], + "renames": [] +} diff --git a/packages/console/core/migrations/0017_woozy_thaddeus_ross.sql b/packages/console/core/migrations/20250924230623_woozy_thaddeus_ross/migration.sql similarity index 100% rename from packages/console/core/migrations/0017_woozy_thaddeus_ross.sql rename to packages/console/core/migrations/20250924230623_woozy_thaddeus_ross/migration.sql diff --git a/packages/console/core/migrations/20250924230623_woozy_thaddeus_ross/snapshot.json b/packages/console/core/migrations/20250924230623_woozy_thaddeus_ross/snapshot.json new file mode 100644 index 0000000000..4a6758c6be --- /dev/null +++ b/packages/console/core/migrations/20250924230623_woozy_thaddeus_ross/snapshot.json @@ -0,0 +1,1157 @@ +{ + "version": "6", + "id": "100a21cf-ff9c-476f-bf7d-100c1824b2b2", + "prevIds": ["45b67fb4-77ce-4aa2-b883-1971429c69f5"], + "dialect": "mysql", + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "account", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "account", + "entityType": "columns" + }, + { + "name": "billing", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(4)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_last4", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "balance", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_locked_till", + "table": "billing", + "entityType": "columns" + }, + { + "name": "payment", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "invoice_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "amount", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_refunded", + "table": "payment", + "entityType": "columns" + }, + { + "name": "usage", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "input_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "output_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reasoning_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_read_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_5m_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_1h_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cost", + "table": "usage", + "entityType": "columns" + }, + { + "name": "key", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "key", + "entityType": "columns" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "actor", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "old_name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_used", + "table": "key", + "entityType": "columns" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_seen", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "color", + "table": "user", + "entityType": "columns" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "slug", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "workspace", + "entityType": "columns" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "email", + "table": "account", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "customer_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_customer_id", + "table": "billing", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "billing", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "payment", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "usage", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "key", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_key", + "table": "key", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "name", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "name", + "table": "key", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "key", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "user", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "slug", + "table": "workspace", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "workspace", + "entityType": "pks" + } + ], + "renames": [] +} diff --git a/packages/console/core/migrations/0018_nervous_iron_lad.sql b/packages/console/core/migrations/20250928163425_nervous_iron_lad/migration.sql similarity index 100% rename from packages/console/core/migrations/0018_nervous_iron_lad.sql rename to packages/console/core/migrations/20250928163425_nervous_iron_lad/migration.sql diff --git a/packages/console/core/migrations/20250928163425_nervous_iron_lad/snapshot.json b/packages/console/core/migrations/20250928163425_nervous_iron_lad/snapshot.json new file mode 100644 index 0000000000..a23bd3c8ef --- /dev/null +++ b/packages/console/core/migrations/20250928163425_nervous_iron_lad/snapshot.json @@ -0,0 +1,1185 @@ +{ + "version": "6", + "id": "e9c91c2d-787d-4234-b98d-1620e4ce80e1", + "prevIds": ["100a21cf-ff9c-476f-bf7d-100c1824b2b2"], + "dialect": "mysql", + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "account", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "account", + "entityType": "columns" + }, + { + "name": "billing", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(4)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_last4", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "balance", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_locked_till", + "table": "billing", + "entityType": "columns" + }, + { + "name": "payment", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "invoice_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "amount", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_refunded", + "table": "payment", + "entityType": "columns" + }, + { + "name": "usage", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "input_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "output_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reasoning_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_read_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_5m_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_1h_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cost", + "table": "usage", + "entityType": "columns" + }, + { + "name": "key", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "key", + "entityType": "columns" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "actor", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "old_name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_used", + "table": "key", + "entityType": "columns" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_seen", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_joined", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "color", + "table": "user", + "entityType": "columns" + }, + { + "type": "enum('admin','member')", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "role", + "table": "user", + "entityType": "columns" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "slug", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "workspace", + "entityType": "columns" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "email", + "table": "account", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "customer_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_customer_id", + "table": "billing", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "billing", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "payment", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "usage", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "key", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_key", + "table": "key", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "name", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "name", + "table": "key", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "key", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "user", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "slug", + "table": "workspace", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "workspace", + "entityType": "pks" + } + ], + "renames": [] +} diff --git a/packages/console/core/migrations/0019_dazzling_cable.sql b/packages/console/core/migrations/20250928235456_dazzling_cable/migration.sql similarity index 100% rename from packages/console/core/migrations/0019_dazzling_cable.sql rename to packages/console/core/migrations/20250928235456_dazzling_cable/migration.sql diff --git a/packages/console/core/migrations/20250928235456_dazzling_cable/snapshot.json b/packages/console/core/migrations/20250928235456_dazzling_cable/snapshot.json new file mode 100644 index 0000000000..4f52f4b0b5 --- /dev/null +++ b/packages/console/core/migrations/20250928235456_dazzling_cable/snapshot.json @@ -0,0 +1,1185 @@ +{ + "version": "6", + "id": "a2bb7222-561c-45f0-8939-8ef9b8e57bb3", + "prevIds": ["e9c91c2d-787d-4234-b98d-1620e4ce80e1"], + "dialect": "mysql", + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "account", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "account", + "entityType": "columns" + }, + { + "name": "billing", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(4)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_last4", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "balance", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_locked_till", + "table": "billing", + "entityType": "columns" + }, + { + "name": "payment", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "invoice_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "amount", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_refunded", + "table": "payment", + "entityType": "columns" + }, + { + "name": "usage", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "input_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "output_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reasoning_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_read_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_5m_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_1h_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cost", + "table": "usage", + "entityType": "columns" + }, + { + "name": "key", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "key", + "entityType": "columns" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "actor", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "old_name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_used", + "table": "key", + "entityType": "columns" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_seen", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_joined", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "color", + "table": "user", + "entityType": "columns" + }, + { + "type": "enum('admin','member')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "role", + "table": "user", + "entityType": "columns" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "slug", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "workspace", + "entityType": "columns" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "email", + "table": "account", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "customer_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_customer_id", + "table": "billing", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "billing", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "payment", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "usage", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "key", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_key", + "table": "key", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "name", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "name", + "table": "key", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "key", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "user", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "slug", + "table": "workspace", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "workspace", + "entityType": "pks" + } + ], + "renames": [] +} diff --git a/packages/console/core/migrations/0020_supreme_jack_power.sql b/packages/console/core/migrations/20250929181457_supreme_jack_power/migration.sql similarity index 100% rename from packages/console/core/migrations/0020_supreme_jack_power.sql rename to packages/console/core/migrations/20250929181457_supreme_jack_power/migration.sql diff --git a/packages/console/core/migrations/20250929181457_supreme_jack_power/snapshot.json b/packages/console/core/migrations/20250929181457_supreme_jack_power/snapshot.json new file mode 100644 index 0000000000..6808c0fd5b --- /dev/null +++ b/packages/console/core/migrations/20250929181457_supreme_jack_power/snapshot.json @@ -0,0 +1,1171 @@ +{ + "version": "6", + "id": "908437f9-54ed-4c83-b555-614926e326f8", + "prevIds": ["a2bb7222-561c-45f0-8939-8ef9b8e57bb3"], + "dialect": "mysql", + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "account", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "account", + "entityType": "columns" + }, + { + "name": "billing", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(4)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_last4", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "balance", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_locked_till", + "table": "billing", + "entityType": "columns" + }, + { + "name": "payment", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "invoice_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "amount", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_refunded", + "table": "payment", + "entityType": "columns" + }, + { + "name": "usage", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "input_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "output_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reasoning_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_read_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_5m_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_1h_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cost", + "table": "usage", + "entityType": "columns" + }, + { + "name": "key", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "key", + "entityType": "columns" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "actor", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "old_name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_used", + "table": "key", + "entityType": "columns" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_seen", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "color", + "table": "user", + "entityType": "columns" + }, + { + "type": "enum('admin','member')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "role", + "table": "user", + "entityType": "columns" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "slug", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "workspace", + "entityType": "columns" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "email", + "table": "account", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "customer_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_customer_id", + "table": "billing", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "billing", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "payment", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "usage", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "key", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_key", + "table": "key", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "name", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "name", + "table": "key", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "key", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "user", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "slug", + "table": "workspace", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "workspace", + "entityType": "pks" + } + ], + "renames": [] +} diff --git a/packages/console/core/migrations/0021_flawless_clea.sql b/packages/console/core/migrations/20250929224703_flawless_clea/migration.sql similarity index 100% rename from packages/console/core/migrations/0021_flawless_clea.sql rename to packages/console/core/migrations/20250929224703_flawless_clea/migration.sql diff --git a/packages/console/core/migrations/20250929224703_flawless_clea/snapshot.json b/packages/console/core/migrations/20250929224703_flawless_clea/snapshot.json new file mode 100644 index 0000000000..5c2ab1a4b1 --- /dev/null +++ b/packages/console/core/migrations/20250929224703_flawless_clea/snapshot.json @@ -0,0 +1,1185 @@ +{ + "version": "6", + "id": "14616ba2-c21e-4787-a289-f2a3eb6de04f", + "prevIds": ["908437f9-54ed-4c83-b555-614926e326f8"], + "dialect": "mysql", + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "account", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "account", + "entityType": "columns" + }, + { + "name": "billing", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(4)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_last4", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "balance", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_locked_till", + "table": "billing", + "entityType": "columns" + }, + { + "name": "payment", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "invoice_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "amount", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_refunded", + "table": "payment", + "entityType": "columns" + }, + { + "name": "usage", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "input_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "output_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reasoning_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_read_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_5m_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_1h_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cost", + "table": "usage", + "entityType": "columns" + }, + { + "name": "key", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "key", + "entityType": "columns" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "actor", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "old_name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_used", + "table": "key", + "entityType": "columns" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "old_email", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_seen", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "color", + "table": "user", + "entityType": "columns" + }, + { + "type": "enum('admin','member')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "role", + "table": "user", + "entityType": "columns" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "slug", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "workspace", + "entityType": "columns" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "email", + "table": "account", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "customer_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_customer_id", + "table": "billing", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "billing", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "payment", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "usage", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "key", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_key", + "table": "key", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "name", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "name", + "table": "key", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "key", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "user", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "slug", + "table": "workspace", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "workspace", + "entityType": "pks" + } + ], + "renames": [] +} diff --git a/packages/console/core/migrations/0022_nice_dreadnoughts.sql b/packages/console/core/migrations/20251002175032_nice_dreadnoughts/migration.sql similarity index 100% rename from packages/console/core/migrations/0022_nice_dreadnoughts.sql rename to packages/console/core/migrations/20251002175032_nice_dreadnoughts/migration.sql diff --git a/packages/console/core/migrations/20251002175032_nice_dreadnoughts/snapshot.json b/packages/console/core/migrations/20251002175032_nice_dreadnoughts/snapshot.json new file mode 100644 index 0000000000..12dd96929f --- /dev/null +++ b/packages/console/core/migrations/20251002175032_nice_dreadnoughts/snapshot.json @@ -0,0 +1,1233 @@ +{ + "version": "6", + "id": "2296e9e4-bee6-485b-a146-6666ac8dc0d0", + "prevIds": ["14616ba2-c21e-4787-a289-f2a3eb6de04f"], + "dialect": "mysql", + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "account", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "account", + "entityType": "columns" + }, + { + "name": "billing", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(4)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_last4", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "balance", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_locked_till", + "table": "billing", + "entityType": "columns" + }, + { + "name": "payment", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "invoice_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "amount", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_refunded", + "table": "payment", + "entityType": "columns" + }, + { + "name": "usage", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "input_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "output_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reasoning_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_read_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_5m_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_1h_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cost", + "table": "usage", + "entityType": "columns" + }, + { + "name": "key", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "key", + "entityType": "columns" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "actor", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "old_name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_used", + "table": "key", + "entityType": "columns" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "old_account_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "old_email", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_seen", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "color", + "table": "user", + "entityType": "columns" + }, + { + "type": "enum('admin','member')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "role", + "table": "user", + "entityType": "columns" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "slug", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "workspace", + "entityType": "columns" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "email", + "table": "account", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "customer_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_customer_id", + "table": "billing", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "billing", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "payment", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "usage", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "key", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_key", + "table": "key", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "name", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "name", + "table": "key", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "key", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "user", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "slug", + "table": "workspace", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "workspace", + "entityType": "pks" + } + ], + "renames": [] +} diff --git a/packages/console/core/migrations/0023_optimal_paibok.sql b/packages/console/core/migrations/20251002223020_optimal_paibok/migration.sql similarity index 100% rename from packages/console/core/migrations/0023_optimal_paibok.sql rename to packages/console/core/migrations/20251002223020_optimal_paibok/migration.sql diff --git a/packages/console/core/migrations/20251002223020_optimal_paibok/snapshot.json b/packages/console/core/migrations/20251002223020_optimal_paibok/snapshot.json new file mode 100644 index 0000000000..21f2b0ed2c --- /dev/null +++ b/packages/console/core/migrations/20251002223020_optimal_paibok/snapshot.json @@ -0,0 +1,1265 @@ +{ + "version": "6", + "id": "6857f409-1b5d-4752-9d65-a82ee70e6ad2", + "prevIds": ["2296e9e4-bee6-485b-a146-6666ac8dc0d0"], + "dialect": "mysql", + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "account", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "account", + "entityType": "columns" + }, + { + "name": "billing", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(4)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_last4", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "balance", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_locked_till", + "table": "billing", + "entityType": "columns" + }, + { + "name": "payment", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "invoice_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "amount", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_refunded", + "table": "payment", + "entityType": "columns" + }, + { + "name": "usage", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "input_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "output_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reasoning_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_read_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_5m_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_1h_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cost", + "table": "usage", + "entityType": "columns" + }, + { + "name": "key", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "key", + "entityType": "columns" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "actor", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "old_name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_used", + "table": "key", + "entityType": "columns" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "old_account_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "old_email", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_seen", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "color", + "table": "user", + "entityType": "columns" + }, + { + "type": "enum('admin','member')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "role", + "table": "user", + "entityType": "columns" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "slug", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "workspace", + "entityType": "columns" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "email", + "table": "account", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "customer_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_customer_id", + "table": "billing", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "billing", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "payment", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "usage", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "key", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_key", + "table": "key", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "name", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "name", + "table": "key", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "key", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "user", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "slug", + "table": "workspace", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "workspace", + "entityType": "pks" + } + ], + "renames": [] +} diff --git a/packages/console/core/migrations/0024_early_black_crow.sql b/packages/console/core/migrations/20251003202205_early_black_crow/migration.sql similarity index 100% rename from packages/console/core/migrations/0024_early_black_crow.sql rename to packages/console/core/migrations/20251003202205_early_black_crow/migration.sql diff --git a/packages/console/core/migrations/20251003202205_early_black_crow/snapshot.json b/packages/console/core/migrations/20251003202205_early_black_crow/snapshot.json new file mode 100644 index 0000000000..638be654c6 --- /dev/null +++ b/packages/console/core/migrations/20251003202205_early_black_crow/snapshot.json @@ -0,0 +1,1237 @@ +{ + "version": "6", + "id": "6d546f3e-17b2-4195-bb10-7e6d91774bd7", + "prevIds": ["6857f409-1b5d-4752-9d65-a82ee70e6ad2"], + "dialect": "mysql", + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "account", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "account", + "entityType": "columns" + }, + { + "name": "billing", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(4)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_last4", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "balance", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_locked_till", + "table": "billing", + "entityType": "columns" + }, + { + "name": "payment", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "invoice_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "amount", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_refunded", + "table": "payment", + "entityType": "columns" + }, + { + "name": "usage", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "input_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "output_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reasoning_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_read_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_5m_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_1h_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cost", + "table": "usage", + "entityType": "columns" + }, + { + "name": "key", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "key", + "entityType": "columns" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "actor", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "old_name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_used", + "table": "key", + "entityType": "columns" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_seen", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "color", + "table": "user", + "entityType": "columns" + }, + { + "type": "enum('admin','member')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "role", + "table": "user", + "entityType": "columns" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "slug", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "workspace", + "entityType": "columns" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "email", + "table": "account", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "customer_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_customer_id", + "table": "billing", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "billing", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "payment", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "usage", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "key", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_key", + "table": "key", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "name", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "name", + "table": "key", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "key", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "user", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "slug", + "table": "workspace", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "workspace", + "entityType": "pks" + } + ], + "renames": [] +} diff --git a/packages/console/core/migrations/0025_legal_joseph.sql b/packages/console/core/migrations/20251003210411_legal_joseph/migration.sql similarity index 100% rename from packages/console/core/migrations/0025_legal_joseph.sql rename to packages/console/core/migrations/20251003210411_legal_joseph/migration.sql diff --git a/packages/console/core/migrations/20251003210411_legal_joseph/snapshot.json b/packages/console/core/migrations/20251003210411_legal_joseph/snapshot.json new file mode 100644 index 0000000000..6366356446 --- /dev/null +++ b/packages/console/core/migrations/20251003210411_legal_joseph/snapshot.json @@ -0,0 +1,1251 @@ +{ + "version": "6", + "id": "ce444765-0606-4880-970a-2176bc2a78ac", + "prevIds": ["6d546f3e-17b2-4195-bb10-7e6d91774bd7"], + "dialect": "mysql", + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "account", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "account", + "entityType": "columns" + }, + { + "name": "billing", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(4)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_last4", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "balance", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_locked_till", + "table": "billing", + "entityType": "columns" + }, + { + "name": "payment", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "invoice_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "amount", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_refunded", + "table": "payment", + "entityType": "columns" + }, + { + "name": "usage", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "input_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "output_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reasoning_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_read_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_5m_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_1h_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cost", + "table": "usage", + "entityType": "columns" + }, + { + "name": "key", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "key", + "entityType": "columns" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "actor", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "old_name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "user_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_used", + "table": "key", + "entityType": "columns" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_seen", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "color", + "table": "user", + "entityType": "columns" + }, + { + "type": "enum('admin','member')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "role", + "table": "user", + "entityType": "columns" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "slug", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "workspace", + "entityType": "columns" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "email", + "table": "account", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "customer_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_customer_id", + "table": "billing", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "billing", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "payment", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "usage", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "key", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_key", + "table": "key", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "name", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "name", + "table": "key", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "key", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "user", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "slug", + "table": "workspace", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "workspace", + "entityType": "pks" + } + ], + "renames": [] +} diff --git a/packages/console/core/migrations/0026_numerous_prodigy.sql b/packages/console/core/migrations/20251004030300_numerous_prodigy/migration.sql similarity index 100% rename from packages/console/core/migrations/0026_numerous_prodigy.sql rename to packages/console/core/migrations/20251004030300_numerous_prodigy/migration.sql diff --git a/packages/console/core/migrations/20251004030300_numerous_prodigy/snapshot.json b/packages/console/core/migrations/20251004030300_numerous_prodigy/snapshot.json new file mode 100644 index 0000000000..1588e6b8e3 --- /dev/null +++ b/packages/console/core/migrations/20251004030300_numerous_prodigy/snapshot.json @@ -0,0 +1,1231 @@ +{ + "version": "6", + "id": "9e1313c7-ca78-4d2c-b13b-625d9d6fcaa3", + "prevIds": ["ce444765-0606-4880-970a-2176bc2a78ac"], + "dialect": "mysql", + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "account", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "account", + "entityType": "columns" + }, + { + "name": "billing", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(4)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_last4", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "balance", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_locked_till", + "table": "billing", + "entityType": "columns" + }, + { + "name": "payment", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "invoice_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "amount", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_refunded", + "table": "payment", + "entityType": "columns" + }, + { + "name": "usage", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "input_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "output_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reasoning_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_read_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_5m_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_1h_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cost", + "table": "usage", + "entityType": "columns" + }, + { + "name": "key", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "key", + "entityType": "columns" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "actor", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "old_name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "user_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_used", + "table": "key", + "entityType": "columns" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_seen", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "color", + "table": "user", + "entityType": "columns" + }, + { + "type": "enum('admin','member')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "role", + "table": "user", + "entityType": "columns" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "slug", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "workspace", + "entityType": "columns" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "email", + "table": "account", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "customer_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_customer_id", + "table": "billing", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "billing", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "payment", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "usage", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "key", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_key", + "table": "key", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "key", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "user", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "slug", + "table": "workspace", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "workspace", + "entityType": "pks" + } + ], + "renames": [] +} diff --git a/packages/console/core/migrations/0027_hot_wong.sql b/packages/console/core/migrations/20251004045106_hot_wong/migration.sql similarity index 100% rename from packages/console/core/migrations/0027_hot_wong.sql rename to packages/console/core/migrations/20251004045106_hot_wong/migration.sql diff --git a/packages/console/core/migrations/20251004045106_hot_wong/snapshot.json b/packages/console/core/migrations/20251004045106_hot_wong/snapshot.json new file mode 100644 index 0000000000..15467efc38 --- /dev/null +++ b/packages/console/core/migrations/20251004045106_hot_wong/snapshot.json @@ -0,0 +1,1203 @@ +{ + "version": "6", + "id": "05e873f6-1556-4bcb-8e19-14971e37610a", + "prevIds": ["9e1313c7-ca78-4d2c-b13b-625d9d6fcaa3"], + "dialect": "mysql", + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "account", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "account", + "entityType": "columns" + }, + { + "name": "billing", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(4)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_last4", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "balance", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_locked_till", + "table": "billing", + "entityType": "columns" + }, + { + "name": "payment", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "invoice_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "amount", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_refunded", + "table": "payment", + "entityType": "columns" + }, + { + "name": "usage", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "input_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "output_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reasoning_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_read_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_5m_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_1h_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cost", + "table": "usage", + "entityType": "columns" + }, + { + "name": "key", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "user_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_used", + "table": "key", + "entityType": "columns" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_seen", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "color", + "table": "user", + "entityType": "columns" + }, + { + "type": "enum('admin','member')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "role", + "table": "user", + "entityType": "columns" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "slug", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "workspace", + "entityType": "columns" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "email", + "table": "account", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "customer_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_customer_id", + "table": "billing", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "billing", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "payment", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "usage", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "key", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_key", + "table": "key", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "key", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "user", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "slug", + "table": "workspace", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "workspace", + "entityType": "pks" + } + ], + "renames": [] +} diff --git a/packages/console/core/migrations/0028_careful_cerise.sql b/packages/console/core/migrations/20251007024345_careful_cerise/migration.sql similarity index 100% rename from packages/console/core/migrations/0028_careful_cerise.sql rename to packages/console/core/migrations/20251007024345_careful_cerise/migration.sql diff --git a/packages/console/core/migrations/20251007024345_careful_cerise/snapshot.json b/packages/console/core/migrations/20251007024345_careful_cerise/snapshot.json new file mode 100644 index 0000000000..7dd21cfe14 --- /dev/null +++ b/packages/console/core/migrations/20251007024345_careful_cerise/snapshot.json @@ -0,0 +1,1203 @@ +{ + "version": "6", + "id": "a331e38c-c2e3-406d-a1ff-b0af7229cd85", + "prevIds": ["05e873f6-1556-4bcb-8e19-14971e37610a"], + "dialect": "mysql", + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "account", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "account", + "entityType": "columns" + }, + { + "name": "billing", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(4)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_last4", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "balance", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_locked_till", + "table": "billing", + "entityType": "columns" + }, + { + "name": "payment", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "invoice_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "amount", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_refunded", + "table": "payment", + "entityType": "columns" + }, + { + "name": "usage", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "input_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "output_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reasoning_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_read_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_5m_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_1h_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cost", + "table": "usage", + "entityType": "columns" + }, + { + "name": "key", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "user_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_used", + "table": "key", + "entityType": "columns" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_seen", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "color", + "table": "user", + "entityType": "columns" + }, + { + "type": "enum('admin','member')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "role", + "table": "user", + "entityType": "columns" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "slug", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "workspace", + "entityType": "columns" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "email", + "table": "account", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "customer_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_customer_id", + "table": "billing", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "billing", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "payment", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "usage", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "key", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_key", + "table": "key", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "key", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "user", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "slug", + "table": "workspace", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "workspace", + "entityType": "pks" + } + ], + "renames": [] +} diff --git a/packages/console/core/migrations/0029_panoramic_harrier.sql b/packages/console/core/migrations/20251007043715_panoramic_harrier/migration.sql similarity index 100% rename from packages/console/core/migrations/0029_panoramic_harrier.sql rename to packages/console/core/migrations/20251007043715_panoramic_harrier/migration.sql diff --git a/packages/console/core/migrations/20251007043715_panoramic_harrier/snapshot.json b/packages/console/core/migrations/20251007043715_panoramic_harrier/snapshot.json new file mode 100644 index 0000000000..610ce90114 --- /dev/null +++ b/packages/console/core/migrations/20251007043715_panoramic_harrier/snapshot.json @@ -0,0 +1,1245 @@ +{ + "version": "6", + "id": "33551b4c-fc2e-4753-8d9d-0971f333e65d", + "prevIds": ["a331e38c-c2e3-406d-a1ff-b0af7229cd85"], + "dialect": "mysql", + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "account", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "account", + "entityType": "columns" + }, + { + "name": "billing", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(4)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_last4", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "balance", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_locked_till", + "table": "billing", + "entityType": "columns" + }, + { + "name": "payment", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "invoice_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "amount", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_refunded", + "table": "payment", + "entityType": "columns" + }, + { + "name": "usage", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "input_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "output_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reasoning_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_read_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_5m_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_1h_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cost", + "table": "usage", + "entityType": "columns" + }, + { + "name": "key", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "user_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_used", + "table": "key", + "entityType": "columns" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_seen", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "color", + "table": "user", + "entityType": "columns" + }, + { + "type": "enum('admin','member')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "role", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "user", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "user", + "entityType": "columns" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "slug", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "workspace", + "entityType": "columns" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "email", + "table": "account", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "customer_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_customer_id", + "table": "billing", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "billing", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "payment", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "usage", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "key", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_key", + "table": "key", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "key", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "user", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "slug", + "table": "workspace", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "workspace", + "entityType": "pks" + } + ], + "renames": [] +} diff --git a/packages/console/core/migrations/0030_ordinary_ultragirl.sql b/packages/console/core/migrations/20251007230438_ordinary_ultragirl/migration.sql similarity index 100% rename from packages/console/core/migrations/0030_ordinary_ultragirl.sql rename to packages/console/core/migrations/20251007230438_ordinary_ultragirl/migration.sql diff --git a/packages/console/core/migrations/20251007230438_ordinary_ultragirl/snapshot.json b/packages/console/core/migrations/20251007230438_ordinary_ultragirl/snapshot.json new file mode 100644 index 0000000000..77205c73d2 --- /dev/null +++ b/packages/console/core/migrations/20251007230438_ordinary_ultragirl/snapshot.json @@ -0,0 +1,1359 @@ +{ + "version": "6", + "id": "eae45fcf-dc0f-4756-bc5d-30791f2965a2", + "prevIds": ["33551b4c-fc2e-4753-8d9d-0971f333e65d"], + "dialect": "mysql", + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "account", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "account", + "entityType": "columns" + }, + { + "name": "billing", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(4)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_last4", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "balance", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_locked_till", + "table": "billing", + "entityType": "columns" + }, + { + "name": "payment", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "invoice_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "amount", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_refunded", + "table": "payment", + "entityType": "columns" + }, + { + "name": "usage", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "input_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "output_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reasoning_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_read_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_5m_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_1h_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cost", + "table": "usage", + "entityType": "columns" + }, + { + "name": "key", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "user_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_used", + "table": "key", + "entityType": "columns" + }, + { + "name": "model", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "model", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "model", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "model", + "entityType": "columns" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_seen", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "color", + "table": "user", + "entityType": "columns" + }, + { + "type": "enum('admin','member')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "role", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "user", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "user", + "entityType": "columns" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "slug", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "workspace", + "entityType": "columns" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "email", + "table": "account", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "customer_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_customer_id", + "table": "billing", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "billing", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "payment", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "usage", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "key", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_key", + "table": "key", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "key", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "model", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "model_workspace_model", + "table": "model", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "model", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "user", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "slug", + "table": "workspace", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "workspace", + "entityType": "pks" + } + ], + "renames": [] +} diff --git a/packages/console/core/migrations/0031_outgoing_outlaw_kid.sql b/packages/console/core/migrations/20251008161718_outgoing_outlaw_kid/migration.sql similarity index 100% rename from packages/console/core/migrations/0031_outgoing_outlaw_kid.sql rename to packages/console/core/migrations/20251008161718_outgoing_outlaw_kid/migration.sql diff --git a/packages/console/core/migrations/20251008161718_outgoing_outlaw_kid/snapshot.json b/packages/console/core/migrations/20251008161718_outgoing_outlaw_kid/snapshot.json new file mode 100644 index 0000000000..d91bd7d1aa --- /dev/null +++ b/packages/console/core/migrations/20251008161718_outgoing_outlaw_kid/snapshot.json @@ -0,0 +1,1487 @@ +{ + "version": "6", + "id": "9dceb591-8e08-4991-a49c-1f1741ec1e57", + "prevIds": ["eae45fcf-dc0f-4756-bc5d-30791f2965a2"], + "dialect": "mysql", + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "account", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "account", + "entityType": "columns" + }, + { + "name": "billing", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(4)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_last4", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "balance", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_locked_till", + "table": "billing", + "entityType": "columns" + }, + { + "name": "payment", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "invoice_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "amount", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_refunded", + "table": "payment", + "entityType": "columns" + }, + { + "name": "usage", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "input_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "output_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reasoning_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_read_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_5m_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_1h_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cost", + "table": "usage", + "entityType": "columns" + }, + { + "name": "key", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "user_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_used", + "table": "key", + "entityType": "columns" + }, + { + "name": "model", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "model", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "model", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "model", + "entityType": "columns" + }, + { + "name": "provider", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "provider", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "provider", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "provider", + "entityType": "columns" + }, + { + "type": "text", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "credentials", + "table": "provider", + "entityType": "columns" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_seen", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "color", + "table": "user", + "entityType": "columns" + }, + { + "type": "enum('admin','member')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "role", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "user", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "user", + "entityType": "columns" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "slug", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "workspace", + "entityType": "columns" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "email", + "table": "account", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "customer_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_customer_id", + "table": "billing", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "billing", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "payment", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "usage", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "key", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_key", + "table": "key", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "key", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "model", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "model_workspace_model", + "table": "model", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "model", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "provider", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "workspace_provider", + "table": "provider", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "provider", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "user", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "slug", + "table": "workspace", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "workspace", + "entityType": "pks" + } + ], + "renames": [] +} diff --git a/packages/console/core/migrations/0032_white_doctor_doom.sql b/packages/console/core/migrations/20251009021849_white_doctor_doom/migration.sql similarity index 100% rename from packages/console/core/migrations/0032_white_doctor_doom.sql rename to packages/console/core/migrations/20251009021849_white_doctor_doom/migration.sql diff --git a/packages/console/core/migrations/20251009021849_white_doctor_doom/snapshot.json b/packages/console/core/migrations/20251009021849_white_doctor_doom/snapshot.json new file mode 100644 index 0000000000..6fe9fd5dc0 --- /dev/null +++ b/packages/console/core/migrations/20251009021849_white_doctor_doom/snapshot.json @@ -0,0 +1,1501 @@ +{ + "version": "6", + "id": "b2406421-f22d-4153-a2a4-6deafe70ee54", + "prevIds": ["9dceb591-8e08-4991-a49c-1f1741ec1e57"], + "dialect": "mysql", + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "account", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "account", + "entityType": "columns" + }, + { + "name": "billing", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(4)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_last4", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "balance", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_locked_till", + "table": "billing", + "entityType": "columns" + }, + { + "name": "payment", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "invoice_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "amount", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_refunded", + "table": "payment", + "entityType": "columns" + }, + { + "name": "usage", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "input_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "output_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reasoning_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_read_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_5m_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_1h_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cost", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key_id", + "table": "usage", + "entityType": "columns" + }, + { + "name": "key", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "user_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_used", + "table": "key", + "entityType": "columns" + }, + { + "name": "model", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "model", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "model", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "model", + "entityType": "columns" + }, + { + "name": "provider", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "provider", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "provider", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "provider", + "entityType": "columns" + }, + { + "type": "text", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "credentials", + "table": "provider", + "entityType": "columns" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_seen", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "color", + "table": "user", + "entityType": "columns" + }, + { + "type": "enum('admin','member')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "role", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "user", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "user", + "entityType": "columns" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "slug", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "workspace", + "entityType": "columns" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "email", + "table": "account", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "customer_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_customer_id", + "table": "billing", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "billing", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "payment", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "usage", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "key", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_key", + "table": "key", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "key", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "model", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "model_workspace_model", + "table": "model", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "model", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "provider", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "workspace_provider", + "table": "provider", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "provider", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "user", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "slug", + "table": "workspace", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "workspace", + "entityType": "pks" + } + ], + "renames": [] +} diff --git a/packages/console/core/migrations/0033_cynical_jack_flag.sql b/packages/console/core/migrations/20251016175624_cynical_jack_flag/migration.sql similarity index 100% rename from packages/console/core/migrations/0033_cynical_jack_flag.sql rename to packages/console/core/migrations/20251016175624_cynical_jack_flag/migration.sql diff --git a/packages/console/core/migrations/20251016175624_cynical_jack_flag/snapshot.json b/packages/console/core/migrations/20251016175624_cynical_jack_flag/snapshot.json new file mode 100644 index 0000000000..3ea26248b3 --- /dev/null +++ b/packages/console/core/migrations/20251016175624_cynical_jack_flag/snapshot.json @@ -0,0 +1,1515 @@ +{ + "version": "6", + "id": "91ef8fda-ca96-4a3f-af29-dd6ae7136398", + "prevIds": ["b2406421-f22d-4153-a2a4-6deafe70ee54"], + "dialect": "mysql", + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "account", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "account", + "entityType": "columns" + }, + { + "name": "billing", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(32)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_type", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(4)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_last4", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "balance", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_locked_till", + "table": "billing", + "entityType": "columns" + }, + { + "name": "payment", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "invoice_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "amount", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_refunded", + "table": "payment", + "entityType": "columns" + }, + { + "name": "usage", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "input_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "output_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reasoning_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_read_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_5m_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_1h_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cost", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key_id", + "table": "usage", + "entityType": "columns" + }, + { + "name": "key", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "user_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_used", + "table": "key", + "entityType": "columns" + }, + { + "name": "model", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "model", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "model", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "model", + "entityType": "columns" + }, + { + "name": "provider", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "provider", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "provider", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "provider", + "entityType": "columns" + }, + { + "type": "text", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "credentials", + "table": "provider", + "entityType": "columns" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_seen", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "color", + "table": "user", + "entityType": "columns" + }, + { + "type": "enum('admin','member')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "role", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "user", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "user", + "entityType": "columns" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "slug", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "workspace", + "entityType": "columns" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "email", + "table": "account", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "customer_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_customer_id", + "table": "billing", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "billing", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "payment", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "usage", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "key", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_key", + "table": "key", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "key", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "model", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "model_workspace_model", + "table": "model", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "model", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "provider", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "workspace_provider", + "table": "provider", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "provider", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "user", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "slug", + "table": "workspace", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "workspace", + "entityType": "pks" + } + ], + "renames": [] +} diff --git a/packages/console/core/migrations/0034_short_bulldozer.sql b/packages/console/core/migrations/20251016214520_short_bulldozer/migration.sql similarity index 100% rename from packages/console/core/migrations/0034_short_bulldozer.sql rename to packages/console/core/migrations/20251016214520_short_bulldozer/migration.sql diff --git a/packages/console/core/migrations/20251016214520_short_bulldozer/snapshot.json b/packages/console/core/migrations/20251016214520_short_bulldozer/snapshot.json new file mode 100644 index 0000000000..c22274da05 --- /dev/null +++ b/packages/console/core/migrations/20251016214520_short_bulldozer/snapshot.json @@ -0,0 +1,1637 @@ +{ + "version": "6", + "id": "34706440-26d7-43f5-9b39-815aa912e5ef", + "prevIds": ["91ef8fda-ca96-4a3f-af29-dd6ae7136398"], + "dialect": "mysql", + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "account", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "account", + "entityType": "columns" + }, + { + "name": "auth", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "auth", + "entityType": "columns" + }, + { + "type": "enum('email','github','google')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "auth", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subject", + "table": "auth", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "table": "auth", + "entityType": "columns" + }, + { + "name": "billing", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(32)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_type", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(4)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_last4", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "balance", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_locked_till", + "table": "billing", + "entityType": "columns" + }, + { + "name": "payment", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "invoice_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "amount", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_refunded", + "table": "payment", + "entityType": "columns" + }, + { + "name": "usage", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "input_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "output_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reasoning_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_read_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_5m_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_1h_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cost", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key_id", + "table": "usage", + "entityType": "columns" + }, + { + "name": "key", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "user_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_used", + "table": "key", + "entityType": "columns" + }, + { + "name": "model", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "model", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "model", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "model", + "entityType": "columns" + }, + { + "name": "provider", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "provider", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "provider", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "provider", + "entityType": "columns" + }, + { + "type": "text", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "credentials", + "table": "provider", + "entityType": "columns" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_seen", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "color", + "table": "user", + "entityType": "columns" + }, + { + "type": "enum('admin','member')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "role", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "user", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "user", + "entityType": "columns" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "slug", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "workspace", + "entityType": "columns" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "email", + "table": "account", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "provider", + "isExpression": false + }, + { + "value": "subject", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "provider", + "table": "auth", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "customer_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_customer_id", + "table": "billing", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "billing", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "payment", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "usage", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "key", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_key", + "table": "key", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "key", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "model", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "model_workspace_model", + "table": "model", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "model", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "provider", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "workspace_provider", + "table": "provider", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "provider", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "user", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "slug", + "table": "workspace", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "workspace", + "entityType": "pks" + } + ], + "renames": [] +} diff --git a/packages/console/core/migrations/0035_narrow_blindfold.sql b/packages/console/core/migrations/20251017015733_narrow_blindfold/migration.sql similarity index 100% rename from packages/console/core/migrations/0035_narrow_blindfold.sql rename to packages/console/core/migrations/20251017015733_narrow_blindfold/migration.sql diff --git a/packages/console/core/migrations/20251017015733_narrow_blindfold/snapshot.json b/packages/console/core/migrations/20251017015733_narrow_blindfold/snapshot.json new file mode 100644 index 0000000000..0266131452 --- /dev/null +++ b/packages/console/core/migrations/20251017015733_narrow_blindfold/snapshot.json @@ -0,0 +1,1623 @@ +{ + "version": "6", + "id": "10169105-4545-4894-838b-004c0a42c584", + "prevIds": ["34706440-26d7-43f5-9b39-815aa912e5ef"], + "dialect": "mysql", + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "account", + "entityType": "columns" + }, + { + "name": "auth", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "auth", + "entityType": "columns" + }, + { + "type": "enum('email','github','google')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "auth", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subject", + "table": "auth", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "table": "auth", + "entityType": "columns" + }, + { + "name": "billing", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(32)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_type", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(4)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_last4", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "balance", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_locked_till", + "table": "billing", + "entityType": "columns" + }, + { + "name": "payment", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "invoice_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "amount", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_refunded", + "table": "payment", + "entityType": "columns" + }, + { + "name": "usage", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "input_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "output_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reasoning_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_read_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_5m_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_1h_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cost", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key_id", + "table": "usage", + "entityType": "columns" + }, + { + "name": "key", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "user_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_used", + "table": "key", + "entityType": "columns" + }, + { + "name": "model", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "model", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "model", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "model", + "entityType": "columns" + }, + { + "name": "provider", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "provider", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "provider", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "provider", + "entityType": "columns" + }, + { + "type": "text", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "credentials", + "table": "provider", + "entityType": "columns" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_seen", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "color", + "table": "user", + "entityType": "columns" + }, + { + "type": "enum('admin','member')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "role", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "user", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "user", + "entityType": "columns" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "slug", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "workspace", + "entityType": "columns" + }, + { + "columns": [ + { + "value": "provider", + "isExpression": false + }, + { + "value": "subject", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "provider", + "table": "auth", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "account_id", + "table": "auth", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "customer_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_customer_id", + "table": "billing", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "billing", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "payment", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "usage", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "key", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_key", + "table": "key", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "key", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "model", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "model_workspace_model", + "table": "model", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "model", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "provider", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "workspace_provider", + "table": "provider", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "provider", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "user", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "slug", + "table": "workspace", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "workspace", + "entityType": "pks" + } + ], + "renames": [] +} diff --git a/packages/console/core/migrations/0036_slimy_energizer.sql b/packages/console/core/migrations/20251017024232_slimy_energizer/migration.sql similarity index 100% rename from packages/console/core/migrations/0036_slimy_energizer.sql rename to packages/console/core/migrations/20251017024232_slimy_energizer/migration.sql diff --git a/packages/console/core/migrations/20251017024232_slimy_energizer/snapshot.json b/packages/console/core/migrations/20251017024232_slimy_energizer/snapshot.json new file mode 100644 index 0000000000..106aa33c6d --- /dev/null +++ b/packages/console/core/migrations/20251017024232_slimy_energizer/snapshot.json @@ -0,0 +1,1635 @@ +{ + "version": "6", + "id": "5470c8b4-296d-47bd-85a7-88cfd3b71434", + "prevIds": ["10169105-4545-4894-838b-004c0a42c584"], + "dialect": "mysql", + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "account", + "entityType": "columns" + }, + { + "name": "auth", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "auth", + "entityType": "columns" + }, + { + "type": "enum('email','github','google')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "auth", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subject", + "table": "auth", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "table": "auth", + "entityType": "columns" + }, + { + "name": "billing", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(32)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_type", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(4)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_last4", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "balance", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_locked_till", + "table": "billing", + "entityType": "columns" + }, + { + "name": "payment", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "invoice_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "amount", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_refunded", + "table": "payment", + "entityType": "columns" + }, + { + "name": "usage", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "input_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "output_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reasoning_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_read_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_5m_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_1h_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cost", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key_id", + "table": "usage", + "entityType": "columns" + }, + { + "name": "key", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "user_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_used", + "table": "key", + "entityType": "columns" + }, + { + "name": "model", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "model", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "model", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "model", + "entityType": "columns" + }, + { + "name": "provider", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "provider", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "provider", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "provider", + "entityType": "columns" + }, + { + "type": "text", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "credentials", + "table": "provider", + "entityType": "columns" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_seen", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "color", + "table": "user", + "entityType": "columns" + }, + { + "type": "enum('admin','member')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "role", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "user", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "user", + "entityType": "columns" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "slug", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "workspace", + "entityType": "columns" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "account", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "provider", + "isExpression": false + }, + { + "value": "subject", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "provider", + "table": "auth", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "account_id", + "table": "auth", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "auth", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "customer_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_customer_id", + "table": "billing", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "billing", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "payment", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "usage", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "key", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_key", + "table": "key", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "key", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "model", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "model_workspace_model", + "table": "model", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "model", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "provider", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "workspace_provider", + "table": "provider", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "provider", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "user", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "slug", + "table": "workspace", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "workspace", + "entityType": "pks" + } + ], + "renames": [] +} diff --git a/packages/console/core/migrations/0037_messy_jackal.sql b/packages/console/core/migrations/20251031163113_messy_jackal/migration.sql similarity index 100% rename from packages/console/core/migrations/0037_messy_jackal.sql rename to packages/console/core/migrations/20251031163113_messy_jackal/migration.sql diff --git a/packages/console/core/migrations/20251031163113_messy_jackal/snapshot.json b/packages/console/core/migrations/20251031163113_messy_jackal/snapshot.json new file mode 100644 index 0000000000..27f03383a6 --- /dev/null +++ b/packages/console/core/migrations/20251031163113_messy_jackal/snapshot.json @@ -0,0 +1,1663 @@ +{ + "version": "6", + "id": "8b7fa839-a088-408e-84a4-1a07325c0290", + "prevIds": ["5470c8b4-296d-47bd-85a7-88cfd3b71434"], + "dialect": "mysql", + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "account", + "entityType": "columns" + }, + { + "name": "auth", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "auth", + "entityType": "columns" + }, + { + "type": "enum('email','github','google')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "auth", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subject", + "table": "auth", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "table": "auth", + "entityType": "columns" + }, + { + "name": "billing", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(32)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_type", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(4)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_last4", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "balance", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_trigger", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_amount", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_locked_till", + "table": "billing", + "entityType": "columns" + }, + { + "name": "payment", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "invoice_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "amount", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_refunded", + "table": "payment", + "entityType": "columns" + }, + { + "name": "usage", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "input_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "output_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reasoning_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_read_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_5m_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_1h_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cost", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key_id", + "table": "usage", + "entityType": "columns" + }, + { + "name": "key", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "user_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_used", + "table": "key", + "entityType": "columns" + }, + { + "name": "model", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "model", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "model", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "model", + "entityType": "columns" + }, + { + "name": "provider", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "provider", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "provider", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "provider", + "entityType": "columns" + }, + { + "type": "text", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "credentials", + "table": "provider", + "entityType": "columns" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_seen", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "color", + "table": "user", + "entityType": "columns" + }, + { + "type": "enum('admin','member')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "role", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "user", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "user", + "entityType": "columns" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "slug", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "workspace", + "entityType": "columns" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "account", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "provider", + "isExpression": false + }, + { + "value": "subject", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "provider", + "table": "auth", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "account_id", + "table": "auth", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "auth", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "customer_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_customer_id", + "table": "billing", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "billing", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "payment", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "usage", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "key", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_key", + "table": "key", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "key", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "model", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "model_workspace_model", + "table": "model", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "model", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "provider", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "workspace_provider", + "table": "provider", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "provider", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "user", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "slug", + "table": "workspace", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "workspace", + "entityType": "pks" + } + ], + "renames": [] +} diff --git a/packages/console/core/migrations/0038_famous_magik.sql b/packages/console/core/migrations/20251125223403_famous_magik/migration.sql similarity index 100% rename from packages/console/core/migrations/0038_famous_magik.sql rename to packages/console/core/migrations/20251125223403_famous_magik/migration.sql diff --git a/packages/console/core/migrations/20251125223403_famous_magik/snapshot.json b/packages/console/core/migrations/20251125223403_famous_magik/snapshot.json new file mode 100644 index 0000000000..5250b41461 --- /dev/null +++ b/packages/console/core/migrations/20251125223403_famous_magik/snapshot.json @@ -0,0 +1,1743 @@ +{ + "version": "6", + "id": "9d5d9885-7ec5-45f6-ac53-45a8e25dede7", + "prevIds": ["8b7fa839-a088-408e-84a4-1a07325c0290"], + "dialect": "mysql", + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "account", + "entityType": "columns" + }, + { + "name": "auth", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "auth", + "entityType": "columns" + }, + { + "type": "enum('email','github','google')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "auth", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subject", + "table": "auth", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "table": "auth", + "entityType": "columns" + }, + { + "name": "billing", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(32)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_type", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(4)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_last4", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "balance", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_trigger", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_amount", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_locked_till", + "table": "billing", + "entityType": "columns" + }, + { + "name": "payment", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "invoice_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "amount", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_refunded", + "table": "payment", + "entityType": "columns" + }, + { + "name": "usage", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "input_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "output_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reasoning_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_read_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_5m_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_1h_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cost", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key_id", + "table": "usage", + "entityType": "columns" + }, + { + "name": "ip", + "entityType": "tables" + }, + { + "type": "varchar(45)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "ip", + "table": "ip", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "ip", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "ip", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "ip", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "usage", + "table": "ip", + "entityType": "columns" + }, + { + "name": "key", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "user_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_used", + "table": "key", + "entityType": "columns" + }, + { + "name": "model", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "model", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "model", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "model", + "entityType": "columns" + }, + { + "name": "provider", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "provider", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "provider", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "provider", + "entityType": "columns" + }, + { + "type": "text", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "credentials", + "table": "provider", + "entityType": "columns" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_seen", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "color", + "table": "user", + "entityType": "columns" + }, + { + "type": "enum('admin','member')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "role", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "user", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "user", + "entityType": "columns" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "slug", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "workspace", + "entityType": "columns" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "account", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "provider", + "isExpression": false + }, + { + "value": "subject", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "provider", + "table": "auth", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "account_id", + "table": "auth", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "auth", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "customer_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_customer_id", + "table": "billing", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "billing", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "payment", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "usage", + "entityType": "pks" + }, + { + "columns": ["ip"], + "name": "PRIMARY", + "table": "ip", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "key", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_key", + "table": "key", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "key", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "model", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "model_workspace_model", + "table": "model", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "model", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "provider", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "workspace_provider", + "table": "provider", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "provider", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "user", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "slug", + "table": "workspace", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "workspace", + "entityType": "pks" + } + ], + "renames": [] +} diff --git a/packages/console/core/migrations/0039_striped_forge.sql b/packages/console/core/migrations/20251228182259_striped_forge/migration.sql similarity index 100% rename from packages/console/core/migrations/0039_striped_forge.sql rename to packages/console/core/migrations/20251228182259_striped_forge/migration.sql diff --git a/packages/console/core/migrations/20251228182259_striped_forge/snapshot.json b/packages/console/core/migrations/20251228182259_striped_forge/snapshot.json new file mode 100644 index 0000000000..0a540a4b9f --- /dev/null +++ b/packages/console/core/migrations/20251228182259_striped_forge/snapshot.json @@ -0,0 +1,1867 @@ +{ + "version": "6", + "id": "49a1ac05-78ab-4aae-908e-d4aeeb8196fc", + "prevIds": ["9d5d9885-7ec5-45f6-ac53-45a8e25dede7"], + "dialect": "mysql", + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "account", + "entityType": "columns" + }, + { + "name": "auth", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "auth", + "entityType": "columns" + }, + { + "type": "enum('email','github','google')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "auth", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subject", + "table": "auth", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "table": "auth", + "entityType": "columns" + }, + { + "name": "benchmark", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "agent", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "mediumtext", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "result", + "table": "benchmark", + "entityType": "columns" + }, + { + "name": "billing", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(32)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_type", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(4)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_last4", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "balance", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_trigger", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_amount", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_locked_till", + "table": "billing", + "entityType": "columns" + }, + { + "name": "payment", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "invoice_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "amount", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_refunded", + "table": "payment", + "entityType": "columns" + }, + { + "name": "usage", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "input_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "output_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reasoning_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_read_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_5m_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_1h_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cost", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key_id", + "table": "usage", + "entityType": "columns" + }, + { + "name": "ip", + "entityType": "tables" + }, + { + "type": "varchar(45)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "ip", + "table": "ip", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "ip", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "ip", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "ip", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "usage", + "table": "ip", + "entityType": "columns" + }, + { + "name": "key", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "user_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_used", + "table": "key", + "entityType": "columns" + }, + { + "name": "model", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "model", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "model", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "model", + "entityType": "columns" + }, + { + "name": "provider", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "provider", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "provider", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "provider", + "entityType": "columns" + }, + { + "type": "text", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "credentials", + "table": "provider", + "entityType": "columns" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_seen", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "color", + "table": "user", + "entityType": "columns" + }, + { + "type": "enum('admin','member')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "role", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "user", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "user", + "entityType": "columns" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "slug", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "workspace", + "entityType": "columns" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "account", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "provider", + "isExpression": false + }, + { + "value": "subject", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "provider", + "table": "auth", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "account_id", + "table": "auth", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "auth", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "time_created", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "time_created", + "table": "benchmark", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "benchmark", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "customer_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_customer_id", + "table": "billing", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "billing", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "payment", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "usage", + "entityType": "pks" + }, + { + "columns": ["ip"], + "name": "PRIMARY", + "table": "ip", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "key", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_key", + "table": "key", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "key", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "model", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "model_workspace_model", + "table": "model", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "model", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "provider", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "workspace_provider", + "table": "provider", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "provider", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "user", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "slug", + "table": "workspace", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "workspace", + "entityType": "pks" + } + ], + "renames": [] +} diff --git a/packages/console/core/migrations/0040_broken_gamora.sql b/packages/console/core/migrations/20260105034337_broken_gamora/migration.sql similarity index 100% rename from packages/console/core/migrations/0040_broken_gamora.sql rename to packages/console/core/migrations/20260105034337_broken_gamora/migration.sql diff --git a/packages/console/core/migrations/20260105034337_broken_gamora/snapshot.json b/packages/console/core/migrations/20260105034337_broken_gamora/snapshot.json new file mode 100644 index 0000000000..04e088505b --- /dev/null +++ b/packages/console/core/migrations/20260105034337_broken_gamora/snapshot.json @@ -0,0 +1,1887 @@ +{ + "version": "6", + "id": "bf19cd74-71f9-4bdf-b50e-67c2436f3408", + "prevIds": ["49a1ac05-78ab-4aae-908e-d4aeeb8196fc"], + "dialect": "mysql", + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "account", + "entityType": "columns" + }, + { + "name": "auth", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "auth", + "entityType": "columns" + }, + { + "type": "enum('email','github','google')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "auth", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subject", + "table": "auth", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "table": "auth", + "entityType": "columns" + }, + { + "name": "benchmark", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "agent", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "mediumtext", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "result", + "table": "benchmark", + "entityType": "columns" + }, + { + "name": "billing", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(32)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_type", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(4)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_last4", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "balance", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_trigger", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_amount", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_locked_till", + "table": "billing", + "entityType": "columns" + }, + { + "name": "payment", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "invoice_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "amount", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_refunded", + "table": "payment", + "entityType": "columns" + }, + { + "name": "usage", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "input_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "output_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reasoning_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_read_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_5m_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_1h_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cost", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key_id", + "table": "usage", + "entityType": "columns" + }, + { + "name": "ip", + "entityType": "tables" + }, + { + "type": "varchar(45)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "ip", + "table": "ip", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "ip", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "ip", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "ip", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "usage", + "table": "ip", + "entityType": "columns" + }, + { + "name": "key", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "user_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_used", + "table": "key", + "entityType": "columns" + }, + { + "name": "model", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "model", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "model", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "model", + "entityType": "columns" + }, + { + "name": "provider", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "provider", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "provider", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "provider", + "entityType": "columns" + }, + { + "type": "text", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "credentials", + "table": "provider", + "entityType": "columns" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_seen", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "color", + "table": "user", + "entityType": "columns" + }, + { + "type": "enum('admin','member')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "role", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "user", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "user", + "entityType": "columns" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "slug", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "workspace", + "entityType": "columns" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "account", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "provider", + "isExpression": false + }, + { + "value": "subject", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "provider", + "table": "auth", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "account_id", + "table": "auth", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "auth", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "time_created", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "time_created", + "table": "benchmark", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "benchmark", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "customer_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_customer_id", + "table": "billing", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "billing", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "payment", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "time_created", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "usage_time_created", + "table": "usage", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "usage", + "entityType": "pks" + }, + { + "columns": ["ip"], + "name": "PRIMARY", + "table": "ip", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "key", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_key", + "table": "key", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "key", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "model", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "model_workspace_model", + "table": "model", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "model", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "provider", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "workspace_provider", + "table": "provider", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "provider", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "user", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "slug", + "table": "workspace", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "workspace", + "entityType": "pks" + } + ], + "renames": [] +} diff --git a/packages/console/core/migrations/0041_odd_misty_knight.sql b/packages/console/core/migrations/20260106204919_odd_misty_knight/migration.sql similarity index 100% rename from packages/console/core/migrations/0041_odd_misty_knight.sql rename to packages/console/core/migrations/20260106204919_odd_misty_knight/migration.sql diff --git a/packages/console/core/migrations/20260106204919_odd_misty_knight/snapshot.json b/packages/console/core/migrations/20260106204919_odd_misty_knight/snapshot.json new file mode 100644 index 0000000000..17a9730364 --- /dev/null +++ b/packages/console/core/migrations/20260106204919_odd_misty_knight/snapshot.json @@ -0,0 +1,1939 @@ +{ + "version": "6", + "id": "9cf10c24-6029-4cb4-866e-ff9b501eaf7e", + "prevIds": ["bf19cd74-71f9-4bdf-b50e-67c2436f3408"], + "dialect": "mysql", + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "account", + "entityType": "columns" + }, + { + "name": "auth", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "auth", + "entityType": "columns" + }, + { + "type": "enum('email','github','google')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "auth", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subject", + "table": "auth", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "table": "auth", + "entityType": "columns" + }, + { + "name": "benchmark", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "agent", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "mediumtext", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "result", + "table": "benchmark", + "entityType": "columns" + }, + { + "name": "billing", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(32)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_type", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(4)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_last4", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "balance", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_trigger", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_amount", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_locked_till", + "table": "billing", + "entityType": "columns" + }, + { + "name": "payment", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "invoice_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "amount", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_refunded", + "table": "payment", + "entityType": "columns" + }, + { + "name": "usage", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "input_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "output_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reasoning_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_read_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_5m_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_1h_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cost", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key_id", + "table": "usage", + "entityType": "columns" + }, + { + "name": "ip_rate_limit", + "entityType": "tables" + }, + { + "type": "varchar(45)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "ip", + "table": "ip_rate_limit", + "entityType": "columns" + }, + { + "type": "varchar(10)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "interval", + "table": "ip_rate_limit", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "count", + "table": "ip_rate_limit", + "entityType": "columns" + }, + { + "name": "ip", + "entityType": "tables" + }, + { + "type": "varchar(45)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "ip", + "table": "ip", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "ip", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "ip", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "ip", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "usage", + "table": "ip", + "entityType": "columns" + }, + { + "name": "key", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "user_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_used", + "table": "key", + "entityType": "columns" + }, + { + "name": "model", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "model", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "model", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "model", + "entityType": "columns" + }, + { + "name": "provider", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "provider", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "provider", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "provider", + "entityType": "columns" + }, + { + "type": "text", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "credentials", + "table": "provider", + "entityType": "columns" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_seen", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "color", + "table": "user", + "entityType": "columns" + }, + { + "type": "enum('admin','member')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "role", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "user", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "user", + "entityType": "columns" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "slug", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "workspace", + "entityType": "columns" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "account", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "provider", + "isExpression": false + }, + { + "value": "subject", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "provider", + "table": "auth", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "account_id", + "table": "auth", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "auth", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "time_created", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "time_created", + "table": "benchmark", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "benchmark", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "customer_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_customer_id", + "table": "billing", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "billing", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "payment", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "time_created", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "usage_time_created", + "table": "usage", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "usage", + "entityType": "pks" + }, + { + "columns": ["ip", "interval"], + "name": "PRIMARY", + "table": "ip_rate_limit", + "entityType": "pks" + }, + { + "columns": ["ip"], + "name": "PRIMARY", + "table": "ip", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "key", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_key", + "table": "key", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "key", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "model", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "model_workspace_model", + "table": "model", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "model", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "provider", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "workspace_provider", + "table": "provider", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "provider", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "user", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "slug", + "table": "workspace", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "workspace", + "entityType": "pks" + } + ], + "renames": [] +} diff --git a/packages/console/core/migrations/0042_flat_nightmare.sql b/packages/console/core/migrations/20260107000117_flat_nightmare/migration.sql similarity index 100% rename from packages/console/core/migrations/0042_flat_nightmare.sql rename to packages/console/core/migrations/20260107000117_flat_nightmare/migration.sql diff --git a/packages/console/core/migrations/20260107000117_flat_nightmare/snapshot.json b/packages/console/core/migrations/20260107000117_flat_nightmare/snapshot.json new file mode 100644 index 0000000000..179c712ba7 --- /dev/null +++ b/packages/console/core/migrations/20260107000117_flat_nightmare/snapshot.json @@ -0,0 +1,2037 @@ +{ + "version": "6", + "id": "4775571c-ad9c-4104-a202-2374b1963cfe", + "prevIds": ["9cf10c24-6029-4cb4-866e-ff9b501eaf7e"], + "dialect": "mysql", + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "account", + "entityType": "columns" + }, + { + "name": "auth", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "auth", + "entityType": "columns" + }, + { + "type": "enum('email','github','google')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "auth", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subject", + "table": "auth", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "table": "auth", + "entityType": "columns" + }, + { + "name": "benchmark", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "agent", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "mediumtext", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "result", + "table": "benchmark", + "entityType": "columns" + }, + { + "name": "billing", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(32)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_type", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(4)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_last4", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "balance", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_trigger", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_amount", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_locked_till", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(28)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subscription_id", + "table": "billing", + "entityType": "columns" + }, + { + "name": "payment", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "invoice_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "amount", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_refunded", + "table": "payment", + "entityType": "columns" + }, + { + "name": "usage", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "input_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "output_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reasoning_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_read_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_5m_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_1h_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cost", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "data", + "table": "usage", + "entityType": "columns" + }, + { + "name": "ip_rate_limit", + "entityType": "tables" + }, + { + "type": "varchar(45)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "ip", + "table": "ip_rate_limit", + "entityType": "columns" + }, + { + "type": "varchar(10)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "interval", + "table": "ip_rate_limit", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "count", + "table": "ip_rate_limit", + "entityType": "columns" + }, + { + "name": "ip", + "entityType": "tables" + }, + { + "type": "varchar(45)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "ip", + "table": "ip", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "ip", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "ip", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "ip", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "usage", + "table": "ip", + "entityType": "columns" + }, + { + "name": "key", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "user_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_used", + "table": "key", + "entityType": "columns" + }, + { + "name": "model", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "model", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "model", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "model", + "entityType": "columns" + }, + { + "name": "provider", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "provider", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "provider", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "provider", + "entityType": "columns" + }, + { + "type": "text", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "credentials", + "table": "provider", + "entityType": "columns" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_seen", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "color", + "table": "user", + "entityType": "columns" + }, + { + "type": "enum('admin','member')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "role", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "user", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_subscribed", + "table": "user", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "sub_recent_usage", + "table": "user", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "sub_monthly_usage", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "sub_time_recent_usage_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "sub_time_monthly_usage_updated", + "table": "user", + "entityType": "columns" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "slug", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "workspace", + "entityType": "columns" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "account", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "provider", + "isExpression": false + }, + { + "value": "subject", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "provider", + "table": "auth", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "account_id", + "table": "auth", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "auth", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "time_created", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "time_created", + "table": "benchmark", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "benchmark", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "customer_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_customer_id", + "table": "billing", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "billing", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "payment", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "time_created", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "usage_time_created", + "table": "usage", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "usage", + "entityType": "pks" + }, + { + "columns": ["ip", "interval"], + "name": "PRIMARY", + "table": "ip_rate_limit", + "entityType": "pks" + }, + { + "columns": ["ip"], + "name": "PRIMARY", + "table": "ip", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "key", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_key", + "table": "key", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "key", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "model", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "model_workspace_model", + "table": "model", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "model", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "provider", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "workspace_provider", + "table": "provider", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "provider", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "user", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "slug", + "table": "workspace", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "workspace", + "entityType": "pks" + } + ], + "renames": [] +} diff --git a/packages/console/core/migrations/0043_lame_calypso.sql b/packages/console/core/migrations/20260107022356_lame_calypso/migration.sql similarity index 100% rename from packages/console/core/migrations/0043_lame_calypso.sql rename to packages/console/core/migrations/20260107022356_lame_calypso/migration.sql diff --git a/packages/console/core/migrations/20260107022356_lame_calypso/snapshot.json b/packages/console/core/migrations/20260107022356_lame_calypso/snapshot.json new file mode 100644 index 0000000000..27b00b6e00 --- /dev/null +++ b/packages/console/core/migrations/20260107022356_lame_calypso/snapshot.json @@ -0,0 +1,2037 @@ +{ + "version": "6", + "id": "3ff862f3-eeb6-4b10-8c78-254de3778ab3", + "prevIds": ["4775571c-ad9c-4104-a202-2374b1963cfe"], + "dialect": "mysql", + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "account", + "entityType": "columns" + }, + { + "name": "auth", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "auth", + "entityType": "columns" + }, + { + "type": "enum('email','github','google')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "auth", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subject", + "table": "auth", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "table": "auth", + "entityType": "columns" + }, + { + "name": "benchmark", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "agent", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "mediumtext", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "result", + "table": "benchmark", + "entityType": "columns" + }, + { + "name": "billing", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(32)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_type", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(4)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_last4", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "balance", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_trigger", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_amount", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_locked_till", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(28)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subscription_id", + "table": "billing", + "entityType": "columns" + }, + { + "name": "payment", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "invoice_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "amount", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_refunded", + "table": "payment", + "entityType": "columns" + }, + { + "name": "usage", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "input_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "output_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reasoning_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_read_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_5m_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_1h_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cost", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "data", + "table": "usage", + "entityType": "columns" + }, + { + "name": "ip_rate_limit", + "entityType": "tables" + }, + { + "type": "varchar(45)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "ip", + "table": "ip_rate_limit", + "entityType": "columns" + }, + { + "type": "varchar(10)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "interval", + "table": "ip_rate_limit", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "count", + "table": "ip_rate_limit", + "entityType": "columns" + }, + { + "name": "ip", + "entityType": "tables" + }, + { + "type": "varchar(45)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "ip", + "table": "ip", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "ip", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "ip", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "ip", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "usage", + "table": "ip", + "entityType": "columns" + }, + { + "name": "key", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "user_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_used", + "table": "key", + "entityType": "columns" + }, + { + "name": "model", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "model", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "model", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "model", + "entityType": "columns" + }, + { + "name": "provider", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "provider", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "provider", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "provider", + "entityType": "columns" + }, + { + "type": "text", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "credentials", + "table": "provider", + "entityType": "columns" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_seen", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "color", + "table": "user", + "entityType": "columns" + }, + { + "type": "enum('admin','member')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "role", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "user", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_subscribed", + "table": "user", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "sub_interval_usage", + "table": "user", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "sub_monthly_usage", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "sub_time_interval_usage_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "sub_time_monthly_usage_updated", + "table": "user", + "entityType": "columns" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "slug", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "workspace", + "entityType": "columns" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "account", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "provider", + "isExpression": false + }, + { + "value": "subject", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "provider", + "table": "auth", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "account_id", + "table": "auth", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "auth", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "time_created", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "time_created", + "table": "benchmark", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "benchmark", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "customer_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_customer_id", + "table": "billing", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "billing", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "payment", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "time_created", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "usage_time_created", + "table": "usage", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "usage", + "entityType": "pks" + }, + { + "columns": ["ip", "interval"], + "name": "PRIMARY", + "table": "ip_rate_limit", + "entityType": "pks" + }, + { + "columns": ["ip"], + "name": "PRIMARY", + "table": "ip", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "key", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_key", + "table": "key", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "key", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "model", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "model_workspace_model", + "table": "model", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "model", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "provider", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "workspace_provider", + "table": "provider", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "provider", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "user", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "slug", + "table": "workspace", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "workspace", + "entityType": "pks" + } + ], + "renames": [] +} diff --git a/packages/console/core/migrations/0044_tiny_captain_midlands.sql b/packages/console/core/migrations/20260107041522_tiny_captain_midlands/migration.sql similarity index 100% rename from packages/console/core/migrations/0044_tiny_captain_midlands.sql rename to packages/console/core/migrations/20260107041522_tiny_captain_midlands/migration.sql diff --git a/packages/console/core/migrations/20260107041522_tiny_captain_midlands/snapshot.json b/packages/console/core/migrations/20260107041522_tiny_captain_midlands/snapshot.json new file mode 100644 index 0000000000..088f95612d --- /dev/null +++ b/packages/console/core/migrations/20260107041522_tiny_captain_midlands/snapshot.json @@ -0,0 +1,2037 @@ +{ + "version": "6", + "id": "70394850-2c28-4012-a3d5-69357e3348b6", + "prevIds": ["3ff862f3-eeb6-4b10-8c78-254de3778ab3"], + "dialect": "mysql", + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "account", + "entityType": "columns" + }, + { + "name": "auth", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "auth", + "entityType": "columns" + }, + { + "type": "enum('email','github','google')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "auth", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subject", + "table": "auth", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "table": "auth", + "entityType": "columns" + }, + { + "name": "benchmark", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "agent", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "mediumtext", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "result", + "table": "benchmark", + "entityType": "columns" + }, + { + "name": "billing", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(32)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_type", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(4)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_last4", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "balance", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_trigger", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_amount", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_locked_till", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(28)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subscription_id", + "table": "billing", + "entityType": "columns" + }, + { + "name": "payment", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "invoice_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "amount", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_refunded", + "table": "payment", + "entityType": "columns" + }, + { + "name": "usage", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "input_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "output_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reasoning_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_read_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_5m_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_1h_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cost", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "enrichment", + "table": "usage", + "entityType": "columns" + }, + { + "name": "ip_rate_limit", + "entityType": "tables" + }, + { + "type": "varchar(45)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "ip", + "table": "ip_rate_limit", + "entityType": "columns" + }, + { + "type": "varchar(10)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "interval", + "table": "ip_rate_limit", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "count", + "table": "ip_rate_limit", + "entityType": "columns" + }, + { + "name": "ip", + "entityType": "tables" + }, + { + "type": "varchar(45)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "ip", + "table": "ip", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "ip", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "ip", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "ip", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "usage", + "table": "ip", + "entityType": "columns" + }, + { + "name": "key", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "user_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_used", + "table": "key", + "entityType": "columns" + }, + { + "name": "model", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "model", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "model", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "model", + "entityType": "columns" + }, + { + "name": "provider", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "provider", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "provider", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "provider", + "entityType": "columns" + }, + { + "type": "text", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "credentials", + "table": "provider", + "entityType": "columns" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_seen", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "color", + "table": "user", + "entityType": "columns" + }, + { + "type": "enum('admin','member')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "role", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "user", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_subscribed", + "table": "user", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "sub_interval_usage", + "table": "user", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "sub_monthly_usage", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "sub_time_interval_usage_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "sub_time_monthly_usage_updated", + "table": "user", + "entityType": "columns" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "slug", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "workspace", + "entityType": "columns" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "account", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "provider", + "isExpression": false + }, + { + "value": "subject", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "provider", + "table": "auth", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "account_id", + "table": "auth", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "auth", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "time_created", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "time_created", + "table": "benchmark", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "benchmark", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "customer_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_customer_id", + "table": "billing", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "billing", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "payment", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "time_created", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "usage_time_created", + "table": "usage", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "usage", + "entityType": "pks" + }, + { + "columns": ["ip", "interval"], + "name": "PRIMARY", + "table": "ip_rate_limit", + "entityType": "pks" + }, + { + "columns": ["ip"], + "name": "PRIMARY", + "table": "ip", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "key", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_key", + "table": "key", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "key", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "model", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "model_workspace_model", + "table": "model", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "model", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "provider", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "workspace_provider", + "table": "provider", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "provider", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "user", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "slug", + "table": "workspace", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "workspace", + "entityType": "pks" + } + ], + "renames": [] +} diff --git a/packages/console/core/migrations/0045_cuddly_diamondback.sql b/packages/console/core/migrations/20260107055817_cuddly_diamondback/migration.sql similarity index 100% rename from packages/console/core/migrations/0045_cuddly_diamondback.sql rename to packages/console/core/migrations/20260107055817_cuddly_diamondback/migration.sql diff --git a/packages/console/core/migrations/20260107055817_cuddly_diamondback/snapshot.json b/packages/console/core/migrations/20260107055817_cuddly_diamondback/snapshot.json new file mode 100644 index 0000000000..03fe57605a --- /dev/null +++ b/packages/console/core/migrations/20260107055817_cuddly_diamondback/snapshot.json @@ -0,0 +1,2053 @@ +{ + "version": "6", + "id": "27c1a3eb-b125-46d4-b436-abe5764fe4b7", + "prevIds": ["70394850-2c28-4012-a3d5-69357e3348b6"], + "dialect": "mysql", + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "account", + "entityType": "columns" + }, + { + "name": "auth", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "auth", + "entityType": "columns" + }, + { + "type": "enum('email','github','google')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "auth", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subject", + "table": "auth", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "table": "auth", + "entityType": "columns" + }, + { + "name": "benchmark", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "agent", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "mediumtext", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "result", + "table": "benchmark", + "entityType": "columns" + }, + { + "name": "billing", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(32)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_type", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(4)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_last4", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "balance", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_trigger", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_amount", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_locked_till", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(28)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subscription_id", + "table": "billing", + "entityType": "columns" + }, + { + "name": "payment", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "invoice_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "amount", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_refunded", + "table": "payment", + "entityType": "columns" + }, + { + "name": "usage", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "input_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "output_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reasoning_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_read_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_5m_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_1h_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cost", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "enrichment", + "table": "usage", + "entityType": "columns" + }, + { + "name": "ip_rate_limit", + "entityType": "tables" + }, + { + "type": "varchar(45)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "ip", + "table": "ip_rate_limit", + "entityType": "columns" + }, + { + "type": "varchar(10)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "interval", + "table": "ip_rate_limit", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "count", + "table": "ip_rate_limit", + "entityType": "columns" + }, + { + "name": "ip", + "entityType": "tables" + }, + { + "type": "varchar(45)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "ip", + "table": "ip", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "ip", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "ip", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "ip", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "usage", + "table": "ip", + "entityType": "columns" + }, + { + "name": "key", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "user_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_used", + "table": "key", + "entityType": "columns" + }, + { + "name": "model", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "model", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "model", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "model", + "entityType": "columns" + }, + { + "name": "provider", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "provider", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "provider", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "provider", + "entityType": "columns" + }, + { + "type": "text", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "credentials", + "table": "provider", + "entityType": "columns" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_seen", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "color", + "table": "user", + "entityType": "columns" + }, + { + "type": "enum('admin','member')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "role", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "user", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_subscribed", + "table": "user", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "sub_interval_usage", + "table": "user", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "sub_monthly_usage", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "sub_time_interval_usage_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "sub_time_monthly_usage_updated", + "table": "user", + "entityType": "columns" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "slug", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "workspace", + "entityType": "columns" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "account", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "provider", + "isExpression": false + }, + { + "value": "subject", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "provider", + "table": "auth", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "account_id", + "table": "auth", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "auth", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "time_created", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "time_created", + "table": "benchmark", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "benchmark", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "customer_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_customer_id", + "table": "billing", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "subscription_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_subscription_id", + "table": "billing", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "billing", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "payment", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "time_created", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "usage_time_created", + "table": "usage", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "usage", + "entityType": "pks" + }, + { + "columns": ["ip", "interval"], + "name": "PRIMARY", + "table": "ip_rate_limit", + "entityType": "pks" + }, + { + "columns": ["ip"], + "name": "PRIMARY", + "table": "ip", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "key", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_key", + "table": "key", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "key", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "model", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "model_workspace_model", + "table": "model", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "model", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "provider", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "workspace_provider", + "table": "provider", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "provider", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "user", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "slug", + "table": "workspace", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "workspace", + "entityType": "pks" + } + ], + "renames": [] +} diff --git a/packages/console/core/migrations/0046_charming_black_bolt.sql b/packages/console/core/migrations/20260108224422_charming_black_bolt/migration.sql similarity index 100% rename from packages/console/core/migrations/0046_charming_black_bolt.sql rename to packages/console/core/migrations/20260108224422_charming_black_bolt/migration.sql diff --git a/packages/console/core/migrations/20260108224422_charming_black_bolt/snapshot.json b/packages/console/core/migrations/20260108224422_charming_black_bolt/snapshot.json new file mode 100644 index 0000000000..90142e70ed --- /dev/null +++ b/packages/console/core/migrations/20260108224422_charming_black_bolt/snapshot.json @@ -0,0 +1,2203 @@ +{ + "version": "6", + "id": "f3725f6d-5f33-4497-b4ba-cf05c46fb873", + "prevIds": ["27c1a3eb-b125-46d4-b436-abe5764fe4b7"], + "dialect": "mysql", + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "account", + "entityType": "columns" + }, + { + "name": "auth", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "auth", + "entityType": "columns" + }, + { + "type": "enum('email','github','google')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "auth", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subject", + "table": "auth", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "table": "auth", + "entityType": "columns" + }, + { + "name": "benchmark", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "agent", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "mediumtext", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "result", + "table": "benchmark", + "entityType": "columns" + }, + { + "name": "billing", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(32)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_type", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(4)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_last4", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "balance", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_trigger", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_amount", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_locked_till", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(28)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subscription_id", + "table": "billing", + "entityType": "columns" + }, + { + "name": "payment", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "invoice_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "amount", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_refunded", + "table": "payment", + "entityType": "columns" + }, + { + "name": "subscription", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "user_id", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "rolling_usage", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "fixed_usage", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_rolling_updated", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_fixed_updated", + "table": "subscription", + "entityType": "columns" + }, + { + "name": "usage", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "input_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "output_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reasoning_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_read_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_5m_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_1h_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cost", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "enrichment", + "table": "usage", + "entityType": "columns" + }, + { + "name": "ip_rate_limit", + "entityType": "tables" + }, + { + "type": "varchar(45)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "ip", + "table": "ip_rate_limit", + "entityType": "columns" + }, + { + "type": "varchar(10)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "interval", + "table": "ip_rate_limit", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "count", + "table": "ip_rate_limit", + "entityType": "columns" + }, + { + "name": "ip", + "entityType": "tables" + }, + { + "type": "varchar(45)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "ip", + "table": "ip", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "ip", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "ip", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "ip", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "usage", + "table": "ip", + "entityType": "columns" + }, + { + "name": "key", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "user_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_used", + "table": "key", + "entityType": "columns" + }, + { + "name": "model", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "model", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "model", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "model", + "entityType": "columns" + }, + { + "name": "provider", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "provider", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "provider", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "provider", + "entityType": "columns" + }, + { + "type": "text", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "credentials", + "table": "provider", + "entityType": "columns" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_seen", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "color", + "table": "user", + "entityType": "columns" + }, + { + "type": "enum('admin','member')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "role", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "user", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_subscribed", + "table": "user", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "sub_interval_usage", + "table": "user", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "sub_monthly_usage", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "sub_time_interval_usage_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "sub_time_monthly_usage_updated", + "table": "user", + "entityType": "columns" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "slug", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "workspace", + "entityType": "columns" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "account", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "provider", + "isExpression": false + }, + { + "value": "subject", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "provider", + "table": "auth", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "account_id", + "table": "auth", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "auth", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "time_created", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "time_created", + "table": "benchmark", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "benchmark", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "customer_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_customer_id", + "table": "billing", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "subscription_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_subscription_id", + "table": "billing", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "billing", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "payment", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "subscription", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "time_created", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "usage_time_created", + "table": "usage", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "usage", + "entityType": "pks" + }, + { + "columns": ["ip", "interval"], + "name": "PRIMARY", + "table": "ip_rate_limit", + "entityType": "pks" + }, + { + "columns": ["ip"], + "name": "PRIMARY", + "table": "ip", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "key", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_key", + "table": "key", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "key", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "model", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "model_workspace_model", + "table": "model", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "model", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "provider", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "workspace_provider", + "table": "provider", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "provider", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "user", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "slug", + "table": "workspace", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "workspace", + "entityType": "pks" + } + ], + "renames": [] +} diff --git a/packages/console/core/migrations/0047_huge_omega_red.sql b/packages/console/core/migrations/20260109000245_huge_omega_red/migration.sql similarity index 100% rename from packages/console/core/migrations/0047_huge_omega_red.sql rename to packages/console/core/migrations/20260109000245_huge_omega_red/migration.sql diff --git a/packages/console/core/migrations/20260109000245_huge_omega_red/snapshot.json b/packages/console/core/migrations/20260109000245_huge_omega_red/snapshot.json new file mode 100644 index 0000000000..dad3cdbfa6 --- /dev/null +++ b/packages/console/core/migrations/20260109000245_huge_omega_red/snapshot.json @@ -0,0 +1,2153 @@ +{ + "version": "6", + "id": "fec4cb15-6f13-465d-a902-b76b026872f4", + "prevIds": ["f3725f6d-5f33-4497-b4ba-cf05c46fb873"], + "dialect": "mysql", + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "account", + "entityType": "columns" + }, + { + "name": "auth", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "auth", + "entityType": "columns" + }, + { + "type": "enum('email','github','google')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "auth", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subject", + "table": "auth", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "table": "auth", + "entityType": "columns" + }, + { + "name": "benchmark", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "agent", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "mediumtext", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "result", + "table": "benchmark", + "entityType": "columns" + }, + { + "name": "billing", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(32)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_type", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(4)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_last4", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "balance", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_trigger", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_amount", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_locked_till", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(28)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subscription_id", + "table": "billing", + "entityType": "columns" + }, + { + "name": "payment", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "invoice_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "amount", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_refunded", + "table": "payment", + "entityType": "columns" + }, + { + "name": "subscription", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "user_id", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "rolling_usage", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "fixed_usage", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_rolling_updated", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_fixed_updated", + "table": "subscription", + "entityType": "columns" + }, + { + "name": "usage", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "input_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "output_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reasoning_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_read_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_5m_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_1h_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cost", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "enrichment", + "table": "usage", + "entityType": "columns" + }, + { + "name": "ip_rate_limit", + "entityType": "tables" + }, + { + "type": "varchar(45)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "ip", + "table": "ip_rate_limit", + "entityType": "columns" + }, + { + "type": "varchar(10)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "interval", + "table": "ip_rate_limit", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "count", + "table": "ip_rate_limit", + "entityType": "columns" + }, + { + "name": "ip", + "entityType": "tables" + }, + { + "type": "varchar(45)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "ip", + "table": "ip", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "ip", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "ip", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "ip", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "usage", + "table": "ip", + "entityType": "columns" + }, + { + "name": "key", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "user_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_used", + "table": "key", + "entityType": "columns" + }, + { + "name": "model", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "model", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "model", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "model", + "entityType": "columns" + }, + { + "name": "provider", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "provider", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "provider", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "provider", + "entityType": "columns" + }, + { + "type": "text", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "credentials", + "table": "provider", + "entityType": "columns" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_seen", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "color", + "table": "user", + "entityType": "columns" + }, + { + "type": "enum('admin','member')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "role", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "user", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "user", + "entityType": "columns" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "slug", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "workspace", + "entityType": "columns" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "account", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "provider", + "isExpression": false + }, + { + "value": "subject", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "provider", + "table": "auth", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "account_id", + "table": "auth", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "auth", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "time_created", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "time_created", + "table": "benchmark", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "benchmark", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "customer_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_customer_id", + "table": "billing", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "subscription_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_subscription_id", + "table": "billing", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "billing", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "payment", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "user_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "workspace_user_id", + "table": "subscription", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "subscription", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "time_created", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "usage_time_created", + "table": "usage", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "usage", + "entityType": "pks" + }, + { + "columns": ["ip", "interval"], + "name": "PRIMARY", + "table": "ip_rate_limit", + "entityType": "pks" + }, + { + "columns": ["ip"], + "name": "PRIMARY", + "table": "ip", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "key", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_key", + "table": "key", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "key", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "model", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "model_workspace_model", + "table": "model", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "model", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "provider", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "workspace_provider", + "table": "provider", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "provider", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "user", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "slug", + "table": "workspace", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "workspace", + "entityType": "pks" + } + ], + "renames": [] +} diff --git a/packages/console/core/migrations/0048_mean_frank_castle.sql b/packages/console/core/migrations/20260109001625_mean_frank_castle/migration.sql similarity index 100% rename from packages/console/core/migrations/0048_mean_frank_castle.sql rename to packages/console/core/migrations/20260109001625_mean_frank_castle/migration.sql diff --git a/packages/console/core/migrations/20260109001625_mean_frank_castle/snapshot.json b/packages/console/core/migrations/20260109001625_mean_frank_castle/snapshot.json new file mode 100644 index 0000000000..9a43cd2bdf --- /dev/null +++ b/packages/console/core/migrations/20260109001625_mean_frank_castle/snapshot.json @@ -0,0 +1,2153 @@ +{ + "version": "6", + "id": "bb90bb3e-fd08-439a-b92f-5f433807480e", + "prevIds": ["fec4cb15-6f13-465d-a902-b76b026872f4"], + "dialect": "mysql", + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "account", + "entityType": "columns" + }, + { + "name": "auth", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "auth", + "entityType": "columns" + }, + { + "type": "enum('email','github','google')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "auth", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subject", + "table": "auth", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "table": "auth", + "entityType": "columns" + }, + { + "name": "benchmark", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "agent", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "mediumtext", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "result", + "table": "benchmark", + "entityType": "columns" + }, + { + "name": "billing", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(32)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_type", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(4)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_last4", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "balance", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_trigger", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_amount", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_locked_till", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(28)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subscription_id", + "table": "billing", + "entityType": "columns" + }, + { + "name": "payment", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "invoice_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "amount", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_refunded", + "table": "payment", + "entityType": "columns" + }, + { + "name": "subscription", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "user_id", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "rolling_usage", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "fixed_usage", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_rolling_updated", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_fixed_updated", + "table": "subscription", + "entityType": "columns" + }, + { + "name": "usage", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "input_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "output_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reasoning_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_read_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_5m_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_1h_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cost", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "enrichment", + "table": "usage", + "entityType": "columns" + }, + { + "name": "ip_rate_limit", + "entityType": "tables" + }, + { + "type": "varchar(45)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "ip", + "table": "ip_rate_limit", + "entityType": "columns" + }, + { + "type": "varchar(10)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "interval", + "table": "ip_rate_limit", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "count", + "table": "ip_rate_limit", + "entityType": "columns" + }, + { + "name": "ip", + "entityType": "tables" + }, + { + "type": "varchar(45)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "ip", + "table": "ip", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "ip", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "ip", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "ip", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "usage", + "table": "ip", + "entityType": "columns" + }, + { + "name": "key", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "user_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_used", + "table": "key", + "entityType": "columns" + }, + { + "name": "model", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "model", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "model", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "model", + "entityType": "columns" + }, + { + "name": "provider", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "provider", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "provider", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "provider", + "entityType": "columns" + }, + { + "type": "text", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "credentials", + "table": "provider", + "entityType": "columns" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_seen", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "color", + "table": "user", + "entityType": "columns" + }, + { + "type": "enum('admin','member')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "role", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "user", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "user", + "entityType": "columns" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "slug", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "workspace", + "entityType": "columns" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "account", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "provider", + "isExpression": false + }, + { + "value": "subject", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "provider", + "table": "auth", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "account_id", + "table": "auth", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "auth", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "time_created", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "time_created", + "table": "benchmark", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "benchmark", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "customer_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_customer_id", + "table": "billing", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "subscription_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_subscription_id", + "table": "billing", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "billing", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "payment", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "user_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "workspace_user_id", + "table": "subscription", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "subscription", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "time_created", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "usage_time_created", + "table": "usage", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "usage", + "entityType": "pks" + }, + { + "columns": ["ip", "interval"], + "name": "PRIMARY", + "table": "ip_rate_limit", + "entityType": "pks" + }, + { + "columns": ["ip"], + "name": "PRIMARY", + "table": "ip", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "key", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_key", + "table": "key", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "key", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "model", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "model_workspace_model", + "table": "model", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "model", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "provider", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "workspace_provider", + "table": "provider", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "provider", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "user", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "slug", + "table": "workspace", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "workspace", + "entityType": "pks" + } + ], + "renames": [] +} diff --git a/packages/console/core/migrations/0049_noisy_domino.sql b/packages/console/core/migrations/20260109014234_noisy_domino/migration.sql similarity index 100% rename from packages/console/core/migrations/0049_noisy_domino.sql rename to packages/console/core/migrations/20260109014234_noisy_domino/migration.sql diff --git a/packages/console/core/migrations/20260109014234_noisy_domino/snapshot.json b/packages/console/core/migrations/20260109014234_noisy_domino/snapshot.json new file mode 100644 index 0000000000..0e6084f51e --- /dev/null +++ b/packages/console/core/migrations/20260109014234_noisy_domino/snapshot.json @@ -0,0 +1,2167 @@ +{ + "version": "6", + "id": "2fd0308b-0653-437d-aea3-29428a4de9f1", + "prevIds": ["bb90bb3e-fd08-439a-b92f-5f433807480e"], + "dialect": "mysql", + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "account", + "entityType": "columns" + }, + { + "name": "auth", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "auth", + "entityType": "columns" + }, + { + "type": "enum('email','github','google')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "auth", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subject", + "table": "auth", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "table": "auth", + "entityType": "columns" + }, + { + "name": "benchmark", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "agent", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "mediumtext", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "result", + "table": "benchmark", + "entityType": "columns" + }, + { + "name": "billing", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(32)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_type", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(4)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_last4", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "balance", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_trigger", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_amount", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_locked_till", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(28)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subscription_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(28)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subscription_coupon_id", + "table": "billing", + "entityType": "columns" + }, + { + "name": "payment", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "invoice_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "amount", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_refunded", + "table": "payment", + "entityType": "columns" + }, + { + "name": "subscription", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "user_id", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "rolling_usage", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "fixed_usage", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_rolling_updated", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_fixed_updated", + "table": "subscription", + "entityType": "columns" + }, + { + "name": "usage", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "input_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "output_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reasoning_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_read_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_5m_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_1h_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cost", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "enrichment", + "table": "usage", + "entityType": "columns" + }, + { + "name": "ip_rate_limit", + "entityType": "tables" + }, + { + "type": "varchar(45)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "ip", + "table": "ip_rate_limit", + "entityType": "columns" + }, + { + "type": "varchar(10)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "interval", + "table": "ip_rate_limit", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "count", + "table": "ip_rate_limit", + "entityType": "columns" + }, + { + "name": "ip", + "entityType": "tables" + }, + { + "type": "varchar(45)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "ip", + "table": "ip", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "ip", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "ip", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "ip", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "usage", + "table": "ip", + "entityType": "columns" + }, + { + "name": "key", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "user_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_used", + "table": "key", + "entityType": "columns" + }, + { + "name": "model", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "model", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "model", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "model", + "entityType": "columns" + }, + { + "name": "provider", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "provider", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "provider", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "provider", + "entityType": "columns" + }, + { + "type": "text", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "credentials", + "table": "provider", + "entityType": "columns" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_seen", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "color", + "table": "user", + "entityType": "columns" + }, + { + "type": "enum('admin','member')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "role", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "user", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "user", + "entityType": "columns" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "slug", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "workspace", + "entityType": "columns" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "account", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "provider", + "isExpression": false + }, + { + "value": "subject", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "provider", + "table": "auth", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "account_id", + "table": "auth", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "auth", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "time_created", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "time_created", + "table": "benchmark", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "benchmark", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "customer_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_customer_id", + "table": "billing", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "subscription_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_subscription_id", + "table": "billing", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "billing", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "payment", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "user_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "workspace_user_id", + "table": "subscription", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "subscription", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "time_created", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "usage_time_created", + "table": "usage", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "usage", + "entityType": "pks" + }, + { + "columns": ["ip", "interval"], + "name": "PRIMARY", + "table": "ip_rate_limit", + "entityType": "pks" + }, + { + "columns": ["ip"], + "name": "PRIMARY", + "table": "ip", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "key", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_key", + "table": "key", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "key", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "model", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "model_workspace_model", + "table": "model", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "model", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "provider", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "workspace_provider", + "table": "provider", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "provider", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "user", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "slug", + "table": "workspace", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "workspace", + "entityType": "pks" + } + ], + "renames": [] +} diff --git a/packages/console/core/migrations/0050_bumpy_mephistopheles.sql b/packages/console/core/migrations/20260109040130_bumpy_mephistopheles/migration.sql similarity index 100% rename from packages/console/core/migrations/0050_bumpy_mephistopheles.sql rename to packages/console/core/migrations/20260109040130_bumpy_mephistopheles/migration.sql diff --git a/packages/console/core/migrations/20260109040130_bumpy_mephistopheles/snapshot.json b/packages/console/core/migrations/20260109040130_bumpy_mephistopheles/snapshot.json new file mode 100644 index 0000000000..ebff34d85d --- /dev/null +++ b/packages/console/core/migrations/20260109040130_bumpy_mephistopheles/snapshot.json @@ -0,0 +1,2181 @@ +{ + "version": "6", + "id": "a0d18802-c390-47d4-98f1-d1f83869cf0c", + "prevIds": ["2fd0308b-0653-437d-aea3-29428a4de9f1"], + "dialect": "mysql", + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "account", + "entityType": "columns" + }, + { + "name": "auth", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "auth", + "entityType": "columns" + }, + { + "type": "enum('email','github','google')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "auth", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subject", + "table": "auth", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "table": "auth", + "entityType": "columns" + }, + { + "name": "benchmark", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "agent", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "mediumtext", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "result", + "table": "benchmark", + "entityType": "columns" + }, + { + "name": "billing", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(32)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_type", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(4)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_last4", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "balance", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_trigger", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_amount", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_locked_till", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(28)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subscription_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(28)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subscription_coupon_id", + "table": "billing", + "entityType": "columns" + }, + { + "name": "payment", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "invoice_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "amount", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_refunded", + "table": "payment", + "entityType": "columns" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "enrichment", + "table": "payment", + "entityType": "columns" + }, + { + "name": "subscription", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "user_id", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "rolling_usage", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "fixed_usage", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_rolling_updated", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_fixed_updated", + "table": "subscription", + "entityType": "columns" + }, + { + "name": "usage", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "input_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "output_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reasoning_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_read_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_5m_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_1h_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cost", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "enrichment", + "table": "usage", + "entityType": "columns" + }, + { + "name": "ip_rate_limit", + "entityType": "tables" + }, + { + "type": "varchar(45)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "ip", + "table": "ip_rate_limit", + "entityType": "columns" + }, + { + "type": "varchar(10)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "interval", + "table": "ip_rate_limit", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "count", + "table": "ip_rate_limit", + "entityType": "columns" + }, + { + "name": "ip", + "entityType": "tables" + }, + { + "type": "varchar(45)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "ip", + "table": "ip", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "ip", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "ip", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "ip", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "usage", + "table": "ip", + "entityType": "columns" + }, + { + "name": "key", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "user_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_used", + "table": "key", + "entityType": "columns" + }, + { + "name": "model", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "model", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "model", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "model", + "entityType": "columns" + }, + { + "name": "provider", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "provider", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "provider", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "provider", + "entityType": "columns" + }, + { + "type": "text", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "credentials", + "table": "provider", + "entityType": "columns" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_seen", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "color", + "table": "user", + "entityType": "columns" + }, + { + "type": "enum('admin','member')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "role", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "user", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "user", + "entityType": "columns" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "slug", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "workspace", + "entityType": "columns" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "account", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "provider", + "isExpression": false + }, + { + "value": "subject", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "provider", + "table": "auth", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "account_id", + "table": "auth", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "auth", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "time_created", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "time_created", + "table": "benchmark", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "benchmark", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "customer_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_customer_id", + "table": "billing", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "subscription_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_subscription_id", + "table": "billing", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "billing", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "payment", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "user_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "workspace_user_id", + "table": "subscription", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "subscription", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "time_created", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "usage_time_created", + "table": "usage", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "usage", + "entityType": "pks" + }, + { + "columns": ["ip", "interval"], + "name": "PRIMARY", + "table": "ip_rate_limit", + "entityType": "pks" + }, + { + "columns": ["ip"], + "name": "PRIMARY", + "table": "ip", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "key", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_key", + "table": "key", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "key", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "model", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "model_workspace_model", + "table": "model", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "model", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "provider", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "workspace_provider", + "table": "provider", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "provider", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "user", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "slug", + "table": "workspace", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "workspace", + "entityType": "pks" + } + ], + "renames": [] +} diff --git a/packages/console/core/migrations/0051_jazzy_green_goblin.sql b/packages/console/core/migrations/20260113215232_jazzy_green_goblin/migration.sql similarity index 100% rename from packages/console/core/migrations/0051_jazzy_green_goblin.sql rename to packages/console/core/migrations/20260113215232_jazzy_green_goblin/migration.sql diff --git a/packages/console/core/migrations/20260113215232_jazzy_green_goblin/snapshot.json b/packages/console/core/migrations/20260113215232_jazzy_green_goblin/snapshot.json new file mode 100644 index 0000000000..f03e37f2f5 --- /dev/null +++ b/packages/console/core/migrations/20260113215232_jazzy_green_goblin/snapshot.json @@ -0,0 +1,2195 @@ +{ + "version": "6", + "id": "14cbf4c8-55f1-4488-956f-56fb5ccb3a5a", + "prevIds": ["a0d18802-c390-47d4-98f1-d1f83869cf0c"], + "dialect": "mysql", + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "account", + "entityType": "columns" + }, + { + "name": "auth", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "auth", + "entityType": "columns" + }, + { + "type": "enum('email','github','google')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "auth", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subject", + "table": "auth", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "table": "auth", + "entityType": "columns" + }, + { + "name": "benchmark", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "agent", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "mediumtext", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "result", + "table": "benchmark", + "entityType": "columns" + }, + { + "name": "billing", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(32)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_type", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(4)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_last4", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "balance", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_trigger", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_amount", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_locked_till", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(28)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subscription_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(28)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subscription_coupon_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_subscription_booked", + "table": "billing", + "entityType": "columns" + }, + { + "name": "payment", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "invoice_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "amount", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_refunded", + "table": "payment", + "entityType": "columns" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "enrichment", + "table": "payment", + "entityType": "columns" + }, + { + "name": "subscription", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "user_id", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "rolling_usage", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "fixed_usage", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_rolling_updated", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_fixed_updated", + "table": "subscription", + "entityType": "columns" + }, + { + "name": "usage", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "input_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "output_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reasoning_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_read_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_5m_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_1h_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cost", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "enrichment", + "table": "usage", + "entityType": "columns" + }, + { + "name": "ip_rate_limit", + "entityType": "tables" + }, + { + "type": "varchar(45)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "ip", + "table": "ip_rate_limit", + "entityType": "columns" + }, + { + "type": "varchar(10)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "interval", + "table": "ip_rate_limit", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "count", + "table": "ip_rate_limit", + "entityType": "columns" + }, + { + "name": "ip", + "entityType": "tables" + }, + { + "type": "varchar(45)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "ip", + "table": "ip", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "ip", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "ip", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "ip", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "usage", + "table": "ip", + "entityType": "columns" + }, + { + "name": "key", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "user_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_used", + "table": "key", + "entityType": "columns" + }, + { + "name": "model", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "model", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "model", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "model", + "entityType": "columns" + }, + { + "name": "provider", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "provider", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "provider", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "provider", + "entityType": "columns" + }, + { + "type": "text", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "credentials", + "table": "provider", + "entityType": "columns" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_seen", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "color", + "table": "user", + "entityType": "columns" + }, + { + "type": "enum('admin','member')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "role", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "user", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "user", + "entityType": "columns" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "slug", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "workspace", + "entityType": "columns" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "account", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "provider", + "isExpression": false + }, + { + "value": "subject", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "provider", + "table": "auth", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "account_id", + "table": "auth", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "auth", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "time_created", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "time_created", + "table": "benchmark", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "benchmark", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "customer_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_customer_id", + "table": "billing", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "subscription_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_subscription_id", + "table": "billing", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "billing", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "payment", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "user_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "workspace_user_id", + "table": "subscription", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "subscription", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "time_created", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "usage_time_created", + "table": "usage", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "usage", + "entityType": "pks" + }, + { + "columns": ["ip", "interval"], + "name": "PRIMARY", + "table": "ip_rate_limit", + "entityType": "pks" + }, + { + "columns": ["ip"], + "name": "PRIMARY", + "table": "ip", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "key", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_key", + "table": "key", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "key", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "model", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "model_workspace_model", + "table": "model", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "model", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "provider", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "workspace_provider", + "table": "provider", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "provider", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "user", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "slug", + "table": "workspace", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "workspace", + "entityType": "pks" + } + ], + "renames": [] +} diff --git a/packages/console/core/migrations/0052_aromatic_agent_zero.sql b/packages/console/core/migrations/20260113223840_aromatic_agent_zero/migration.sql similarity index 100% rename from packages/console/core/migrations/0052_aromatic_agent_zero.sql rename to packages/console/core/migrations/20260113223840_aromatic_agent_zero/migration.sql diff --git a/packages/console/core/migrations/20260113223840_aromatic_agent_zero/snapshot.json b/packages/console/core/migrations/20260113223840_aromatic_agent_zero/snapshot.json new file mode 100644 index 0000000000..000b6f5562 --- /dev/null +++ b/packages/console/core/migrations/20260113223840_aromatic_agent_zero/snapshot.json @@ -0,0 +1,2209 @@ +{ + "version": "6", + "id": "00774acd-a1e5-49c0-b296-cacc9506a566", + "prevIds": ["14cbf4c8-55f1-4488-956f-56fb5ccb3a5a"], + "dialect": "mysql", + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "account", + "entityType": "columns" + }, + { + "name": "auth", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "auth", + "entityType": "columns" + }, + { + "type": "enum('email','github','google')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "auth", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subject", + "table": "auth", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "table": "auth", + "entityType": "columns" + }, + { + "name": "benchmark", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "agent", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "mediumtext", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "result", + "table": "benchmark", + "entityType": "columns" + }, + { + "name": "billing", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(32)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_type", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(4)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_last4", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "balance", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_trigger", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_amount", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_locked_till", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(28)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subscription_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(28)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subscription_coupon_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "enum('20','100','200')", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subscription_plan", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_subscription_booked", + "table": "billing", + "entityType": "columns" + }, + { + "name": "payment", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "invoice_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "amount", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_refunded", + "table": "payment", + "entityType": "columns" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "enrichment", + "table": "payment", + "entityType": "columns" + }, + { + "name": "subscription", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "user_id", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "rolling_usage", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "fixed_usage", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_rolling_updated", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_fixed_updated", + "table": "subscription", + "entityType": "columns" + }, + { + "name": "usage", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "input_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "output_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reasoning_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_read_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_5m_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_1h_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cost", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "enrichment", + "table": "usage", + "entityType": "columns" + }, + { + "name": "ip_rate_limit", + "entityType": "tables" + }, + { + "type": "varchar(45)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "ip", + "table": "ip_rate_limit", + "entityType": "columns" + }, + { + "type": "varchar(10)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "interval", + "table": "ip_rate_limit", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "count", + "table": "ip_rate_limit", + "entityType": "columns" + }, + { + "name": "ip", + "entityType": "tables" + }, + { + "type": "varchar(45)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "ip", + "table": "ip", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "ip", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "ip", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "ip", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "usage", + "table": "ip", + "entityType": "columns" + }, + { + "name": "key", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "user_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_used", + "table": "key", + "entityType": "columns" + }, + { + "name": "model", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "model", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "model", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "model", + "entityType": "columns" + }, + { + "name": "provider", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "provider", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "provider", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "provider", + "entityType": "columns" + }, + { + "type": "text", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "credentials", + "table": "provider", + "entityType": "columns" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_seen", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "color", + "table": "user", + "entityType": "columns" + }, + { + "type": "enum('admin','member')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "role", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "user", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "user", + "entityType": "columns" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "slug", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "workspace", + "entityType": "columns" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "account", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "provider", + "isExpression": false + }, + { + "value": "subject", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "provider", + "table": "auth", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "account_id", + "table": "auth", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "auth", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "time_created", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "time_created", + "table": "benchmark", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "benchmark", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "customer_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_customer_id", + "table": "billing", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "subscription_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_subscription_id", + "table": "billing", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "billing", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "payment", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "user_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "workspace_user_id", + "table": "subscription", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "subscription", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "time_created", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "usage_time_created", + "table": "usage", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "usage", + "entityType": "pks" + }, + { + "columns": ["ip", "interval"], + "name": "PRIMARY", + "table": "ip_rate_limit", + "entityType": "pks" + }, + { + "columns": ["ip"], + "name": "PRIMARY", + "table": "ip", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "key", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_key", + "table": "key", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "key", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "model", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "model_workspace_model", + "table": "model", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "model", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "provider", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "workspace_provider", + "table": "provider", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "provider", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "user", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "slug", + "table": "workspace", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "workspace", + "entityType": "pks" + } + ], + "renames": [] +} diff --git a/packages/console/core/migrations/0053_gigantic_hardball.sql b/packages/console/core/migrations/20260116213606_gigantic_hardball/migration.sql similarity index 100% rename from packages/console/core/migrations/0053_gigantic_hardball.sql rename to packages/console/core/migrations/20260116213606_gigantic_hardball/migration.sql diff --git a/packages/console/core/migrations/20260116213606_gigantic_hardball/snapshot.json b/packages/console/core/migrations/20260116213606_gigantic_hardball/snapshot.json new file mode 100644 index 0000000000..d62a4ca582 --- /dev/null +++ b/packages/console/core/migrations/20260116213606_gigantic_hardball/snapshot.json @@ -0,0 +1,2223 @@ +{ + "version": "6", + "id": "32a0c40b-a269-4ad1-a5a0-52b1f18932aa", + "prevIds": ["00774acd-a1e5-49c0-b296-cacc9506a566"], + "dialect": "mysql", + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "account", + "entityType": "columns" + }, + { + "name": "auth", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "auth", + "entityType": "columns" + }, + { + "type": "enum('email','github','google')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "auth", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subject", + "table": "auth", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "table": "auth", + "entityType": "columns" + }, + { + "name": "benchmark", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "agent", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "mediumtext", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "result", + "table": "benchmark", + "entityType": "columns" + }, + { + "name": "billing", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(32)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_type", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(4)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_last4", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "balance", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_trigger", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_amount", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_locked_till", + "table": "billing", + "entityType": "columns" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subscription", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(28)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subscription_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(28)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subscription_coupon_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "enum('20','100','200')", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subscription_plan", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_subscription_booked", + "table": "billing", + "entityType": "columns" + }, + { + "name": "payment", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "invoice_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "amount", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_refunded", + "table": "payment", + "entityType": "columns" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "enrichment", + "table": "payment", + "entityType": "columns" + }, + { + "name": "subscription", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "user_id", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "rolling_usage", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "fixed_usage", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_rolling_updated", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_fixed_updated", + "table": "subscription", + "entityType": "columns" + }, + { + "name": "usage", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "input_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "output_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reasoning_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_read_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_5m_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_1h_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cost", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "enrichment", + "table": "usage", + "entityType": "columns" + }, + { + "name": "ip_rate_limit", + "entityType": "tables" + }, + { + "type": "varchar(45)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "ip", + "table": "ip_rate_limit", + "entityType": "columns" + }, + { + "type": "varchar(10)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "interval", + "table": "ip_rate_limit", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "count", + "table": "ip_rate_limit", + "entityType": "columns" + }, + { + "name": "ip", + "entityType": "tables" + }, + { + "type": "varchar(45)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "ip", + "table": "ip", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "ip", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "ip", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "ip", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "usage", + "table": "ip", + "entityType": "columns" + }, + { + "name": "key", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "user_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_used", + "table": "key", + "entityType": "columns" + }, + { + "name": "model", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "model", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "model", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "model", + "entityType": "columns" + }, + { + "name": "provider", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "provider", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "provider", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "provider", + "entityType": "columns" + }, + { + "type": "text", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "credentials", + "table": "provider", + "entityType": "columns" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_seen", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "color", + "table": "user", + "entityType": "columns" + }, + { + "type": "enum('admin','member')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "role", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "user", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "user", + "entityType": "columns" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "slug", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "workspace", + "entityType": "columns" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "account", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "provider", + "isExpression": false + }, + { + "value": "subject", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "provider", + "table": "auth", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "account_id", + "table": "auth", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "auth", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "time_created", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "time_created", + "table": "benchmark", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "benchmark", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "customer_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_customer_id", + "table": "billing", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "subscription_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_subscription_id", + "table": "billing", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "billing", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "payment", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "user_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "workspace_user_id", + "table": "subscription", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "subscription", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "time_created", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "usage_time_created", + "table": "usage", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "usage", + "entityType": "pks" + }, + { + "columns": ["ip", "interval"], + "name": "PRIMARY", + "table": "ip_rate_limit", + "entityType": "pks" + }, + { + "columns": ["ip"], + "name": "PRIMARY", + "table": "ip", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "key", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_key", + "table": "key", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "key", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "model", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "model_workspace_model", + "table": "model", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "model", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "provider", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "workspace_provider", + "table": "provider", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "provider", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "user", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "slug", + "table": "workspace", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "workspace", + "entityType": "pks" + } + ], + "renames": [] +} diff --git a/packages/console/core/migrations/0054_numerous_annihilus.sql b/packages/console/core/migrations/20260116224745_numerous_annihilus/migration.sql similarity index 100% rename from packages/console/core/migrations/0054_numerous_annihilus.sql rename to packages/console/core/migrations/20260116224745_numerous_annihilus/migration.sql diff --git a/packages/console/core/migrations/20260116224745_numerous_annihilus/snapshot.json b/packages/console/core/migrations/20260116224745_numerous_annihilus/snapshot.json new file mode 100644 index 0000000000..85f6c848a9 --- /dev/null +++ b/packages/console/core/migrations/20260116224745_numerous_annihilus/snapshot.json @@ -0,0 +1,2209 @@ +{ + "version": "6", + "id": "a0ade64b-b735-4a70-8d39-ebd84bc9e924", + "prevIds": ["32a0c40b-a269-4ad1-a5a0-52b1f18932aa"], + "dialect": "mysql", + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "account", + "entityType": "columns" + }, + { + "name": "auth", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "auth", + "entityType": "columns" + }, + { + "type": "enum('email','github','google')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "auth", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subject", + "table": "auth", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "table": "auth", + "entityType": "columns" + }, + { + "name": "benchmark", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "agent", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "mediumtext", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "result", + "table": "benchmark", + "entityType": "columns" + }, + { + "name": "billing", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(32)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_type", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(4)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_last4", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "balance", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_trigger", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_amount", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_locked_till", + "table": "billing", + "entityType": "columns" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subscription", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(28)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subscription_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "enum('20','100','200')", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subscription_plan", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_subscription_booked", + "table": "billing", + "entityType": "columns" + }, + { + "name": "payment", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "invoice_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "amount", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_refunded", + "table": "payment", + "entityType": "columns" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "enrichment", + "table": "payment", + "entityType": "columns" + }, + { + "name": "subscription", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "user_id", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "rolling_usage", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "fixed_usage", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_rolling_updated", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_fixed_updated", + "table": "subscription", + "entityType": "columns" + }, + { + "name": "usage", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "input_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "output_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reasoning_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_read_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_5m_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_1h_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cost", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "enrichment", + "table": "usage", + "entityType": "columns" + }, + { + "name": "ip_rate_limit", + "entityType": "tables" + }, + { + "type": "varchar(45)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "ip", + "table": "ip_rate_limit", + "entityType": "columns" + }, + { + "type": "varchar(10)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "interval", + "table": "ip_rate_limit", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "count", + "table": "ip_rate_limit", + "entityType": "columns" + }, + { + "name": "ip", + "entityType": "tables" + }, + { + "type": "varchar(45)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "ip", + "table": "ip", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "ip", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "ip", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "ip", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "usage", + "table": "ip", + "entityType": "columns" + }, + { + "name": "key", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "user_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_used", + "table": "key", + "entityType": "columns" + }, + { + "name": "model", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "model", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "model", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "model", + "entityType": "columns" + }, + { + "name": "provider", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "provider", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "provider", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "provider", + "entityType": "columns" + }, + { + "type": "text", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "credentials", + "table": "provider", + "entityType": "columns" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_seen", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "color", + "table": "user", + "entityType": "columns" + }, + { + "type": "enum('admin','member')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "role", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "user", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "user", + "entityType": "columns" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "slug", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "workspace", + "entityType": "columns" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "account", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "provider", + "isExpression": false + }, + { + "value": "subject", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "provider", + "table": "auth", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "account_id", + "table": "auth", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "auth", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "time_created", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "time_created", + "table": "benchmark", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "benchmark", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "customer_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_customer_id", + "table": "billing", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "subscription_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_subscription_id", + "table": "billing", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "billing", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "payment", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "user_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "workspace_user_id", + "table": "subscription", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "subscription", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "time_created", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "usage_time_created", + "table": "usage", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "usage", + "entityType": "pks" + }, + { + "columns": ["ip", "interval"], + "name": "PRIMARY", + "table": "ip_rate_limit", + "entityType": "pks" + }, + { + "columns": ["ip"], + "name": "PRIMARY", + "table": "ip", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "key", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_key", + "table": "key", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "key", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "model", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "model_workspace_model", + "table": "model", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "model", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "provider", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "workspace_provider", + "table": "provider", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "provider", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "user", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "slug", + "table": "workspace", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "workspace", + "entityType": "pks" + } + ], + "renames": [] +} diff --git a/packages/console/core/migrations/0055_moaning_karnak.sql b/packages/console/core/migrations/20260122190905_moaning_karnak/migration.sql similarity index 100% rename from packages/console/core/migrations/0055_moaning_karnak.sql rename to packages/console/core/migrations/20260122190905_moaning_karnak/migration.sql diff --git a/packages/console/core/migrations/20260122190905_moaning_karnak/snapshot.json b/packages/console/core/migrations/20260122190905_moaning_karnak/snapshot.json new file mode 100644 index 0000000000..cb606b01ae --- /dev/null +++ b/packages/console/core/migrations/20260122190905_moaning_karnak/snapshot.json @@ -0,0 +1,2223 @@ +{ + "version": "6", + "id": "e630f63c-04a8-4b59-bf56-03efcdd1b011", + "prevIds": ["a0ade64b-b735-4a70-8d39-ebd84bc9e924"], + "dialect": "mysql", + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "account", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "account", + "entityType": "columns" + }, + { + "name": "auth", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "auth", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "auth", + "entityType": "columns" + }, + { + "type": "enum('email','github','google')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "auth", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subject", + "table": "auth", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "table": "auth", + "entityType": "columns" + }, + { + "name": "benchmark", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "agent", + "table": "benchmark", + "entityType": "columns" + }, + { + "type": "mediumtext", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "result", + "table": "benchmark", + "entityType": "columns" + }, + { + "name": "billing", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(32)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_type", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(4)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_last4", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "balance", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "billing", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "billing", + "entityType": "columns" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_trigger", + "table": "billing", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_amount", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_error", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_locked_till", + "table": "billing", + "entityType": "columns" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subscription", + "table": "billing", + "entityType": "columns" + }, + { + "type": "varchar(28)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subscription_id", + "table": "billing", + "entityType": "columns" + }, + { + "type": "enum('20','100','200')", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subscription_plan", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_subscription_booked", + "table": "billing", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_subscription_selected", + "table": "billing", + "entityType": "columns" + }, + { + "name": "payment", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "invoice_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_id", + "table": "payment", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "amount", + "table": "payment", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_refunded", + "table": "payment", + "entityType": "columns" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "enrichment", + "table": "payment", + "entityType": "columns" + }, + { + "name": "subscription", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "user_id", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "rolling_usage", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "fixed_usage", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_rolling_updated", + "table": "subscription", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_fixed_updated", + "table": "subscription", + "entityType": "columns" + }, + { + "name": "usage", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "usage", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "input_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "output_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reasoning_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_read_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_5m_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_1h_tokens", + "table": "usage", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cost", + "table": "usage", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key_id", + "table": "usage", + "entityType": "columns" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "enrichment", + "table": "usage", + "entityType": "columns" + }, + { + "name": "ip_rate_limit", + "entityType": "tables" + }, + { + "type": "varchar(45)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "ip", + "table": "ip_rate_limit", + "entityType": "columns" + }, + { + "type": "varchar(10)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "interval", + "table": "ip_rate_limit", + "entityType": "columns" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "count", + "table": "ip_rate_limit", + "entityType": "columns" + }, + { + "name": "ip", + "entityType": "tables" + }, + { + "type": "varchar(45)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "ip", + "table": "ip", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "ip", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "ip", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "ip", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "usage", + "table": "ip", + "entityType": "columns" + }, + { + "name": "key", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "table": "key", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "user_id", + "table": "key", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_used", + "table": "key", + "entityType": "columns" + }, + { + "name": "model", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "model", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "model", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "model", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "table": "model", + "entityType": "columns" + }, + { + "name": "provider", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "provider", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "provider", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "provider", + "entityType": "columns" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "table": "provider", + "entityType": "columns" + }, + { + "type": "text", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "credentials", + "table": "provider", + "entityType": "columns" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "table": "user", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_seen", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "color", + "table": "user", + "entityType": "columns" + }, + { + "type": "enum('admin','member')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "role", + "table": "user", + "entityType": "columns" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "table": "user", + "entityType": "columns" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "table": "user", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "table": "user", + "entityType": "columns" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "slug", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "table": "workspace", + "entityType": "columns" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "table": "workspace", + "entityType": "columns" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "account", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "provider", + "isExpression": false + }, + { + "value": "subject", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "provider", + "table": "auth", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "account_id", + "table": "auth", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "auth", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "time_created", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "time_created", + "table": "benchmark", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "benchmark", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "customer_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_customer_id", + "table": "billing", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "subscription_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_subscription_id", + "table": "billing", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "billing", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "payment", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "user_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "workspace_user_id", + "table": "subscription", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "subscription", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "time_created", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "usage_time_created", + "table": "usage", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "usage", + "entityType": "pks" + }, + { + "columns": ["ip", "interval"], + "name": "PRIMARY", + "table": "ip_rate_limit", + "entityType": "pks" + }, + { + "columns": ["ip"], + "name": "PRIMARY", + "table": "ip", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "key", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_key", + "table": "key", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "key", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "model", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "model_workspace_model", + "table": "model", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "model", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "provider", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "workspace_provider", + "table": "provider", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "provider", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_account_id", + "table": "user", + "entityType": "indexes" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_email", + "table": "user", + "entityType": "indexes" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "user", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "slug", + "table": "workspace", + "entityType": "indexes" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "workspace", + "entityType": "pks" + } + ], + "renames": [] +} diff --git a/packages/console/core/migrations/20260222233442_clever_toxin/migration.sql b/packages/console/core/migrations/20260222233442_clever_toxin/migration.sql new file mode 100644 index 0000000000..03cfe4c033 --- /dev/null +++ b/packages/console/core/migrations/20260222233442_clever_toxin/migration.sql @@ -0,0 +1 @@ +ALTER TABLE `usage` ADD `session_id` varchar(30); \ No newline at end of file diff --git a/packages/console/core/migrations/20260222233442_clever_toxin/snapshot.json b/packages/console/core/migrations/20260222233442_clever_toxin/snapshot.json new file mode 100644 index 0000000000..a91dacd60e --- /dev/null +++ b/packages/console/core/migrations/20260222233442_clever_toxin/snapshot.json @@ -0,0 +1,2237 @@ +{ + "version": "6", + "dialect": "mysql", + "id": "4bf45b3f-3edd-4db7-94d5-097aa55ca5f7", + "prevIds": ["e630f63c-04a8-4b59-bf56-03efcdd1b011"], + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "name": "auth", + "entityType": "tables" + }, + { + "name": "benchmark", + "entityType": "tables" + }, + { + "name": "billing", + "entityType": "tables" + }, + { + "name": "payment", + "entityType": "tables" + }, + { + "name": "subscription", + "entityType": "tables" + }, + { + "name": "usage", + "entityType": "tables" + }, + { + "name": "ip_rate_limit", + "entityType": "tables" + }, + { + "name": "ip", + "entityType": "tables" + }, + { + "name": "key", + "entityType": "tables" + }, + { + "name": "model", + "entityType": "tables" + }, + { + "name": "provider", + "entityType": "tables" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "account" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "account" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "account" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "entityType": "columns", + "table": "account" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "auth" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "auth" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "auth" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "entityType": "columns", + "table": "auth" + }, + { + "type": "enum('email','github','google')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "entityType": "columns", + "table": "auth" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subject", + "entityType": "columns", + "table": "auth" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "entityType": "columns", + "table": "auth" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "benchmark" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "benchmark" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "benchmark" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "entityType": "columns", + "table": "benchmark" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "entityType": "columns", + "table": "benchmark" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "agent", + "entityType": "columns", + "table": "benchmark" + }, + { + "type": "mediumtext", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "result", + "entityType": "columns", + "table": "benchmark" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "billing" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "entityType": "columns", + "table": "billing" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "billing" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "billing" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "entityType": "columns", + "table": "billing" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "entityType": "columns", + "table": "billing" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_id", + "entityType": "columns", + "table": "billing" + }, + { + "type": "varchar(32)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_type", + "entityType": "columns", + "table": "billing" + }, + { + "type": "varchar(4)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_last4", + "entityType": "columns", + "table": "billing" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "balance", + "entityType": "columns", + "table": "billing" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "entityType": "columns", + "table": "billing" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "entityType": "columns", + "table": "billing" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "entityType": "columns", + "table": "billing" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload", + "entityType": "columns", + "table": "billing" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_trigger", + "entityType": "columns", + "table": "billing" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_amount", + "entityType": "columns", + "table": "billing" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_error", + "entityType": "columns", + "table": "billing" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_error", + "entityType": "columns", + "table": "billing" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_locked_till", + "entityType": "columns", + "table": "billing" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subscription", + "entityType": "columns", + "table": "billing" + }, + { + "type": "varchar(28)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subscription_id", + "entityType": "columns", + "table": "billing" + }, + { + "type": "enum('20','100','200')", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subscription_plan", + "entityType": "columns", + "table": "billing" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_subscription_booked", + "entityType": "columns", + "table": "billing" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_subscription_selected", + "entityType": "columns", + "table": "billing" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "payment" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "entityType": "columns", + "table": "payment" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "payment" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "payment" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "entityType": "columns", + "table": "payment" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "entityType": "columns", + "table": "payment" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "invoice_id", + "entityType": "columns", + "table": "payment" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_id", + "entityType": "columns", + "table": "payment" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "amount", + "entityType": "columns", + "table": "payment" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_refunded", + "entityType": "columns", + "table": "payment" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "enrichment", + "entityType": "columns", + "table": "payment" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "subscription" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "entityType": "columns", + "table": "subscription" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "subscription" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "subscription" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "entityType": "columns", + "table": "subscription" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "user_id", + "entityType": "columns", + "table": "subscription" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "rolling_usage", + "entityType": "columns", + "table": "subscription" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "fixed_usage", + "entityType": "columns", + "table": "subscription" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_rolling_updated", + "entityType": "columns", + "table": "subscription" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_fixed_updated", + "entityType": "columns", + "table": "subscription" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "usage" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "entityType": "columns", + "table": "usage" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "usage" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "usage" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "entityType": "columns", + "table": "usage" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "entityType": "columns", + "table": "usage" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "entityType": "columns", + "table": "usage" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "input_tokens", + "entityType": "columns", + "table": "usage" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "output_tokens", + "entityType": "columns", + "table": "usage" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reasoning_tokens", + "entityType": "columns", + "table": "usage" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_read_tokens", + "entityType": "columns", + "table": "usage" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_5m_tokens", + "entityType": "columns", + "table": "usage" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_1h_tokens", + "entityType": "columns", + "table": "usage" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cost", + "entityType": "columns", + "table": "usage" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key_id", + "entityType": "columns", + "table": "usage" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "session_id", + "entityType": "columns", + "table": "usage" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "enrichment", + "entityType": "columns", + "table": "usage" + }, + { + "type": "varchar(45)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "ip", + "entityType": "columns", + "table": "ip_rate_limit" + }, + { + "type": "varchar(10)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "interval", + "entityType": "columns", + "table": "ip_rate_limit" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "count", + "entityType": "columns", + "table": "ip_rate_limit" + }, + { + "type": "varchar(45)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "ip", + "entityType": "columns", + "table": "ip" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "ip" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "ip" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "entityType": "columns", + "table": "ip" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "usage", + "entityType": "columns", + "table": "ip" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "key" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "entityType": "columns", + "table": "key" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "key" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "key" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "entityType": "columns", + "table": "key" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "entityType": "columns", + "table": "key" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "entityType": "columns", + "table": "key" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "user_id", + "entityType": "columns", + "table": "key" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_used", + "entityType": "columns", + "table": "key" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "model" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "entityType": "columns", + "table": "model" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "model" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "model" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "entityType": "columns", + "table": "model" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "entityType": "columns", + "table": "model" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "provider" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "entityType": "columns", + "table": "provider" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "provider" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "provider" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "entityType": "columns", + "table": "provider" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "entityType": "columns", + "table": "provider" + }, + { + "type": "text", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "credentials", + "entityType": "columns", + "table": "provider" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "user" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "entityType": "columns", + "table": "user" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "user" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "user" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "entityType": "columns", + "table": "user" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "entityType": "columns", + "table": "user" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "entityType": "columns", + "table": "user" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "entityType": "columns", + "table": "user" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_seen", + "entityType": "columns", + "table": "user" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "color", + "entityType": "columns", + "table": "user" + }, + { + "type": "enum('admin','member')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "role", + "entityType": "columns", + "table": "user" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "entityType": "columns", + "table": "user" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "entityType": "columns", + "table": "user" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "entityType": "columns", + "table": "user" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "workspace" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "slug", + "entityType": "columns", + "table": "workspace" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "entityType": "columns", + "table": "workspace" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "workspace" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "workspace" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "entityType": "columns", + "table": "workspace" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "account", + "entityType": "pks" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "auth", + "entityType": "pks" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "benchmark", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "billing", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "payment", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "subscription", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "usage", + "entityType": "pks" + }, + { + "columns": ["ip", "interval"], + "name": "PRIMARY", + "table": "ip_rate_limit", + "entityType": "pks" + }, + { + "columns": ["ip"], + "name": "PRIMARY", + "table": "ip", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "key", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "model", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "provider", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "user", + "entityType": "pks" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "workspace", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "provider", + "isExpression": false + }, + { + "value": "subject", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "provider", + "entityType": "indexes", + "table": "auth" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "account_id", + "entityType": "indexes", + "table": "auth" + }, + { + "columns": [ + { + "value": "time_created", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "time_created", + "entityType": "indexes", + "table": "benchmark" + }, + { + "columns": [ + { + "value": "customer_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_customer_id", + "entityType": "indexes", + "table": "billing" + }, + { + "columns": [ + { + "value": "subscription_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_subscription_id", + "entityType": "indexes", + "table": "billing" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "user_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "workspace_user_id", + "entityType": "indexes", + "table": "subscription" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "time_created", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "usage_time_created", + "entityType": "indexes", + "table": "usage" + }, + { + "columns": [ + { + "value": "key", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_key", + "entityType": "indexes", + "table": "key" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "model", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "model_workspace_model", + "entityType": "indexes", + "table": "model" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "provider", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "workspace_provider", + "entityType": "indexes", + "table": "provider" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_account_id", + "entityType": "indexes", + "table": "user" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_email", + "entityType": "indexes", + "table": "user" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_account_id", + "entityType": "indexes", + "table": "user" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_email", + "entityType": "indexes", + "table": "user" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "slug", + "entityType": "indexes", + "table": "workspace" + } + ], + "renames": [] +} diff --git a/packages/console/core/migrations/20260224043338_nifty_starjammers/migration.sql b/packages/console/core/migrations/20260224043338_nifty_starjammers/migration.sql new file mode 100644 index 0000000000..1c97afbd98 --- /dev/null +++ b/packages/console/core/migrations/20260224043338_nifty_starjammers/migration.sql @@ -0,0 +1,19 @@ +CREATE TABLE `lite` ( + `id` varchar(30) NOT NULL, + `workspace_id` varchar(30) NOT NULL, + `time_created` timestamp(3) NOT NULL DEFAULT (now()), + `time_updated` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), + `time_deleted` timestamp(3), + `user_id` varchar(30) NOT NULL, + `rolling_usage` bigint, + `weekly_usage` bigint, + `monthly_usage` bigint, + `time_rolling_updated` timestamp(3), + `time_weekly_updated` timestamp(3), + `time_monthly_updated` timestamp(3), + CONSTRAINT `PRIMARY` PRIMARY KEY(`workspace_id`,`id`), + CONSTRAINT `workspace_user_id` UNIQUE INDEX(`workspace_id`,`user_id`) +); +--> statement-breakpoint +ALTER TABLE `billing` ADD `lite_subscription_id` varchar(28);--> statement-breakpoint +ALTER TABLE `billing` ADD `lite` json; \ No newline at end of file diff --git a/packages/console/core/migrations/20260224043338_nifty_starjammers/snapshot.json b/packages/console/core/migrations/20260224043338_nifty_starjammers/snapshot.json new file mode 100644 index 0000000000..bc20ee2b96 --- /dev/null +++ b/packages/console/core/migrations/20260224043338_nifty_starjammers/snapshot.json @@ -0,0 +1,2463 @@ +{ + "version": "6", + "dialect": "mysql", + "id": "5e506dec-61e7-4726-81d1-afa4ffbc61ed", + "prevIds": ["4bf45b3f-3edd-4db7-94d5-097aa55ca5f7"], + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "name": "auth", + "entityType": "tables" + }, + { + "name": "benchmark", + "entityType": "tables" + }, + { + "name": "billing", + "entityType": "tables" + }, + { + "name": "lite", + "entityType": "tables" + }, + { + "name": "payment", + "entityType": "tables" + }, + { + "name": "subscription", + "entityType": "tables" + }, + { + "name": "usage", + "entityType": "tables" + }, + { + "name": "ip_rate_limit", + "entityType": "tables" + }, + { + "name": "ip", + "entityType": "tables" + }, + { + "name": "key", + "entityType": "tables" + }, + { + "name": "model", + "entityType": "tables" + }, + { + "name": "provider", + "entityType": "tables" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "account" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "account" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "account" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "entityType": "columns", + "table": "account" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "auth" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "auth" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "auth" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "entityType": "columns", + "table": "auth" + }, + { + "type": "enum('email','github','google')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "entityType": "columns", + "table": "auth" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subject", + "entityType": "columns", + "table": "auth" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "entityType": "columns", + "table": "auth" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "benchmark" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "benchmark" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "benchmark" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "entityType": "columns", + "table": "benchmark" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "entityType": "columns", + "table": "benchmark" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "agent", + "entityType": "columns", + "table": "benchmark" + }, + { + "type": "mediumtext", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "result", + "entityType": "columns", + "table": "benchmark" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "billing" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "entityType": "columns", + "table": "billing" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "billing" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "billing" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "entityType": "columns", + "table": "billing" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "entityType": "columns", + "table": "billing" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_id", + "entityType": "columns", + "table": "billing" + }, + { + "type": "varchar(32)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_type", + "entityType": "columns", + "table": "billing" + }, + { + "type": "varchar(4)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_last4", + "entityType": "columns", + "table": "billing" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "balance", + "entityType": "columns", + "table": "billing" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "entityType": "columns", + "table": "billing" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "entityType": "columns", + "table": "billing" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "entityType": "columns", + "table": "billing" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload", + "entityType": "columns", + "table": "billing" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_trigger", + "entityType": "columns", + "table": "billing" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_amount", + "entityType": "columns", + "table": "billing" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_error", + "entityType": "columns", + "table": "billing" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_error", + "entityType": "columns", + "table": "billing" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_locked_till", + "entityType": "columns", + "table": "billing" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subscription", + "entityType": "columns", + "table": "billing" + }, + { + "type": "varchar(28)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subscription_id", + "entityType": "columns", + "table": "billing" + }, + { + "type": "enum('20','100','200')", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subscription_plan", + "entityType": "columns", + "table": "billing" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_subscription_booked", + "entityType": "columns", + "table": "billing" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_subscription_selected", + "entityType": "columns", + "table": "billing" + }, + { + "type": "varchar(28)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "lite_subscription_id", + "entityType": "columns", + "table": "billing" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "lite", + "entityType": "columns", + "table": "billing" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "lite" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "entityType": "columns", + "table": "lite" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "lite" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "lite" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "entityType": "columns", + "table": "lite" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "user_id", + "entityType": "columns", + "table": "lite" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "rolling_usage", + "entityType": "columns", + "table": "lite" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "weekly_usage", + "entityType": "columns", + "table": "lite" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "entityType": "columns", + "table": "lite" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_rolling_updated", + "entityType": "columns", + "table": "lite" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_weekly_updated", + "entityType": "columns", + "table": "lite" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_updated", + "entityType": "columns", + "table": "lite" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "payment" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "entityType": "columns", + "table": "payment" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "payment" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "payment" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "entityType": "columns", + "table": "payment" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "entityType": "columns", + "table": "payment" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "invoice_id", + "entityType": "columns", + "table": "payment" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_id", + "entityType": "columns", + "table": "payment" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "amount", + "entityType": "columns", + "table": "payment" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_refunded", + "entityType": "columns", + "table": "payment" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "enrichment", + "entityType": "columns", + "table": "payment" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "subscription" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "entityType": "columns", + "table": "subscription" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "subscription" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "subscription" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "entityType": "columns", + "table": "subscription" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "user_id", + "entityType": "columns", + "table": "subscription" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "rolling_usage", + "entityType": "columns", + "table": "subscription" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "fixed_usage", + "entityType": "columns", + "table": "subscription" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_rolling_updated", + "entityType": "columns", + "table": "subscription" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_fixed_updated", + "entityType": "columns", + "table": "subscription" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "usage" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "entityType": "columns", + "table": "usage" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "usage" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "usage" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "entityType": "columns", + "table": "usage" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "entityType": "columns", + "table": "usage" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "entityType": "columns", + "table": "usage" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "input_tokens", + "entityType": "columns", + "table": "usage" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "output_tokens", + "entityType": "columns", + "table": "usage" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reasoning_tokens", + "entityType": "columns", + "table": "usage" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_read_tokens", + "entityType": "columns", + "table": "usage" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_5m_tokens", + "entityType": "columns", + "table": "usage" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_1h_tokens", + "entityType": "columns", + "table": "usage" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cost", + "entityType": "columns", + "table": "usage" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key_id", + "entityType": "columns", + "table": "usage" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "session_id", + "entityType": "columns", + "table": "usage" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "enrichment", + "entityType": "columns", + "table": "usage" + }, + { + "type": "varchar(45)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "ip", + "entityType": "columns", + "table": "ip_rate_limit" + }, + { + "type": "varchar(10)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "interval", + "entityType": "columns", + "table": "ip_rate_limit" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "count", + "entityType": "columns", + "table": "ip_rate_limit" + }, + { + "type": "varchar(45)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "ip", + "entityType": "columns", + "table": "ip" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "ip" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "ip" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "entityType": "columns", + "table": "ip" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "usage", + "entityType": "columns", + "table": "ip" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "key" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "entityType": "columns", + "table": "key" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "key" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "key" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "entityType": "columns", + "table": "key" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "entityType": "columns", + "table": "key" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "entityType": "columns", + "table": "key" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "user_id", + "entityType": "columns", + "table": "key" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_used", + "entityType": "columns", + "table": "key" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "model" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "entityType": "columns", + "table": "model" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "model" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "model" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "entityType": "columns", + "table": "model" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "entityType": "columns", + "table": "model" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "provider" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "entityType": "columns", + "table": "provider" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "provider" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "provider" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "entityType": "columns", + "table": "provider" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "entityType": "columns", + "table": "provider" + }, + { + "type": "text", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "credentials", + "entityType": "columns", + "table": "provider" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "user" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "entityType": "columns", + "table": "user" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "user" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "user" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "entityType": "columns", + "table": "user" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "entityType": "columns", + "table": "user" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "entityType": "columns", + "table": "user" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "entityType": "columns", + "table": "user" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_seen", + "entityType": "columns", + "table": "user" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "color", + "entityType": "columns", + "table": "user" + }, + { + "type": "enum('admin','member')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "role", + "entityType": "columns", + "table": "user" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "entityType": "columns", + "table": "user" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "entityType": "columns", + "table": "user" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "entityType": "columns", + "table": "user" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "workspace" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "slug", + "entityType": "columns", + "table": "workspace" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "entityType": "columns", + "table": "workspace" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "workspace" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "workspace" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "entityType": "columns", + "table": "workspace" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "account", + "entityType": "pks" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "auth", + "entityType": "pks" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "benchmark", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "billing", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "lite", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "payment", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "subscription", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "usage", + "entityType": "pks" + }, + { + "columns": ["ip", "interval"], + "name": "PRIMARY", + "table": "ip_rate_limit", + "entityType": "pks" + }, + { + "columns": ["ip"], + "name": "PRIMARY", + "table": "ip", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "key", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "model", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "provider", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "user", + "entityType": "pks" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "workspace", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "provider", + "isExpression": false + }, + { + "value": "subject", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "provider", + "entityType": "indexes", + "table": "auth" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "account_id", + "entityType": "indexes", + "table": "auth" + }, + { + "columns": [ + { + "value": "time_created", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "time_created", + "entityType": "indexes", + "table": "benchmark" + }, + { + "columns": [ + { + "value": "customer_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_customer_id", + "entityType": "indexes", + "table": "billing" + }, + { + "columns": [ + { + "value": "subscription_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_subscription_id", + "entityType": "indexes", + "table": "billing" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "user_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "workspace_user_id", + "entityType": "indexes", + "table": "lite" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "user_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "workspace_user_id", + "entityType": "indexes", + "table": "subscription" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "time_created", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "usage_time_created", + "entityType": "indexes", + "table": "usage" + }, + { + "columns": [ + { + "value": "key", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_key", + "entityType": "indexes", + "table": "key" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "model", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "model_workspace_model", + "entityType": "indexes", + "table": "model" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "provider", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "workspace_provider", + "entityType": "indexes", + "table": "provider" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_account_id", + "entityType": "indexes", + "table": "user" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_email", + "entityType": "indexes", + "table": "user" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_account_id", + "entityType": "indexes", + "table": "user" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_email", + "entityType": "indexes", + "table": "user" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "slug", + "entityType": "indexes", + "table": "workspace" + } + ], + "renames": [] +} diff --git a/packages/console/core/migrations/meta/0000_snapshot.json b/packages/console/core/migrations/meta/0000_snapshot.json deleted file mode 100644 index 17d3bd7f9d..0000000000 --- a/packages/console/core/migrations/meta/0000_snapshot.json +++ /dev/null @@ -1,569 +0,0 @@ -{ - "version": "5", - "dialect": "mysql", - "id": "aee779c5-db1d-4655-95ec-6451c18455be", - "prevId": "00000000-0000-0000-0000-000000000000", - "tables": { - "account": { - "name": "account", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "email": { - "name": "email", - "columns": ["email"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "billing": { - "name": "billing", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "payment": { - "name": "payment", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "usage": { - "name": "usage", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "input_tokens": { - "name": "input_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "output_tokens": { - "name": "output_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_tokens": { - "name": "cache_write_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "key": { - "name": "key", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "key": { - "name": "key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_used": { - "name": "time_used", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_key": { - "name": "global_key", - "columns": ["key"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "key_workspace_id_id_pk": { - "name": "key_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "color": { - "name": "color", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "user_email": { - "name": "user_email", - "columns": ["workspace_id", "email"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "workspace": { - "name": "workspace", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": ["slug"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "workspace_id": { - "name": "workspace_id", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - } - }, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "tables": {}, - "indexes": {} - } -} diff --git a/packages/console/core/migrations/meta/0001_snapshot.json b/packages/console/core/migrations/meta/0001_snapshot.json deleted file mode 100644 index d23d1601d9..0000000000 --- a/packages/console/core/migrations/meta/0001_snapshot.json +++ /dev/null @@ -1,569 +0,0 @@ -{ - "version": "5", - "dialect": "mysql", - "id": "79b7ee25-1c1c-41ff-9bbf-754af257102b", - "prevId": "aee779c5-db1d-4655-95ec-6451c18455be", - "tables": { - "account": { - "name": "account", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "email": { - "name": "email", - "columns": ["email"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "billing": { - "name": "billing", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "payment": { - "name": "payment", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "usage": { - "name": "usage", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "input_tokens": { - "name": "input_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "output_tokens": { - "name": "output_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_tokens": { - "name": "cache_write_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "key": { - "name": "key", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "actor": { - "name": "actor", - "type": "json", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "key": { - "name": "key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_used": { - "name": "time_used", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_key": { - "name": "global_key", - "columns": ["key"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "key_workspace_id_id_pk": { - "name": "key_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "color": { - "name": "color", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "user_email": { - "name": "user_email", - "columns": ["workspace_id", "email"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "workspace": { - "name": "workspace", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": ["slug"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "workspace_id": { - "name": "workspace_id", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - } - }, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "tables": {}, - "indexes": {} - } -} diff --git a/packages/console/core/migrations/meta/0002_snapshot.json b/packages/console/core/migrations/meta/0002_snapshot.json deleted file mode 100644 index 45d06926c1..0000000000 --- a/packages/console/core/migrations/meta/0002_snapshot.json +++ /dev/null @@ -1,576 +0,0 @@ -{ - "version": "5", - "dialect": "mysql", - "id": "9f51ef52-31ac-4ace-8b6d-39b35efe9c81", - "prevId": "79b7ee25-1c1c-41ff-9bbf-754af257102b", - "tables": { - "account": { - "name": "account", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "email": { - "name": "email", - "columns": ["email"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "billing": { - "name": "billing", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "payment": { - "name": "payment", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "usage": { - "name": "usage", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "input_tokens": { - "name": "input_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "output_tokens": { - "name": "output_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_tokens": { - "name": "cache_write_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "key": { - "name": "key", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "actor": { - "name": "actor", - "type": "json", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "old_name": { - "name": "old_name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "key": { - "name": "key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_used": { - "name": "time_used", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_key": { - "name": "global_key", - "columns": ["key"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "key_workspace_id_id_pk": { - "name": "key_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "color": { - "name": "color", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "user_email": { - "name": "user_email", - "columns": ["workspace_id", "email"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "workspace": { - "name": "workspace", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": ["slug"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "workspace_id": { - "name": "workspace_id", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - } - }, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "tables": {}, - "indexes": {} - } -} diff --git a/packages/console/core/migrations/meta/0003_snapshot.json b/packages/console/core/migrations/meta/0003_snapshot.json deleted file mode 100644 index e832ebb00c..0000000000 --- a/packages/console/core/migrations/meta/0003_snapshot.json +++ /dev/null @@ -1,581 +0,0 @@ -{ - "version": "5", - "dialect": "mysql", - "id": "26cebd59-f553-441c-a2b2-2f9578a0ad2b", - "prevId": "9f51ef52-31ac-4ace-8b6d-39b35efe9c81", - "tables": { - "account": { - "name": "account", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "email": { - "name": "email", - "columns": ["email"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "billing": { - "name": "billing", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "payment": { - "name": "payment", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "usage": { - "name": "usage", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "input_tokens": { - "name": "input_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "output_tokens": { - "name": "output_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_tokens": { - "name": "cache_write_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "key": { - "name": "key", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "actor": { - "name": "actor", - "type": "json", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "old_name": { - "name": "old_name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "key": { - "name": "key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_used": { - "name": "time_used", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_key": { - "name": "global_key", - "columns": ["key"], - "isUnique": true - }, - "name": { - "name": "name", - "columns": ["workspace_id", "name"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "key_workspace_id_id_pk": { - "name": "key_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "color": { - "name": "color", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "user_email": { - "name": "user_email", - "columns": ["workspace_id", "email"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "workspace": { - "name": "workspace", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": ["slug"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "workspace_id": { - "name": "workspace_id", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - } - }, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "tables": {}, - "indexes": {} - } -} diff --git a/packages/console/core/migrations/meta/0004_snapshot.json b/packages/console/core/migrations/meta/0004_snapshot.json deleted file mode 100644 index 6d2695c488..0000000000 --- a/packages/console/core/migrations/meta/0004_snapshot.json +++ /dev/null @@ -1,588 +0,0 @@ -{ - "version": "5", - "dialect": "mysql", - "id": "06dc6226-bfbb-4ccc-b4bc-f26070c3bed5", - "prevId": "26cebd59-f553-441c-a2b2-2f9578a0ad2b", - "tables": { - "account": { - "name": "account", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "email": { - "name": "email", - "columns": ["email"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "billing": { - "name": "billing", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "payment": { - "name": "payment", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "usage": { - "name": "usage", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "input_tokens": { - "name": "input_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "output_tokens": { - "name": "output_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_tokens": { - "name": "cache_write_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "key": { - "name": "key", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "actor": { - "name": "actor", - "type": "json", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "old_name": { - "name": "old_name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "key": { - "name": "key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_used": { - "name": "time_used", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_key": { - "name": "global_key", - "columns": ["key"], - "isUnique": true - }, - "name": { - "name": "name", - "columns": ["workspace_id", "name"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "key_workspace_id_id_pk": { - "name": "key_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "color": { - "name": "color", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "user_email": { - "name": "user_email", - "columns": ["workspace_id", "email"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "workspace": { - "name": "workspace", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": ["slug"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "workspace_id": { - "name": "workspace_id", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - } - }, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "tables": {}, - "indexes": {} - } -} diff --git a/packages/console/core/migrations/meta/0005_snapshot.json b/packages/console/core/migrations/meta/0005_snapshot.json deleted file mode 100644 index 12246a6d62..0000000000 --- a/packages/console/core/migrations/meta/0005_snapshot.json +++ /dev/null @@ -1,588 +0,0 @@ -{ - "version": "5", - "dialect": "mysql", - "id": "d13af80e-3c70-4866-8f14-48e7ff6ff0ff", - "prevId": "06dc6226-bfbb-4ccc-b4bc-f26070c3bed5", - "tables": { - "account": { - "name": "account", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "email": { - "name": "email", - "columns": ["email"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "billing": { - "name": "billing", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "payment": { - "name": "payment", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "usage": { - "name": "usage", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "input_tokens": { - "name": "input_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "output_tokens": { - "name": "output_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_tokens": { - "name": "cache_write_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "key": { - "name": "key", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "actor": { - "name": "actor", - "type": "json", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "old_name": { - "name": "old_name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "key": { - "name": "key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_used": { - "name": "time_used", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_key": { - "name": "global_key", - "columns": ["key"], - "isUnique": true - }, - "name": { - "name": "name", - "columns": ["workspace_id", "name"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "key_workspace_id_id_pk": { - "name": "key_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "color": { - "name": "color", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "user_email": { - "name": "user_email", - "columns": ["workspace_id", "email"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "workspace": { - "name": "workspace", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": ["slug"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "workspace_id": { - "name": "workspace_id", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - } - }, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "tables": {}, - "indexes": {} - } -} diff --git a/packages/console/core/migrations/meta/0006_snapshot.json b/packages/console/core/migrations/meta/0006_snapshot.json deleted file mode 100644 index d726b6f678..0000000000 --- a/packages/console/core/migrations/meta/0006_snapshot.json +++ /dev/null @@ -1,602 +0,0 @@ -{ - "version": "5", - "dialect": "mysql", - "id": "b0ad4b11-b607-46c7-8e2d-3b9823cdc5f7", - "prevId": "d13af80e-3c70-4866-8f14-48e7ff6ff0ff", - "tables": { - "account": { - "name": "account", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "email": { - "name": "email", - "columns": ["email"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "billing": { - "name": "billing", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "payment": { - "name": "payment", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "usage": { - "name": "usage", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "input_tokens": { - "name": "input_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "output_tokens": { - "name": "output_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_tokens": { - "name": "cache_write_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_5m_tokens": { - "name": "cache_write_5m_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_1h_tokens": { - "name": "cache_write_1h_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "key": { - "name": "key", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "actor": { - "name": "actor", - "type": "json", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "old_name": { - "name": "old_name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "key": { - "name": "key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_used": { - "name": "time_used", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_key": { - "name": "global_key", - "columns": ["key"], - "isUnique": true - }, - "name": { - "name": "name", - "columns": ["workspace_id", "name"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "key_workspace_id_id_pk": { - "name": "key_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "color": { - "name": "color", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "user_email": { - "name": "user_email", - "columns": ["workspace_id", "email"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "workspace": { - "name": "workspace", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": ["slug"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "workspace_id": { - "name": "workspace_id", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - } - }, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "tables": {}, - "indexes": {} - } -} diff --git a/packages/console/core/migrations/meta/0007_snapshot.json b/packages/console/core/migrations/meta/0007_snapshot.json deleted file mode 100644 index 122db42cb9..0000000000 --- a/packages/console/core/migrations/meta/0007_snapshot.json +++ /dev/null @@ -1,595 +0,0 @@ -{ - "version": "5", - "dialect": "mysql", - "id": "91067cc9-d492-47b3-932a-42dcc0920b3c", - "prevId": "b0ad4b11-b607-46c7-8e2d-3b9823cdc5f7", - "tables": { - "account": { - "name": "account", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "email": { - "name": "email", - "columns": ["email"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "billing": { - "name": "billing", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "payment": { - "name": "payment", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "usage": { - "name": "usage", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "input_tokens": { - "name": "input_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "output_tokens": { - "name": "output_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_5m_tokens": { - "name": "cache_write_5m_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_1h_tokens": { - "name": "cache_write_1h_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "key": { - "name": "key", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "actor": { - "name": "actor", - "type": "json", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "old_name": { - "name": "old_name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "key": { - "name": "key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_used": { - "name": "time_used", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_key": { - "name": "global_key", - "columns": ["key"], - "isUnique": true - }, - "name": { - "name": "name", - "columns": ["workspace_id", "name"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "key_workspace_id_id_pk": { - "name": "key_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "color": { - "name": "color", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "user_email": { - "name": "user_email", - "columns": ["workspace_id", "email"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "workspace": { - "name": "workspace", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": ["slug"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "workspace_id": { - "name": "workspace_id", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - } - }, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "tables": {}, - "indexes": {} - } -} diff --git a/packages/console/core/migrations/meta/0008_snapshot.json b/packages/console/core/migrations/meta/0008_snapshot.json deleted file mode 100644 index 02c4732002..0000000000 --- a/packages/console/core/migrations/meta/0008_snapshot.json +++ /dev/null @@ -1,602 +0,0 @@ -{ - "version": "5", - "dialect": "mysql", - "id": "3e080fc0-9efd-411f-b764-ed3aa4abcee5", - "prevId": "91067cc9-d492-47b3-932a-42dcc0920b3c", - "tables": { - "account": { - "name": "account", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "email": { - "name": "email", - "columns": ["email"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "billing": { - "name": "billing", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_locked_till": { - "name": "time_reload_locked_till", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "payment": { - "name": "payment", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "usage": { - "name": "usage", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "input_tokens": { - "name": "input_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "output_tokens": { - "name": "output_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_5m_tokens": { - "name": "cache_write_5m_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_1h_tokens": { - "name": "cache_write_1h_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "key": { - "name": "key", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "actor": { - "name": "actor", - "type": "json", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "old_name": { - "name": "old_name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "key": { - "name": "key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_used": { - "name": "time_used", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_key": { - "name": "global_key", - "columns": ["key"], - "isUnique": true - }, - "name": { - "name": "name", - "columns": ["workspace_id", "name"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "key_workspace_id_id_pk": { - "name": "key_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "color": { - "name": "color", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "user_email": { - "name": "user_email", - "columns": ["workspace_id", "email"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "workspace": { - "name": "workspace", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": ["slug"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "workspace_id": { - "name": "workspace_id", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - } - }, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "tables": {}, - "indexes": {} - } -} diff --git a/packages/console/core/migrations/meta/0009_snapshot.json b/packages/console/core/migrations/meta/0009_snapshot.json deleted file mode 100644 index a3bd57cae7..0000000000 --- a/packages/console/core/migrations/meta/0009_snapshot.json +++ /dev/null @@ -1,609 +0,0 @@ -{ - "version": "5", - "dialect": "mysql", - "id": "b0019e1e-d365-4f67-be3d-a2e69bdddc04", - "prevId": "3e080fc0-9efd-411f-b764-ed3aa4abcee5", - "tables": { - "account": { - "name": "account", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "email": { - "name": "email", - "columns": ["email"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "billing": { - "name": "billing", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_locked_till": { - "name": "time_reload_locked_till", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "payment": { - "name": "payment", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "error": { - "name": "error", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "usage": { - "name": "usage", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "input_tokens": { - "name": "input_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "output_tokens": { - "name": "output_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_5m_tokens": { - "name": "cache_write_5m_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_1h_tokens": { - "name": "cache_write_1h_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "key": { - "name": "key", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "actor": { - "name": "actor", - "type": "json", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "old_name": { - "name": "old_name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "key": { - "name": "key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_used": { - "name": "time_used", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_key": { - "name": "global_key", - "columns": ["key"], - "isUnique": true - }, - "name": { - "name": "name", - "columns": ["workspace_id", "name"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "key_workspace_id_id_pk": { - "name": "key_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "color": { - "name": "color", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "user_email": { - "name": "user_email", - "columns": ["workspace_id", "email"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "workspace": { - "name": "workspace", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": ["slug"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "workspace_id": { - "name": "workspace_id", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - } - }, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "tables": {}, - "indexes": {} - } -} diff --git a/packages/console/core/migrations/meta/0010_snapshot.json b/packages/console/core/migrations/meta/0010_snapshot.json deleted file mode 100644 index cb55610ae6..0000000000 --- a/packages/console/core/migrations/meta/0010_snapshot.json +++ /dev/null @@ -1,615 +0,0 @@ -{ - "version": "5", - "dialect": "mysql", - "id": "1f08bd5a-436d-4905-a585-87b156847402", - "prevId": "b0019e1e-d365-4f67-be3d-a2e69bdddc04", - "tables": { - "account": { - "name": "account", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "email": { - "name": "email", - "columns": ["email"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "billing": { - "name": "billing", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_locked_till": { - "name": "time_reload_locked_till", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_customer_id": { - "name": "global_customer_id", - "columns": ["customer_id"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "payment": { - "name": "payment", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "error": { - "name": "error", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "usage": { - "name": "usage", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "input_tokens": { - "name": "input_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "output_tokens": { - "name": "output_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_5m_tokens": { - "name": "cache_write_5m_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_1h_tokens": { - "name": "cache_write_1h_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "key": { - "name": "key", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "actor": { - "name": "actor", - "type": "json", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "old_name": { - "name": "old_name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "key": { - "name": "key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_used": { - "name": "time_used", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_key": { - "name": "global_key", - "columns": ["key"], - "isUnique": true - }, - "name": { - "name": "name", - "columns": ["workspace_id", "name"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "key_workspace_id_id_pk": { - "name": "key_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "color": { - "name": "color", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "user_email": { - "name": "user_email", - "columns": ["workspace_id", "email"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "workspace": { - "name": "workspace", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": ["slug"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "workspace_id": { - "name": "workspace_id", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - } - }, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "tables": {}, - "indexes": {} - } -} diff --git a/packages/console/core/migrations/meta/0011_snapshot.json b/packages/console/core/migrations/meta/0011_snapshot.json deleted file mode 100644 index 7eb6fa71ad..0000000000 --- a/packages/console/core/migrations/meta/0011_snapshot.json +++ /dev/null @@ -1,622 +0,0 @@ -{ - "version": "5", - "dialect": "mysql", - "id": "cd9c94c4-9167-4346-b716-1bd0cff10ffc", - "prevId": "1f08bd5a-436d-4905-a585-87b156847402", - "tables": { - "account": { - "name": "account", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "email": { - "name": "email", - "columns": ["email"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "billing": { - "name": "billing", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_locked_till": { - "name": "time_reload_locked_till", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "last_error": { - "name": "last_error", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_last_error": { - "name": "time_last_error", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_customer_id": { - "name": "global_customer_id", - "columns": ["customer_id"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "payment": { - "name": "payment", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "usage": { - "name": "usage", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "input_tokens": { - "name": "input_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "output_tokens": { - "name": "output_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_5m_tokens": { - "name": "cache_write_5m_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_1h_tokens": { - "name": "cache_write_1h_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "key": { - "name": "key", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "actor": { - "name": "actor", - "type": "json", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "old_name": { - "name": "old_name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "key": { - "name": "key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_used": { - "name": "time_used", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_key": { - "name": "global_key", - "columns": ["key"], - "isUnique": true - }, - "name": { - "name": "name", - "columns": ["workspace_id", "name"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "key_workspace_id_id_pk": { - "name": "key_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "color": { - "name": "color", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "user_email": { - "name": "user_email", - "columns": ["workspace_id", "email"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "workspace": { - "name": "workspace", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": ["slug"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "workspace_id": { - "name": "workspace_id", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - } - }, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "tables": {}, - "indexes": {} - } -} diff --git a/packages/console/core/migrations/meta/0012_snapshot.json b/packages/console/core/migrations/meta/0012_snapshot.json deleted file mode 100644 index 4220c988b2..0000000000 --- a/packages/console/core/migrations/meta/0012_snapshot.json +++ /dev/null @@ -1,643 +0,0 @@ -{ - "version": "5", - "dialect": "mysql", - "id": "ba801b30-747a-433e-ab43-b407c961a24c", - "prevId": "cd9c94c4-9167-4346-b716-1bd0cff10ffc", - "tables": { - "account": { - "name": "account", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "email": { - "name": "email", - "columns": ["email"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "billing": { - "name": "billing", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_locked_till": { - "name": "time_reload_locked_till", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "last_error": { - "name": "last_error", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_last_error": { - "name": "time_last_error", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_customer_id": { - "name": "global_customer_id", - "columns": ["customer_id"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "payment": { - "name": "payment", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "usage": { - "name": "usage", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "input_tokens": { - "name": "input_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "output_tokens": { - "name": "output_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_5m_tokens": { - "name": "cache_write_5m_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_1h_tokens": { - "name": "cache_write_1h_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "key": { - "name": "key", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "actor": { - "name": "actor", - "type": "json", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "old_name": { - "name": "old_name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "key": { - "name": "key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_used": { - "name": "time_used", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_key": { - "name": "global_key", - "columns": ["key"], - "isUnique": true - }, - "name": { - "name": "name", - "columns": ["workspace_id", "name"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "key_workspace_id_id_pk": { - "name": "key_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "color": { - "name": "color", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "user_email": { - "name": "user_email", - "columns": ["workspace_id", "email"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "workspace": { - "name": "workspace", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": ["slug"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "workspace_id": { - "name": "workspace_id", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - } - }, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "tables": {}, - "indexes": {} - } -} diff --git a/packages/console/core/migrations/meta/0013_snapshot.json b/packages/console/core/migrations/meta/0013_snapshot.json deleted file mode 100644 index ef805ee836..0000000000 --- a/packages/console/core/migrations/meta/0013_snapshot.json +++ /dev/null @@ -1,646 +0,0 @@ -{ - "version": "5", - "dialect": "mysql", - "id": "28336c91-553c-4d1d-9875-1ee761e47582", - "prevId": "ba801b30-747a-433e-ab43-b407c961a24c", - "tables": { - "account": { - "name": "account", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "email": { - "name": "email", - "columns": ["email"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "billing": { - "name": "billing", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_error": { - "name": "reload_error", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_error": { - "name": "time_reload_error", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_locked_till": { - "name": "time_reload_locked_till", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_customer_id": { - "name": "global_customer_id", - "columns": ["customer_id"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "payment": { - "name": "payment", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "usage": { - "name": "usage", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "input_tokens": { - "name": "input_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "output_tokens": { - "name": "output_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_5m_tokens": { - "name": "cache_write_5m_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_1h_tokens": { - "name": "cache_write_1h_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "key": { - "name": "key", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "actor": { - "name": "actor", - "type": "json", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "old_name": { - "name": "old_name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "key": { - "name": "key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_used": { - "name": "time_used", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_key": { - "name": "global_key", - "columns": ["key"], - "isUnique": true - }, - "name": { - "name": "name", - "columns": ["workspace_id", "name"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "key_workspace_id_id_pk": { - "name": "key_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "color": { - "name": "color", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "user_email": { - "name": "user_email", - "columns": ["workspace_id", "email"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "workspace": { - "name": "workspace", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": ["slug"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "workspace_id": { - "name": "workspace_id", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - } - }, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": { - "\"billing\".\"last_error\"": "\"billing\".\"reload_error\"", - "\"billing\".\"time_last_error\"": "\"billing\".\"time_reload_error\"" - } - }, - "internal": { - "tables": {}, - "indexes": {} - } -} diff --git a/packages/console/core/migrations/meta/0014_snapshot.json b/packages/console/core/migrations/meta/0014_snapshot.json deleted file mode 100644 index b526aeead4..0000000000 --- a/packages/console/core/migrations/meta/0014_snapshot.json +++ /dev/null @@ -1,650 +0,0 @@ -{ - "version": "5", - "dialect": "mysql", - "id": "12189a4e-5083-4b17-b8e3-8279c9a3e61a", - "prevId": "28336c91-553c-4d1d-9875-1ee761e47582", - "tables": { - "account": { - "name": "account", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "email": { - "name": "email", - "columns": ["email"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "billing": { - "name": "billing", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_error": { - "name": "reload_error", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_error": { - "name": "time_reload_error", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_locked_till": { - "name": "time_reload_locked_till", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_customer_id": { - "name": "global_customer_id", - "columns": ["customer_id"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "payment": { - "name": "payment", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "usage": { - "name": "usage", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "input_tokens": { - "name": "input_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "output_tokens": { - "name": "output_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_5m_tokens": { - "name": "cache_write_5m_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_1h_tokens": { - "name": "cache_write_1h_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "key": { - "name": "key", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "actor": { - "name": "actor", - "type": "json", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "old_name": { - "name": "old_name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "key": { - "name": "key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_used": { - "name": "time_used", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_key": { - "name": "global_key", - "columns": ["key"], - "isUnique": true - }, - "name": { - "name": "name", - "columns": ["workspace_id", "name"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "key_workspace_id_id_pk": { - "name": "key_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "color": { - "name": "color", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "user_email": { - "name": "user_email", - "columns": ["workspace_id", "email"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "workspace": { - "name": "workspace", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "data_share": { - "name": "data_share", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": ["slug"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "workspace_id": { - "name": "workspace_id", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - } - }, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "tables": {}, - "indexes": {} - } -} diff --git a/packages/console/core/migrations/meta/0015_snapshot.json b/packages/console/core/migrations/meta/0015_snapshot.json deleted file mode 100644 index 57d893cd80..0000000000 --- a/packages/console/core/migrations/meta/0015_snapshot.json +++ /dev/null @@ -1,643 +0,0 @@ -{ - "version": "5", - "dialect": "mysql", - "id": "7f3989cb-3e8b-430e-a0f5-f87051d1d824", - "prevId": "12189a4e-5083-4b17-b8e3-8279c9a3e61a", - "tables": { - "account": { - "name": "account", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "email": { - "name": "email", - "columns": ["email"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "billing": { - "name": "billing", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_error": { - "name": "reload_error", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_error": { - "name": "time_reload_error", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_locked_till": { - "name": "time_reload_locked_till", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_customer_id": { - "name": "global_customer_id", - "columns": ["customer_id"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "payment": { - "name": "payment", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "usage": { - "name": "usage", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "input_tokens": { - "name": "input_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "output_tokens": { - "name": "output_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_5m_tokens": { - "name": "cache_write_5m_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_1h_tokens": { - "name": "cache_write_1h_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "key": { - "name": "key", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "actor": { - "name": "actor", - "type": "json", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "old_name": { - "name": "old_name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "key": { - "name": "key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_used": { - "name": "time_used", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_key": { - "name": "global_key", - "columns": ["key"], - "isUnique": true - }, - "name": { - "name": "name", - "columns": ["workspace_id", "name"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "key_workspace_id_id_pk": { - "name": "key_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "color": { - "name": "color", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "user_email": { - "name": "user_email", - "columns": ["workspace_id", "email"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "workspace": { - "name": "workspace", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": ["slug"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "workspace_id": { - "name": "workspace_id", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - } - }, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "tables": {}, - "indexes": {} - } -} diff --git a/packages/console/core/migrations/meta/0016_snapshot.json b/packages/console/core/migrations/meta/0016_snapshot.json deleted file mode 100644 index eefeb31a75..0000000000 --- a/packages/console/core/migrations/meta/0016_snapshot.json +++ /dev/null @@ -1,650 +0,0 @@ -{ - "version": "5", - "dialect": "mysql", - "id": "45b67fb4-77ce-4aa2-b883-1971429c69f5", - "prevId": "7f3989cb-3e8b-430e-a0f5-f87051d1d824", - "tables": { - "account": { - "name": "account", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "email": { - "name": "email", - "columns": ["email"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "billing": { - "name": "billing", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_error": { - "name": "reload_error", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_error": { - "name": "time_reload_error", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_locked_till": { - "name": "time_reload_locked_till", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_customer_id": { - "name": "global_customer_id", - "columns": ["customer_id"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "payment": { - "name": "payment", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_refunded": { - "name": "time_refunded", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "usage": { - "name": "usage", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "input_tokens": { - "name": "input_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "output_tokens": { - "name": "output_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_5m_tokens": { - "name": "cache_write_5m_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_1h_tokens": { - "name": "cache_write_1h_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "key": { - "name": "key", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "actor": { - "name": "actor", - "type": "json", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "old_name": { - "name": "old_name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "key": { - "name": "key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_used": { - "name": "time_used", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_key": { - "name": "global_key", - "columns": ["key"], - "isUnique": true - }, - "name": { - "name": "name", - "columns": ["workspace_id", "name"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "key_workspace_id_id_pk": { - "name": "key_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "color": { - "name": "color", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "user_email": { - "name": "user_email", - "columns": ["workspace_id", "email"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "workspace": { - "name": "workspace", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": ["slug"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "workspace_id": { - "name": "workspace_id", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - } - }, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "tables": {}, - "indexes": {} - } -} diff --git a/packages/console/core/migrations/meta/0017_snapshot.json b/packages/console/core/migrations/meta/0017_snapshot.json deleted file mode 100644 index d7687f9c6c..0000000000 --- a/packages/console/core/migrations/meta/0017_snapshot.json +++ /dev/null @@ -1,657 +0,0 @@ -{ - "version": "5", - "dialect": "mysql", - "id": "100a21cf-ff9c-476f-bf7d-100c1824b2b2", - "prevId": "45b67fb4-77ce-4aa2-b883-1971429c69f5", - "tables": { - "account": { - "name": "account", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "email": { - "name": "email", - "columns": ["email"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "billing": { - "name": "billing", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_error": { - "name": "reload_error", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_error": { - "name": "time_reload_error", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_locked_till": { - "name": "time_reload_locked_till", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_customer_id": { - "name": "global_customer_id", - "columns": ["customer_id"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "payment": { - "name": "payment", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "invoice_id": { - "name": "invoice_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_refunded": { - "name": "time_refunded", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "usage": { - "name": "usage", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "input_tokens": { - "name": "input_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "output_tokens": { - "name": "output_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_5m_tokens": { - "name": "cache_write_5m_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_1h_tokens": { - "name": "cache_write_1h_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "key": { - "name": "key", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "actor": { - "name": "actor", - "type": "json", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "old_name": { - "name": "old_name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "key": { - "name": "key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_used": { - "name": "time_used", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_key": { - "name": "global_key", - "columns": ["key"], - "isUnique": true - }, - "name": { - "name": "name", - "columns": ["workspace_id", "name"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "key_workspace_id_id_pk": { - "name": "key_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "color": { - "name": "color", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "user_email": { - "name": "user_email", - "columns": ["workspace_id", "email"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "workspace": { - "name": "workspace", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": ["slug"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "workspace_id": { - "name": "workspace_id", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - } - }, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "tables": {}, - "indexes": {} - } -} diff --git a/packages/console/core/migrations/meta/0018_snapshot.json b/packages/console/core/migrations/meta/0018_snapshot.json deleted file mode 100644 index 3e3c64c734..0000000000 --- a/packages/console/core/migrations/meta/0018_snapshot.json +++ /dev/null @@ -1,671 +0,0 @@ -{ - "version": "5", - "dialect": "mysql", - "id": "e9c91c2d-787d-4234-b98d-1620e4ce80e1", - "prevId": "100a21cf-ff9c-476f-bf7d-100c1824b2b2", - "tables": { - "account": { - "name": "account", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "email": { - "name": "email", - "columns": ["email"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "billing": { - "name": "billing", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_error": { - "name": "reload_error", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_error": { - "name": "time_reload_error", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_locked_till": { - "name": "time_reload_locked_till", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_customer_id": { - "name": "global_customer_id", - "columns": ["customer_id"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "payment": { - "name": "payment", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "invoice_id": { - "name": "invoice_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_refunded": { - "name": "time_refunded", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "usage": { - "name": "usage", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "input_tokens": { - "name": "input_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "output_tokens": { - "name": "output_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_5m_tokens": { - "name": "cache_write_5m_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_1h_tokens": { - "name": "cache_write_1h_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "key": { - "name": "key", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "actor": { - "name": "actor", - "type": "json", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "old_name": { - "name": "old_name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "key": { - "name": "key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_used": { - "name": "time_used", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_key": { - "name": "global_key", - "columns": ["key"], - "isUnique": true - }, - "name": { - "name": "name", - "columns": ["workspace_id", "name"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "key_workspace_id_id_pk": { - "name": "key_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_joined": { - "name": "time_joined", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "color": { - "name": "color", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "role": { - "name": "role", - "type": "enum('admin','member')", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "user_email": { - "name": "user_email", - "columns": ["workspace_id", "email"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "workspace": { - "name": "workspace", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": ["slug"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "workspace_id": { - "name": "workspace_id", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - } - }, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "tables": {}, - "indexes": {} - } -} diff --git a/packages/console/core/migrations/meta/0019_snapshot.json b/packages/console/core/migrations/meta/0019_snapshot.json deleted file mode 100644 index 9a0d4d2439..0000000000 --- a/packages/console/core/migrations/meta/0019_snapshot.json +++ /dev/null @@ -1,671 +0,0 @@ -{ - "version": "5", - "dialect": "mysql", - "id": "a2bb7222-561c-45f0-8939-8ef9b8e57bb3", - "prevId": "e9c91c2d-787d-4234-b98d-1620e4ce80e1", - "tables": { - "account": { - "name": "account", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "email": { - "name": "email", - "columns": ["email"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "billing": { - "name": "billing", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_error": { - "name": "reload_error", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_error": { - "name": "time_reload_error", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_locked_till": { - "name": "time_reload_locked_till", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_customer_id": { - "name": "global_customer_id", - "columns": ["customer_id"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "payment": { - "name": "payment", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "invoice_id": { - "name": "invoice_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_refunded": { - "name": "time_refunded", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "usage": { - "name": "usage", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "input_tokens": { - "name": "input_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "output_tokens": { - "name": "output_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_5m_tokens": { - "name": "cache_write_5m_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_1h_tokens": { - "name": "cache_write_1h_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "key": { - "name": "key", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "actor": { - "name": "actor", - "type": "json", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "old_name": { - "name": "old_name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "key": { - "name": "key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_used": { - "name": "time_used", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_key": { - "name": "global_key", - "columns": ["key"], - "isUnique": true - }, - "name": { - "name": "name", - "columns": ["workspace_id", "name"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "key_workspace_id_id_pk": { - "name": "key_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_joined": { - "name": "time_joined", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "color": { - "name": "color", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "role": { - "name": "role", - "type": "enum('admin','member')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "user_email": { - "name": "user_email", - "columns": ["workspace_id", "email"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "workspace": { - "name": "workspace", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": ["slug"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "workspace_id": { - "name": "workspace_id", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - } - }, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "tables": {}, - "indexes": {} - } -} diff --git a/packages/console/core/migrations/meta/0020_snapshot.json b/packages/console/core/migrations/meta/0020_snapshot.json deleted file mode 100644 index 9defceb5a3..0000000000 --- a/packages/console/core/migrations/meta/0020_snapshot.json +++ /dev/null @@ -1,664 +0,0 @@ -{ - "version": "5", - "dialect": "mysql", - "id": "908437f9-54ed-4c83-b555-614926e326f8", - "prevId": "a2bb7222-561c-45f0-8939-8ef9b8e57bb3", - "tables": { - "account": { - "name": "account", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "email": { - "name": "email", - "columns": ["email"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "billing": { - "name": "billing", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_error": { - "name": "reload_error", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_error": { - "name": "time_reload_error", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_locked_till": { - "name": "time_reload_locked_till", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_customer_id": { - "name": "global_customer_id", - "columns": ["customer_id"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "payment": { - "name": "payment", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "invoice_id": { - "name": "invoice_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_refunded": { - "name": "time_refunded", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "usage": { - "name": "usage", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "input_tokens": { - "name": "input_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "output_tokens": { - "name": "output_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_5m_tokens": { - "name": "cache_write_5m_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_1h_tokens": { - "name": "cache_write_1h_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "key": { - "name": "key", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "actor": { - "name": "actor", - "type": "json", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "old_name": { - "name": "old_name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "key": { - "name": "key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_used": { - "name": "time_used", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_key": { - "name": "global_key", - "columns": ["key"], - "isUnique": true - }, - "name": { - "name": "name", - "columns": ["workspace_id", "name"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "key_workspace_id_id_pk": { - "name": "key_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "color": { - "name": "color", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "role": { - "name": "role", - "type": "enum('admin','member')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "user_email": { - "name": "user_email", - "columns": ["workspace_id", "email"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "workspace": { - "name": "workspace", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": ["slug"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "workspace_id": { - "name": "workspace_id", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - } - }, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "tables": {}, - "indexes": {} - } -} diff --git a/packages/console/core/migrations/meta/0021_snapshot.json b/packages/console/core/migrations/meta/0021_snapshot.json deleted file mode 100644 index 64d3e9d249..0000000000 --- a/packages/console/core/migrations/meta/0021_snapshot.json +++ /dev/null @@ -1,671 +0,0 @@ -{ - "version": "5", - "dialect": "mysql", - "id": "14616ba2-c21e-4787-a289-f2a3eb6de04f", - "prevId": "908437f9-54ed-4c83-b555-614926e326f8", - "tables": { - "account": { - "name": "account", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "email": { - "name": "email", - "columns": ["email"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "billing": { - "name": "billing", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_error": { - "name": "reload_error", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_error": { - "name": "time_reload_error", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_locked_till": { - "name": "time_reload_locked_till", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_customer_id": { - "name": "global_customer_id", - "columns": ["customer_id"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "payment": { - "name": "payment", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "invoice_id": { - "name": "invoice_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_refunded": { - "name": "time_refunded", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "usage": { - "name": "usage", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "input_tokens": { - "name": "input_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "output_tokens": { - "name": "output_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_5m_tokens": { - "name": "cache_write_5m_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_1h_tokens": { - "name": "cache_write_1h_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "key": { - "name": "key", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "actor": { - "name": "actor", - "type": "json", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "old_name": { - "name": "old_name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "key": { - "name": "key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_used": { - "name": "time_used", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_key": { - "name": "global_key", - "columns": ["key"], - "isUnique": true - }, - "name": { - "name": "name", - "columns": ["workspace_id", "name"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "key_workspace_id_id_pk": { - "name": "key_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "old_email": { - "name": "old_email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "color": { - "name": "color", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "role": { - "name": "role", - "type": "enum('admin','member')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "user_email": { - "name": "user_email", - "columns": ["workspace_id", "email"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "workspace": { - "name": "workspace", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": ["slug"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "workspace_id": { - "name": "workspace_id", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - } - }, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "tables": {}, - "indexes": {} - } -} diff --git a/packages/console/core/migrations/meta/0022_snapshot.json b/packages/console/core/migrations/meta/0022_snapshot.json deleted file mode 100644 index 8a1c4e7d8e..0000000000 --- a/packages/console/core/migrations/meta/0022_snapshot.json +++ /dev/null @@ -1,690 +0,0 @@ -{ - "version": "5", - "dialect": "mysql", - "id": "2296e9e4-bee6-485b-a146-6666ac8dc0d0", - "prevId": "14616ba2-c21e-4787-a289-f2a3eb6de04f", - "tables": { - "account": { - "name": "account", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "email": { - "name": "email", - "columns": ["email"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "billing": { - "name": "billing", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_error": { - "name": "reload_error", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_error": { - "name": "time_reload_error", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_locked_till": { - "name": "time_reload_locked_till", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_customer_id": { - "name": "global_customer_id", - "columns": ["customer_id"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "payment": { - "name": "payment", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "invoice_id": { - "name": "invoice_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_refunded": { - "name": "time_refunded", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "usage": { - "name": "usage", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "input_tokens": { - "name": "input_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "output_tokens": { - "name": "output_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_5m_tokens": { - "name": "cache_write_5m_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_1h_tokens": { - "name": "cache_write_1h_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "key": { - "name": "key", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "actor": { - "name": "actor", - "type": "json", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "old_name": { - "name": "old_name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "key": { - "name": "key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_used": { - "name": "time_used", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_key": { - "name": "global_key", - "columns": ["key"], - "isUnique": true - }, - "name": { - "name": "name", - "columns": ["workspace_id", "name"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "key_workspace_id_id_pk": { - "name": "key_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "account_id": { - "name": "account_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "old_account_id": { - "name": "old_account_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "old_email": { - "name": "old_email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "color": { - "name": "color", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "role": { - "name": "role", - "type": "enum('admin','member')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "user_account_id": { - "name": "user_account_id", - "columns": ["workspace_id", "account_id"], - "isUnique": true - }, - "user_email": { - "name": "user_email", - "columns": ["workspace_id", "email"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "workspace": { - "name": "workspace", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": ["slug"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "workspace_id": { - "name": "workspace_id", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - } - }, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "tables": {}, - "indexes": {} - } -} diff --git a/packages/console/core/migrations/meta/0023_snapshot.json b/packages/console/core/migrations/meta/0023_snapshot.json deleted file mode 100644 index 4f6f66283a..0000000000 --- a/packages/console/core/migrations/meta/0023_snapshot.json +++ /dev/null @@ -1,700 +0,0 @@ -{ - "version": "5", - "dialect": "mysql", - "id": "6857f409-1b5d-4752-9d65-a82ee70e6ad2", - "prevId": "2296e9e4-bee6-485b-a146-6666ac8dc0d0", - "tables": { - "account": { - "name": "account", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "email": { - "name": "email", - "columns": ["email"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "billing": { - "name": "billing", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_error": { - "name": "reload_error", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_error": { - "name": "time_reload_error", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_locked_till": { - "name": "time_reload_locked_till", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_customer_id": { - "name": "global_customer_id", - "columns": ["customer_id"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "payment": { - "name": "payment", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "invoice_id": { - "name": "invoice_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_refunded": { - "name": "time_refunded", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "usage": { - "name": "usage", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "input_tokens": { - "name": "input_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "output_tokens": { - "name": "output_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_5m_tokens": { - "name": "cache_write_5m_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_1h_tokens": { - "name": "cache_write_1h_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "key": { - "name": "key", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "actor": { - "name": "actor", - "type": "json", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "old_name": { - "name": "old_name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "key": { - "name": "key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_used": { - "name": "time_used", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_key": { - "name": "global_key", - "columns": ["key"], - "isUnique": true - }, - "name": { - "name": "name", - "columns": ["workspace_id", "name"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "key_workspace_id_id_pk": { - "name": "key_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "account_id": { - "name": "account_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "old_account_id": { - "name": "old_account_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "old_email": { - "name": "old_email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "color": { - "name": "color", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "role": { - "name": "role", - "type": "enum('admin','member')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "user_account_id": { - "name": "user_account_id", - "columns": ["workspace_id", "account_id"], - "isUnique": true - }, - "user_email": { - "name": "user_email", - "columns": ["workspace_id", "email"], - "isUnique": true - }, - "global_account_id": { - "name": "global_account_id", - "columns": ["account_id"], - "isUnique": false - }, - "global_email": { - "name": "global_email", - "columns": ["email"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "workspace": { - "name": "workspace", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": ["slug"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "workspace_id": { - "name": "workspace_id", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - } - }, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "tables": {}, - "indexes": {} - } -} diff --git a/packages/console/core/migrations/meta/0024_snapshot.json b/packages/console/core/migrations/meta/0024_snapshot.json deleted file mode 100644 index 1ef25970a3..0000000000 --- a/packages/console/core/migrations/meta/0024_snapshot.json +++ /dev/null @@ -1,686 +0,0 @@ -{ - "version": "5", - "dialect": "mysql", - "id": "6d546f3e-17b2-4195-bb10-7e6d91774bd7", - "prevId": "6857f409-1b5d-4752-9d65-a82ee70e6ad2", - "tables": { - "account": { - "name": "account", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "email": { - "name": "email", - "columns": ["email"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "billing": { - "name": "billing", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_error": { - "name": "reload_error", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_error": { - "name": "time_reload_error", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_locked_till": { - "name": "time_reload_locked_till", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_customer_id": { - "name": "global_customer_id", - "columns": ["customer_id"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "payment": { - "name": "payment", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "invoice_id": { - "name": "invoice_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_refunded": { - "name": "time_refunded", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "usage": { - "name": "usage", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "input_tokens": { - "name": "input_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "output_tokens": { - "name": "output_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_5m_tokens": { - "name": "cache_write_5m_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_1h_tokens": { - "name": "cache_write_1h_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "key": { - "name": "key", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "actor": { - "name": "actor", - "type": "json", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "old_name": { - "name": "old_name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "key": { - "name": "key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_used": { - "name": "time_used", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_key": { - "name": "global_key", - "columns": ["key"], - "isUnique": true - }, - "name": { - "name": "name", - "columns": ["workspace_id", "name"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "key_workspace_id_id_pk": { - "name": "key_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "account_id": { - "name": "account_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "color": { - "name": "color", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "role": { - "name": "role", - "type": "enum('admin','member')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "user_account_id": { - "name": "user_account_id", - "columns": ["workspace_id", "account_id"], - "isUnique": true - }, - "user_email": { - "name": "user_email", - "columns": ["workspace_id", "email"], - "isUnique": true - }, - "global_account_id": { - "name": "global_account_id", - "columns": ["account_id"], - "isUnique": false - }, - "global_email": { - "name": "global_email", - "columns": ["email"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "workspace": { - "name": "workspace", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": ["slug"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "workspace_id": { - "name": "workspace_id", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - } - }, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "tables": {}, - "indexes": {} - } -} diff --git a/packages/console/core/migrations/meta/0025_snapshot.json b/packages/console/core/migrations/meta/0025_snapshot.json deleted file mode 100644 index 6746a6e8c6..0000000000 --- a/packages/console/core/migrations/meta/0025_snapshot.json +++ /dev/null @@ -1,693 +0,0 @@ -{ - "version": "5", - "dialect": "mysql", - "id": "ce444765-0606-4880-970a-2176bc2a78ac", - "prevId": "6d546f3e-17b2-4195-bb10-7e6d91774bd7", - "tables": { - "account": { - "name": "account", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "email": { - "name": "email", - "columns": ["email"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "billing": { - "name": "billing", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_error": { - "name": "reload_error", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_error": { - "name": "time_reload_error", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_locked_till": { - "name": "time_reload_locked_till", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_customer_id": { - "name": "global_customer_id", - "columns": ["customer_id"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "payment": { - "name": "payment", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "invoice_id": { - "name": "invoice_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_refunded": { - "name": "time_refunded", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "usage": { - "name": "usage", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "input_tokens": { - "name": "input_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "output_tokens": { - "name": "output_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_5m_tokens": { - "name": "cache_write_5m_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_1h_tokens": { - "name": "cache_write_1h_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "key": { - "name": "key", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "actor": { - "name": "actor", - "type": "json", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "old_name": { - "name": "old_name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "key": { - "name": "key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_used": { - "name": "time_used", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_key": { - "name": "global_key", - "columns": ["key"], - "isUnique": true - }, - "name": { - "name": "name", - "columns": ["workspace_id", "name"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "key_workspace_id_id_pk": { - "name": "key_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "account_id": { - "name": "account_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "color": { - "name": "color", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "role": { - "name": "role", - "type": "enum('admin','member')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "user_account_id": { - "name": "user_account_id", - "columns": ["workspace_id", "account_id"], - "isUnique": true - }, - "user_email": { - "name": "user_email", - "columns": ["workspace_id", "email"], - "isUnique": true - }, - "global_account_id": { - "name": "global_account_id", - "columns": ["account_id"], - "isUnique": false - }, - "global_email": { - "name": "global_email", - "columns": ["email"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "workspace": { - "name": "workspace", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": ["slug"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "workspace_id": { - "name": "workspace_id", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - } - }, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "tables": {}, - "indexes": {} - } -} diff --git a/packages/console/core/migrations/meta/0026_snapshot.json b/packages/console/core/migrations/meta/0026_snapshot.json deleted file mode 100644 index d3c7dc496f..0000000000 --- a/packages/console/core/migrations/meta/0026_snapshot.json +++ /dev/null @@ -1,688 +0,0 @@ -{ - "version": "5", - "dialect": "mysql", - "id": "9e1313c7-ca78-4d2c-b13b-625d9d6fcaa3", - "prevId": "ce444765-0606-4880-970a-2176bc2a78ac", - "tables": { - "account": { - "name": "account", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "email": { - "name": "email", - "columns": ["email"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "billing": { - "name": "billing", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_error": { - "name": "reload_error", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_error": { - "name": "time_reload_error", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_locked_till": { - "name": "time_reload_locked_till", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_customer_id": { - "name": "global_customer_id", - "columns": ["customer_id"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "payment": { - "name": "payment", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "invoice_id": { - "name": "invoice_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_refunded": { - "name": "time_refunded", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "usage": { - "name": "usage", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "input_tokens": { - "name": "input_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "output_tokens": { - "name": "output_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_5m_tokens": { - "name": "cache_write_5m_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_1h_tokens": { - "name": "cache_write_1h_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "key": { - "name": "key", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "actor": { - "name": "actor", - "type": "json", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "old_name": { - "name": "old_name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "key": { - "name": "key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_used": { - "name": "time_used", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_key": { - "name": "global_key", - "columns": ["key"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "key_workspace_id_id_pk": { - "name": "key_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "account_id": { - "name": "account_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "color": { - "name": "color", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "role": { - "name": "role", - "type": "enum('admin','member')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "user_account_id": { - "name": "user_account_id", - "columns": ["workspace_id", "account_id"], - "isUnique": true - }, - "user_email": { - "name": "user_email", - "columns": ["workspace_id", "email"], - "isUnique": true - }, - "global_account_id": { - "name": "global_account_id", - "columns": ["account_id"], - "isUnique": false - }, - "global_email": { - "name": "global_email", - "columns": ["email"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "workspace": { - "name": "workspace", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": ["slug"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "workspace_id": { - "name": "workspace_id", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - } - }, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "tables": {}, - "indexes": {} - } -} diff --git a/packages/console/core/migrations/meta/0027_snapshot.json b/packages/console/core/migrations/meta/0027_snapshot.json deleted file mode 100644 index 408766f717..0000000000 --- a/packages/console/core/migrations/meta/0027_snapshot.json +++ /dev/null @@ -1,674 +0,0 @@ -{ - "version": "5", - "dialect": "mysql", - "id": "05e873f6-1556-4bcb-8e19-14971e37610a", - "prevId": "9e1313c7-ca78-4d2c-b13b-625d9d6fcaa3", - "tables": { - "account": { - "name": "account", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "email": { - "name": "email", - "columns": ["email"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "billing": { - "name": "billing", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_error": { - "name": "reload_error", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_error": { - "name": "time_reload_error", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_locked_till": { - "name": "time_reload_locked_till", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_customer_id": { - "name": "global_customer_id", - "columns": ["customer_id"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "payment": { - "name": "payment", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "invoice_id": { - "name": "invoice_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_refunded": { - "name": "time_refunded", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "usage": { - "name": "usage", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "input_tokens": { - "name": "input_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "output_tokens": { - "name": "output_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_5m_tokens": { - "name": "cache_write_5m_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_1h_tokens": { - "name": "cache_write_1h_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "key": { - "name": "key", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "key": { - "name": "key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_used": { - "name": "time_used", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_key": { - "name": "global_key", - "columns": ["key"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "key_workspace_id_id_pk": { - "name": "key_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "account_id": { - "name": "account_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "color": { - "name": "color", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "role": { - "name": "role", - "type": "enum('admin','member')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "user_account_id": { - "name": "user_account_id", - "columns": ["workspace_id", "account_id"], - "isUnique": true - }, - "user_email": { - "name": "user_email", - "columns": ["workspace_id", "email"], - "isUnique": true - }, - "global_account_id": { - "name": "global_account_id", - "columns": ["account_id"], - "isUnique": false - }, - "global_email": { - "name": "global_email", - "columns": ["email"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "workspace": { - "name": "workspace", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": ["slug"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "workspace_id": { - "name": "workspace_id", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - } - }, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "tables": {}, - "indexes": {} - } -} diff --git a/packages/console/core/migrations/meta/0028_snapshot.json b/packages/console/core/migrations/meta/0028_snapshot.json deleted file mode 100644 index 827cb53c5e..0000000000 --- a/packages/console/core/migrations/meta/0028_snapshot.json +++ /dev/null @@ -1,674 +0,0 @@ -{ - "version": "5", - "dialect": "mysql", - "id": "a331e38c-c2e3-406d-a1ff-b0af7229cd85", - "prevId": "05e873f6-1556-4bcb-8e19-14971e37610a", - "tables": { - "account": { - "name": "account", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "email": { - "name": "email", - "columns": ["email"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "billing": { - "name": "billing", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_error": { - "name": "reload_error", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_error": { - "name": "time_reload_error", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_locked_till": { - "name": "time_reload_locked_till", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_customer_id": { - "name": "global_customer_id", - "columns": ["customer_id"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "payment": { - "name": "payment", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "invoice_id": { - "name": "invoice_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_refunded": { - "name": "time_refunded", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "usage": { - "name": "usage", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "input_tokens": { - "name": "input_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "output_tokens": { - "name": "output_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_5m_tokens": { - "name": "cache_write_5m_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_1h_tokens": { - "name": "cache_write_1h_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "key": { - "name": "key", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "key": { - "name": "key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_used": { - "name": "time_used", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_key": { - "name": "global_key", - "columns": ["key"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "key_workspace_id_id_pk": { - "name": "key_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "account_id": { - "name": "account_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "color": { - "name": "color", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "role": { - "name": "role", - "type": "enum('admin','member')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "user_account_id": { - "name": "user_account_id", - "columns": ["workspace_id", "account_id"], - "isUnique": true - }, - "user_email": { - "name": "user_email", - "columns": ["workspace_id", "email"], - "isUnique": true - }, - "global_account_id": { - "name": "global_account_id", - "columns": ["account_id"], - "isUnique": false - }, - "global_email": { - "name": "global_email", - "columns": ["email"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "workspace": { - "name": "workspace", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": ["slug"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "workspace_id": { - "name": "workspace_id", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - } - }, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "tables": {}, - "indexes": {} - } -} diff --git a/packages/console/core/migrations/meta/0029_snapshot.json b/packages/console/core/migrations/meta/0029_snapshot.json deleted file mode 100644 index d235697cc2..0000000000 --- a/packages/console/core/migrations/meta/0029_snapshot.json +++ /dev/null @@ -1,695 +0,0 @@ -{ - "version": "5", - "dialect": "mysql", - "id": "33551b4c-fc2e-4753-8d9d-0971f333e65d", - "prevId": "a331e38c-c2e3-406d-a1ff-b0af7229cd85", - "tables": { - "account": { - "name": "account", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "email": { - "name": "email", - "columns": ["email"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "billing": { - "name": "billing", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_error": { - "name": "reload_error", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_error": { - "name": "time_reload_error", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_locked_till": { - "name": "time_reload_locked_till", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_customer_id": { - "name": "global_customer_id", - "columns": ["customer_id"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "payment": { - "name": "payment", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "invoice_id": { - "name": "invoice_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_refunded": { - "name": "time_refunded", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "usage": { - "name": "usage", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "input_tokens": { - "name": "input_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "output_tokens": { - "name": "output_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_5m_tokens": { - "name": "cache_write_5m_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_1h_tokens": { - "name": "cache_write_1h_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "key": { - "name": "key", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "key": { - "name": "key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_used": { - "name": "time_used", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_key": { - "name": "global_key", - "columns": ["key"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "key_workspace_id_id_pk": { - "name": "key_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "account_id": { - "name": "account_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "color": { - "name": "color", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "role": { - "name": "role", - "type": "enum('admin','member')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "user_account_id": { - "name": "user_account_id", - "columns": ["workspace_id", "account_id"], - "isUnique": true - }, - "user_email": { - "name": "user_email", - "columns": ["workspace_id", "email"], - "isUnique": true - }, - "global_account_id": { - "name": "global_account_id", - "columns": ["account_id"], - "isUnique": false - }, - "global_email": { - "name": "global_email", - "columns": ["email"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "workspace": { - "name": "workspace", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": ["slug"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "workspace_id": { - "name": "workspace_id", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - } - }, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "tables": {}, - "indexes": {} - } -} diff --git a/packages/console/core/migrations/meta/0030_snapshot.json b/packages/console/core/migrations/meta/0030_snapshot.json deleted file mode 100644 index 66978dfa5f..0000000000 --- a/packages/console/core/migrations/meta/0030_snapshot.json +++ /dev/null @@ -1,760 +0,0 @@ -{ - "version": "5", - "dialect": "mysql", - "id": "eae45fcf-dc0f-4756-bc5d-30791f2965a2", - "prevId": "33551b4c-fc2e-4753-8d9d-0971f333e65d", - "tables": { - "account": { - "name": "account", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "email": { - "name": "email", - "columns": ["email"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "billing": { - "name": "billing", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_error": { - "name": "reload_error", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_error": { - "name": "time_reload_error", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_locked_till": { - "name": "time_reload_locked_till", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_customer_id": { - "name": "global_customer_id", - "columns": ["customer_id"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "payment": { - "name": "payment", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "invoice_id": { - "name": "invoice_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_refunded": { - "name": "time_refunded", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "usage": { - "name": "usage", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "input_tokens": { - "name": "input_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "output_tokens": { - "name": "output_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_5m_tokens": { - "name": "cache_write_5m_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_1h_tokens": { - "name": "cache_write_1h_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "key": { - "name": "key", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "key": { - "name": "key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_used": { - "name": "time_used", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_key": { - "name": "global_key", - "columns": ["key"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "key_workspace_id_id_pk": { - "name": "key_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "model": { - "name": "model", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "model_workspace_model": { - "name": "model_workspace_model", - "columns": ["workspace_id", "model"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "model_workspace_id_id_pk": { - "name": "model_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "account_id": { - "name": "account_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "color": { - "name": "color", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "role": { - "name": "role", - "type": "enum('admin','member')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "user_account_id": { - "name": "user_account_id", - "columns": ["workspace_id", "account_id"], - "isUnique": true - }, - "user_email": { - "name": "user_email", - "columns": ["workspace_id", "email"], - "isUnique": true - }, - "global_account_id": { - "name": "global_account_id", - "columns": ["account_id"], - "isUnique": false - }, - "global_email": { - "name": "global_email", - "columns": ["email"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "workspace": { - "name": "workspace", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": ["slug"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "workspace_id": { - "name": "workspace_id", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - } - }, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "tables": {}, - "indexes": {} - } -} diff --git a/packages/console/core/migrations/meta/0031_snapshot.json b/packages/console/core/migrations/meta/0031_snapshot.json deleted file mode 100644 index c471659250..0000000000 --- a/packages/console/core/migrations/meta/0031_snapshot.json +++ /dev/null @@ -1,832 +0,0 @@ -{ - "version": "5", - "dialect": "mysql", - "id": "9dceb591-8e08-4991-a49c-1f1741ec1e57", - "prevId": "eae45fcf-dc0f-4756-bc5d-30791f2965a2", - "tables": { - "account": { - "name": "account", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "email": { - "name": "email", - "columns": ["email"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "billing": { - "name": "billing", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_error": { - "name": "reload_error", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_error": { - "name": "time_reload_error", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_locked_till": { - "name": "time_reload_locked_till", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_customer_id": { - "name": "global_customer_id", - "columns": ["customer_id"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "payment": { - "name": "payment", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "invoice_id": { - "name": "invoice_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_refunded": { - "name": "time_refunded", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "usage": { - "name": "usage", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "input_tokens": { - "name": "input_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "output_tokens": { - "name": "output_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_5m_tokens": { - "name": "cache_write_5m_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_1h_tokens": { - "name": "cache_write_1h_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "key": { - "name": "key", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "key": { - "name": "key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_used": { - "name": "time_used", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_key": { - "name": "global_key", - "columns": ["key"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "key_workspace_id_id_pk": { - "name": "key_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "model": { - "name": "model", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "model_workspace_model": { - "name": "model_workspace_model", - "columns": ["workspace_id", "model"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "model_workspace_id_id_pk": { - "name": "model_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "provider": { - "name": "provider", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "credentials": { - "name": "credentials", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "workspace_provider": { - "name": "workspace_provider", - "columns": ["workspace_id", "provider"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "provider_workspace_id_id_pk": { - "name": "provider_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "account_id": { - "name": "account_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "color": { - "name": "color", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "role": { - "name": "role", - "type": "enum('admin','member')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "user_account_id": { - "name": "user_account_id", - "columns": ["workspace_id", "account_id"], - "isUnique": true - }, - "user_email": { - "name": "user_email", - "columns": ["workspace_id", "email"], - "isUnique": true - }, - "global_account_id": { - "name": "global_account_id", - "columns": ["account_id"], - "isUnique": false - }, - "global_email": { - "name": "global_email", - "columns": ["email"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "workspace": { - "name": "workspace", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": ["slug"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "workspace_id": { - "name": "workspace_id", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - } - }, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "tables": {}, - "indexes": {} - } -} diff --git a/packages/console/core/migrations/meta/0032_snapshot.json b/packages/console/core/migrations/meta/0032_snapshot.json deleted file mode 100644 index 51e84a1d3a..0000000000 --- a/packages/console/core/migrations/meta/0032_snapshot.json +++ /dev/null @@ -1,839 +0,0 @@ -{ - "version": "5", - "dialect": "mysql", - "id": "b2406421-f22d-4153-a2a4-6deafe70ee54", - "prevId": "9dceb591-8e08-4991-a49c-1f1741ec1e57", - "tables": { - "account": { - "name": "account", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "email": { - "name": "email", - "columns": ["email"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "billing": { - "name": "billing", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_error": { - "name": "reload_error", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_error": { - "name": "time_reload_error", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_locked_till": { - "name": "time_reload_locked_till", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_customer_id": { - "name": "global_customer_id", - "columns": ["customer_id"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "payment": { - "name": "payment", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "invoice_id": { - "name": "invoice_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_refunded": { - "name": "time_refunded", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "usage": { - "name": "usage", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "input_tokens": { - "name": "input_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "output_tokens": { - "name": "output_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_5m_tokens": { - "name": "cache_write_5m_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_1h_tokens": { - "name": "cache_write_1h_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "key_id": { - "name": "key_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "key": { - "name": "key", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "key": { - "name": "key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_used": { - "name": "time_used", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_key": { - "name": "global_key", - "columns": ["key"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "key_workspace_id_id_pk": { - "name": "key_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "model": { - "name": "model", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "model_workspace_model": { - "name": "model_workspace_model", - "columns": ["workspace_id", "model"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "model_workspace_id_id_pk": { - "name": "model_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "provider": { - "name": "provider", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "credentials": { - "name": "credentials", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "workspace_provider": { - "name": "workspace_provider", - "columns": ["workspace_id", "provider"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "provider_workspace_id_id_pk": { - "name": "provider_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "account_id": { - "name": "account_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "color": { - "name": "color", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "role": { - "name": "role", - "type": "enum('admin','member')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "user_account_id": { - "name": "user_account_id", - "columns": ["workspace_id", "account_id"], - "isUnique": true - }, - "user_email": { - "name": "user_email", - "columns": ["workspace_id", "email"], - "isUnique": true - }, - "global_account_id": { - "name": "global_account_id", - "columns": ["account_id"], - "isUnique": false - }, - "global_email": { - "name": "global_email", - "columns": ["email"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "workspace": { - "name": "workspace", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": ["slug"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "workspace_id": { - "name": "workspace_id", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - } - }, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "tables": {}, - "indexes": {} - } -} diff --git a/packages/console/core/migrations/meta/0033_snapshot.json b/packages/console/core/migrations/meta/0033_snapshot.json deleted file mode 100644 index 76d4720e89..0000000000 --- a/packages/console/core/migrations/meta/0033_snapshot.json +++ /dev/null @@ -1,846 +0,0 @@ -{ - "version": "5", - "dialect": "mysql", - "id": "91ef8fda-ca96-4a3f-af29-dd6ae7136398", - "prevId": "b2406421-f22d-4153-a2a4-6deafe70ee54", - "tables": { - "account": { - "name": "account", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "email": { - "name": "email", - "columns": ["email"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "billing": { - "name": "billing", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_type": { - "name": "payment_method_type", - "type": "varchar(32)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_error": { - "name": "reload_error", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_error": { - "name": "time_reload_error", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_locked_till": { - "name": "time_reload_locked_till", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_customer_id": { - "name": "global_customer_id", - "columns": ["customer_id"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "payment": { - "name": "payment", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "invoice_id": { - "name": "invoice_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_refunded": { - "name": "time_refunded", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "usage": { - "name": "usage", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "input_tokens": { - "name": "input_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "output_tokens": { - "name": "output_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_5m_tokens": { - "name": "cache_write_5m_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_1h_tokens": { - "name": "cache_write_1h_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "key_id": { - "name": "key_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "key": { - "name": "key", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "key": { - "name": "key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_used": { - "name": "time_used", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_key": { - "name": "global_key", - "columns": ["key"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "key_workspace_id_id_pk": { - "name": "key_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "model": { - "name": "model", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "model_workspace_model": { - "name": "model_workspace_model", - "columns": ["workspace_id", "model"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "model_workspace_id_id_pk": { - "name": "model_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "provider": { - "name": "provider", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "credentials": { - "name": "credentials", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "workspace_provider": { - "name": "workspace_provider", - "columns": ["workspace_id", "provider"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "provider_workspace_id_id_pk": { - "name": "provider_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "account_id": { - "name": "account_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "color": { - "name": "color", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "role": { - "name": "role", - "type": "enum('admin','member')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "user_account_id": { - "name": "user_account_id", - "columns": ["workspace_id", "account_id"], - "isUnique": true - }, - "user_email": { - "name": "user_email", - "columns": ["workspace_id", "email"], - "isUnique": true - }, - "global_account_id": { - "name": "global_account_id", - "columns": ["account_id"], - "isUnique": false - }, - "global_email": { - "name": "global_email", - "columns": ["email"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "workspace": { - "name": "workspace", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": ["slug"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "workspace_id": { - "name": "workspace_id", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - } - }, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "tables": {}, - "indexes": {} - } -} diff --git a/packages/console/core/migrations/meta/0034_snapshot.json b/packages/console/core/migrations/meta/0034_snapshot.json deleted file mode 100644 index e9c999be71..0000000000 --- a/packages/console/core/migrations/meta/0034_snapshot.json +++ /dev/null @@ -1,913 +0,0 @@ -{ - "version": "5", - "dialect": "mysql", - "id": "34706440-26d7-43f5-9b39-815aa912e5ef", - "prevId": "91ef8fda-ca96-4a3f-af29-dd6ae7136398", - "tables": { - "account": { - "name": "account", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "email": { - "name": "email", - "columns": ["email"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "auth": { - "name": "auth", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "enum('email','github','google')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "subject": { - "name": "subject", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "account_id": { - "name": "account_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "provider": { - "name": "provider", - "columns": ["provider", "subject"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "billing": { - "name": "billing", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_type": { - "name": "payment_method_type", - "type": "varchar(32)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_error": { - "name": "reload_error", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_error": { - "name": "time_reload_error", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_locked_till": { - "name": "time_reload_locked_till", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_customer_id": { - "name": "global_customer_id", - "columns": ["customer_id"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "payment": { - "name": "payment", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "invoice_id": { - "name": "invoice_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_refunded": { - "name": "time_refunded", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "usage": { - "name": "usage", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "input_tokens": { - "name": "input_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "output_tokens": { - "name": "output_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_5m_tokens": { - "name": "cache_write_5m_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_1h_tokens": { - "name": "cache_write_1h_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "key_id": { - "name": "key_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "key": { - "name": "key", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "key": { - "name": "key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_used": { - "name": "time_used", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_key": { - "name": "global_key", - "columns": ["key"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "key_workspace_id_id_pk": { - "name": "key_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "model": { - "name": "model", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "model_workspace_model": { - "name": "model_workspace_model", - "columns": ["workspace_id", "model"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "model_workspace_id_id_pk": { - "name": "model_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "provider": { - "name": "provider", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "credentials": { - "name": "credentials", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "workspace_provider": { - "name": "workspace_provider", - "columns": ["workspace_id", "provider"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "provider_workspace_id_id_pk": { - "name": "provider_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "account_id": { - "name": "account_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "color": { - "name": "color", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "role": { - "name": "role", - "type": "enum('admin','member')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "user_account_id": { - "name": "user_account_id", - "columns": ["workspace_id", "account_id"], - "isUnique": true - }, - "user_email": { - "name": "user_email", - "columns": ["workspace_id", "email"], - "isUnique": true - }, - "global_account_id": { - "name": "global_account_id", - "columns": ["account_id"], - "isUnique": false - }, - "global_email": { - "name": "global_email", - "columns": ["email"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "workspace": { - "name": "workspace", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": ["slug"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "workspace_id": { - "name": "workspace_id", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - } - }, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "tables": {}, - "indexes": {} - } -} diff --git a/packages/console/core/migrations/meta/0035_snapshot.json b/packages/console/core/migrations/meta/0035_snapshot.json deleted file mode 100644 index 815d120ea0..0000000000 --- a/packages/console/core/migrations/meta/0035_snapshot.json +++ /dev/null @@ -1,905 +0,0 @@ -{ - "version": "5", - "dialect": "mysql", - "id": "10169105-4545-4894-838b-004c0a42c584", - "prevId": "34706440-26d7-43f5-9b39-815aa912e5ef", - "tables": { - "account": { - "name": "account", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "auth": { - "name": "auth", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "enum('email','github','google')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "subject": { - "name": "subject", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "account_id": { - "name": "account_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "provider": { - "name": "provider", - "columns": ["provider", "subject"], - "isUnique": true - }, - "account_id": { - "name": "account_id", - "columns": ["account_id"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "billing": { - "name": "billing", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_type": { - "name": "payment_method_type", - "type": "varchar(32)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_error": { - "name": "reload_error", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_error": { - "name": "time_reload_error", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_locked_till": { - "name": "time_reload_locked_till", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_customer_id": { - "name": "global_customer_id", - "columns": ["customer_id"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "payment": { - "name": "payment", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "invoice_id": { - "name": "invoice_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_refunded": { - "name": "time_refunded", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "usage": { - "name": "usage", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "input_tokens": { - "name": "input_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "output_tokens": { - "name": "output_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_5m_tokens": { - "name": "cache_write_5m_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_1h_tokens": { - "name": "cache_write_1h_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "key_id": { - "name": "key_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "key": { - "name": "key", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "key": { - "name": "key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_used": { - "name": "time_used", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_key": { - "name": "global_key", - "columns": ["key"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "key_workspace_id_id_pk": { - "name": "key_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "model": { - "name": "model", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "model_workspace_model": { - "name": "model_workspace_model", - "columns": ["workspace_id", "model"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "model_workspace_id_id_pk": { - "name": "model_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "provider": { - "name": "provider", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "credentials": { - "name": "credentials", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "workspace_provider": { - "name": "workspace_provider", - "columns": ["workspace_id", "provider"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "provider_workspace_id_id_pk": { - "name": "provider_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "account_id": { - "name": "account_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "color": { - "name": "color", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "role": { - "name": "role", - "type": "enum('admin','member')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "user_account_id": { - "name": "user_account_id", - "columns": ["workspace_id", "account_id"], - "isUnique": true - }, - "user_email": { - "name": "user_email", - "columns": ["workspace_id", "email"], - "isUnique": true - }, - "global_account_id": { - "name": "global_account_id", - "columns": ["account_id"], - "isUnique": false - }, - "global_email": { - "name": "global_email", - "columns": ["email"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "workspace": { - "name": "workspace", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": ["slug"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "workspace_id": { - "name": "workspace_id", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - } - }, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "tables": {}, - "indexes": {} - } -} diff --git a/packages/console/core/migrations/meta/0036_snapshot.json b/packages/console/core/migrations/meta/0036_snapshot.json deleted file mode 100644 index 926b143ebe..0000000000 --- a/packages/console/core/migrations/meta/0036_snapshot.json +++ /dev/null @@ -1,915 +0,0 @@ -{ - "version": "5", - "dialect": "mysql", - "id": "5470c8b4-296d-47bd-85a7-88cfd3b71434", - "prevId": "10169105-4545-4894-838b-004c0a42c584", - "tables": { - "account": { - "name": "account", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "account_id_pk": { - "name": "account_id_pk", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "auth": { - "name": "auth", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "enum('email','github','google')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "subject": { - "name": "subject", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "account_id": { - "name": "account_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "provider": { - "name": "provider", - "columns": ["provider", "subject"], - "isUnique": true - }, - "account_id": { - "name": "account_id", - "columns": ["account_id"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "auth_id_pk": { - "name": "auth_id_pk", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "billing": { - "name": "billing", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_type": { - "name": "payment_method_type", - "type": "varchar(32)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_error": { - "name": "reload_error", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_error": { - "name": "time_reload_error", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_locked_till": { - "name": "time_reload_locked_till", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_customer_id": { - "name": "global_customer_id", - "columns": ["customer_id"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "payment": { - "name": "payment", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "invoice_id": { - "name": "invoice_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_refunded": { - "name": "time_refunded", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "usage": { - "name": "usage", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "input_tokens": { - "name": "input_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "output_tokens": { - "name": "output_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_5m_tokens": { - "name": "cache_write_5m_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_1h_tokens": { - "name": "cache_write_1h_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "key_id": { - "name": "key_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "key": { - "name": "key", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "key": { - "name": "key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_used": { - "name": "time_used", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_key": { - "name": "global_key", - "columns": ["key"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "key_workspace_id_id_pk": { - "name": "key_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "model": { - "name": "model", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "model_workspace_model": { - "name": "model_workspace_model", - "columns": ["workspace_id", "model"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "model_workspace_id_id_pk": { - "name": "model_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "provider": { - "name": "provider", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "credentials": { - "name": "credentials", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "workspace_provider": { - "name": "workspace_provider", - "columns": ["workspace_id", "provider"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "provider_workspace_id_id_pk": { - "name": "provider_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "account_id": { - "name": "account_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "color": { - "name": "color", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "role": { - "name": "role", - "type": "enum('admin','member')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "user_account_id": { - "name": "user_account_id", - "columns": ["workspace_id", "account_id"], - "isUnique": true - }, - "user_email": { - "name": "user_email", - "columns": ["workspace_id", "email"], - "isUnique": true - }, - "global_account_id": { - "name": "global_account_id", - "columns": ["account_id"], - "isUnique": false - }, - "global_email": { - "name": "global_email", - "columns": ["email"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "workspace": { - "name": "workspace", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": ["slug"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "workspace_id": { - "name": "workspace_id", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - } - }, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "tables": {}, - "indexes": {} - } -} diff --git a/packages/console/core/migrations/meta/0037_snapshot.json b/packages/console/core/migrations/meta/0037_snapshot.json deleted file mode 100644 index 8a80ea5221..0000000000 --- a/packages/console/core/migrations/meta/0037_snapshot.json +++ /dev/null @@ -1,929 +0,0 @@ -{ - "version": "5", - "dialect": "mysql", - "id": "8b7fa839-a088-408e-84a4-1a07325c0290", - "prevId": "5470c8b4-296d-47bd-85a7-88cfd3b71434", - "tables": { - "account": { - "name": "account", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "account_id_pk": { - "name": "account_id_pk", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "auth": { - "name": "auth", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "enum('email','github','google')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "subject": { - "name": "subject", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "account_id": { - "name": "account_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "provider": { - "name": "provider", - "columns": ["provider", "subject"], - "isUnique": true - }, - "account_id": { - "name": "account_id", - "columns": ["account_id"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "auth_id_pk": { - "name": "auth_id_pk", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "billing": { - "name": "billing", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_type": { - "name": "payment_method_type", - "type": "varchar(32)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_trigger": { - "name": "reload_trigger", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_amount": { - "name": "reload_amount", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_error": { - "name": "reload_error", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_error": { - "name": "time_reload_error", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_locked_till": { - "name": "time_reload_locked_till", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_customer_id": { - "name": "global_customer_id", - "columns": ["customer_id"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "payment": { - "name": "payment", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "invoice_id": { - "name": "invoice_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_refunded": { - "name": "time_refunded", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "usage": { - "name": "usage", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "input_tokens": { - "name": "input_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "output_tokens": { - "name": "output_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_5m_tokens": { - "name": "cache_write_5m_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_1h_tokens": { - "name": "cache_write_1h_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "key_id": { - "name": "key_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "key": { - "name": "key", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "key": { - "name": "key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_used": { - "name": "time_used", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_key": { - "name": "global_key", - "columns": ["key"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "key_workspace_id_id_pk": { - "name": "key_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "model": { - "name": "model", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "model_workspace_model": { - "name": "model_workspace_model", - "columns": ["workspace_id", "model"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "model_workspace_id_id_pk": { - "name": "model_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "provider": { - "name": "provider", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "credentials": { - "name": "credentials", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "workspace_provider": { - "name": "workspace_provider", - "columns": ["workspace_id", "provider"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "provider_workspace_id_id_pk": { - "name": "provider_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "account_id": { - "name": "account_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "color": { - "name": "color", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "role": { - "name": "role", - "type": "enum('admin','member')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "user_account_id": { - "name": "user_account_id", - "columns": ["workspace_id", "account_id"], - "isUnique": true - }, - "user_email": { - "name": "user_email", - "columns": ["workspace_id", "email"], - "isUnique": true - }, - "global_account_id": { - "name": "global_account_id", - "columns": ["account_id"], - "isUnique": false - }, - "global_email": { - "name": "global_email", - "columns": ["email"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "workspace": { - "name": "workspace", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": ["slug"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "workspace_id": { - "name": "workspace_id", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - } - }, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "tables": {}, - "indexes": {} - } -} diff --git a/packages/console/core/migrations/meta/0038_snapshot.json b/packages/console/core/migrations/meta/0038_snapshot.json deleted file mode 100644 index b0a59c4978..0000000000 --- a/packages/console/core/migrations/meta/0038_snapshot.json +++ /dev/null @@ -1,981 +0,0 @@ -{ - "version": "5", - "dialect": "mysql", - "id": "9d5d9885-7ec5-45f6-ac53-45a8e25dede7", - "prevId": "8b7fa839-a088-408e-84a4-1a07325c0290", - "tables": { - "account": { - "name": "account", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "account_id_pk": { - "name": "account_id_pk", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "auth": { - "name": "auth", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "enum('email','github','google')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "subject": { - "name": "subject", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "account_id": { - "name": "account_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "provider": { - "name": "provider", - "columns": ["provider", "subject"], - "isUnique": true - }, - "account_id": { - "name": "account_id", - "columns": ["account_id"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "auth_id_pk": { - "name": "auth_id_pk", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "billing": { - "name": "billing", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_type": { - "name": "payment_method_type", - "type": "varchar(32)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_trigger": { - "name": "reload_trigger", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_amount": { - "name": "reload_amount", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_error": { - "name": "reload_error", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_error": { - "name": "time_reload_error", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_locked_till": { - "name": "time_reload_locked_till", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_customer_id": { - "name": "global_customer_id", - "columns": ["customer_id"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "payment": { - "name": "payment", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "invoice_id": { - "name": "invoice_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_refunded": { - "name": "time_refunded", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "usage": { - "name": "usage", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "input_tokens": { - "name": "input_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "output_tokens": { - "name": "output_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_5m_tokens": { - "name": "cache_write_5m_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_1h_tokens": { - "name": "cache_write_1h_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "key_id": { - "name": "key_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "ip": { - "name": "ip", - "columns": { - "ip": { - "name": "ip", - "type": "varchar(45)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "usage": { - "name": "usage", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "ip_ip_pk": { - "name": "ip_ip_pk", - "columns": ["ip"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "key": { - "name": "key", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "key": { - "name": "key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_used": { - "name": "time_used", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_key": { - "name": "global_key", - "columns": ["key"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "key_workspace_id_id_pk": { - "name": "key_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "model": { - "name": "model", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "model_workspace_model": { - "name": "model_workspace_model", - "columns": ["workspace_id", "model"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "model_workspace_id_id_pk": { - "name": "model_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "provider": { - "name": "provider", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "credentials": { - "name": "credentials", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "workspace_provider": { - "name": "workspace_provider", - "columns": ["workspace_id", "provider"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "provider_workspace_id_id_pk": { - "name": "provider_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "account_id": { - "name": "account_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "color": { - "name": "color", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "role": { - "name": "role", - "type": "enum('admin','member')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "user_account_id": { - "name": "user_account_id", - "columns": ["workspace_id", "account_id"], - "isUnique": true - }, - "user_email": { - "name": "user_email", - "columns": ["workspace_id", "email"], - "isUnique": true - }, - "global_account_id": { - "name": "global_account_id", - "columns": ["account_id"], - "isUnique": false - }, - "global_email": { - "name": "global_email", - "columns": ["email"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "workspace": { - "name": "workspace", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": ["slug"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "workspace_id": { - "name": "workspace_id", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - } - }, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "tables": {}, - "indexes": {} - } -} diff --git a/packages/console/core/migrations/meta/0039_snapshot.json b/packages/console/core/migrations/meta/0039_snapshot.json deleted file mode 100644 index ba34f1ac49..0000000000 --- a/packages/console/core/migrations/meta/0039_snapshot.json +++ /dev/null @@ -1,1053 +0,0 @@ -{ - "version": "5", - "dialect": "mysql", - "id": "49a1ac05-78ab-4aae-908e-d4aeeb8196fc", - "prevId": "9d5d9885-7ec5-45f6-ac53-45a8e25dede7", - "tables": { - "account": { - "name": "account", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "account_id_pk": { - "name": "account_id_pk", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "auth": { - "name": "auth", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "enum('email','github','google')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "subject": { - "name": "subject", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "account_id": { - "name": "account_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "provider": { - "name": "provider", - "columns": ["provider", "subject"], - "isUnique": true - }, - "account_id": { - "name": "account_id", - "columns": ["account_id"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "auth_id_pk": { - "name": "auth_id_pk", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "benchmark": { - "name": "benchmark", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "agent": { - "name": "agent", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "result": { - "name": "result", - "type": "mediumtext", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "time_created": { - "name": "time_created", - "columns": ["time_created"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "benchmark_id_pk": { - "name": "benchmark_id_pk", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "billing": { - "name": "billing", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_type": { - "name": "payment_method_type", - "type": "varchar(32)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_trigger": { - "name": "reload_trigger", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_amount": { - "name": "reload_amount", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_error": { - "name": "reload_error", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_error": { - "name": "time_reload_error", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_locked_till": { - "name": "time_reload_locked_till", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_customer_id": { - "name": "global_customer_id", - "columns": ["customer_id"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "payment": { - "name": "payment", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "invoice_id": { - "name": "invoice_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_refunded": { - "name": "time_refunded", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "usage": { - "name": "usage", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "input_tokens": { - "name": "input_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "output_tokens": { - "name": "output_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_5m_tokens": { - "name": "cache_write_5m_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_1h_tokens": { - "name": "cache_write_1h_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "key_id": { - "name": "key_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "ip": { - "name": "ip", - "columns": { - "ip": { - "name": "ip", - "type": "varchar(45)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "usage": { - "name": "usage", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "ip_ip_pk": { - "name": "ip_ip_pk", - "columns": ["ip"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "key": { - "name": "key", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "key": { - "name": "key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_used": { - "name": "time_used", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_key": { - "name": "global_key", - "columns": ["key"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "key_workspace_id_id_pk": { - "name": "key_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "model": { - "name": "model", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "model_workspace_model": { - "name": "model_workspace_model", - "columns": ["workspace_id", "model"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "model_workspace_id_id_pk": { - "name": "model_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "provider": { - "name": "provider", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "credentials": { - "name": "credentials", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "workspace_provider": { - "name": "workspace_provider", - "columns": ["workspace_id", "provider"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "provider_workspace_id_id_pk": { - "name": "provider_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "account_id": { - "name": "account_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "color": { - "name": "color", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "role": { - "name": "role", - "type": "enum('admin','member')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "user_account_id": { - "name": "user_account_id", - "columns": ["workspace_id", "account_id"], - "isUnique": true - }, - "user_email": { - "name": "user_email", - "columns": ["workspace_id", "email"], - "isUnique": true - }, - "global_account_id": { - "name": "global_account_id", - "columns": ["account_id"], - "isUnique": false - }, - "global_email": { - "name": "global_email", - "columns": ["email"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "workspace": { - "name": "workspace", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": ["slug"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "workspace_id": { - "name": "workspace_id", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - } - }, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "tables": {}, - "indexes": {} - } -} diff --git a/packages/console/core/migrations/meta/0040_snapshot.json b/packages/console/core/migrations/meta/0040_snapshot.json deleted file mode 100644 index 77012fd0ff..0000000000 --- a/packages/console/core/migrations/meta/0040_snapshot.json +++ /dev/null @@ -1,1059 +0,0 @@ -{ - "version": "5", - "dialect": "mysql", - "id": "bf19cd74-71f9-4bdf-b50e-67c2436f3408", - "prevId": "49a1ac05-78ab-4aae-908e-d4aeeb8196fc", - "tables": { - "account": { - "name": "account", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "account_id_pk": { - "name": "account_id_pk", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "auth": { - "name": "auth", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "enum('email','github','google')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "subject": { - "name": "subject", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "account_id": { - "name": "account_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "provider": { - "name": "provider", - "columns": ["provider", "subject"], - "isUnique": true - }, - "account_id": { - "name": "account_id", - "columns": ["account_id"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "auth_id_pk": { - "name": "auth_id_pk", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "benchmark": { - "name": "benchmark", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "agent": { - "name": "agent", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "result": { - "name": "result", - "type": "mediumtext", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "time_created": { - "name": "time_created", - "columns": ["time_created"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "benchmark_id_pk": { - "name": "benchmark_id_pk", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "billing": { - "name": "billing", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_type": { - "name": "payment_method_type", - "type": "varchar(32)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_trigger": { - "name": "reload_trigger", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_amount": { - "name": "reload_amount", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_error": { - "name": "reload_error", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_error": { - "name": "time_reload_error", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_locked_till": { - "name": "time_reload_locked_till", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_customer_id": { - "name": "global_customer_id", - "columns": ["customer_id"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "payment": { - "name": "payment", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "invoice_id": { - "name": "invoice_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_refunded": { - "name": "time_refunded", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "usage": { - "name": "usage", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "input_tokens": { - "name": "input_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "output_tokens": { - "name": "output_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_5m_tokens": { - "name": "cache_write_5m_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_1h_tokens": { - "name": "cache_write_1h_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "key_id": { - "name": "key_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "usage_time_created": { - "name": "usage_time_created", - "columns": ["workspace_id", "time_created"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "ip": { - "name": "ip", - "columns": { - "ip": { - "name": "ip", - "type": "varchar(45)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "usage": { - "name": "usage", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "ip_ip_pk": { - "name": "ip_ip_pk", - "columns": ["ip"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "key": { - "name": "key", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "key": { - "name": "key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_used": { - "name": "time_used", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_key": { - "name": "global_key", - "columns": ["key"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "key_workspace_id_id_pk": { - "name": "key_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "model": { - "name": "model", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "model_workspace_model": { - "name": "model_workspace_model", - "columns": ["workspace_id", "model"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "model_workspace_id_id_pk": { - "name": "model_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "provider": { - "name": "provider", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "credentials": { - "name": "credentials", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "workspace_provider": { - "name": "workspace_provider", - "columns": ["workspace_id", "provider"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "provider_workspace_id_id_pk": { - "name": "provider_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "account_id": { - "name": "account_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "color": { - "name": "color", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "role": { - "name": "role", - "type": "enum('admin','member')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "user_account_id": { - "name": "user_account_id", - "columns": ["workspace_id", "account_id"], - "isUnique": true - }, - "user_email": { - "name": "user_email", - "columns": ["workspace_id", "email"], - "isUnique": true - }, - "global_account_id": { - "name": "global_account_id", - "columns": ["account_id"], - "isUnique": false - }, - "global_email": { - "name": "global_email", - "columns": ["email"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "workspace": { - "name": "workspace", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": ["slug"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "workspace_id": { - "name": "workspace_id", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - } - }, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "tables": {}, - "indexes": {} - } -} diff --git a/packages/console/core/migrations/meta/0041_snapshot.json b/packages/console/core/migrations/meta/0041_snapshot.json deleted file mode 100644 index 583b55925b..0000000000 --- a/packages/console/core/migrations/meta/0041_snapshot.json +++ /dev/null @@ -1,1095 +0,0 @@ -{ - "version": "5", - "dialect": "mysql", - "id": "9cf10c24-6029-4cb4-866e-ff9b501eaf7e", - "prevId": "bf19cd74-71f9-4bdf-b50e-67c2436f3408", - "tables": { - "account": { - "name": "account", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "account_id_pk": { - "name": "account_id_pk", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "auth": { - "name": "auth", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "enum('email','github','google')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "subject": { - "name": "subject", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "account_id": { - "name": "account_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "provider": { - "name": "provider", - "columns": ["provider", "subject"], - "isUnique": true - }, - "account_id": { - "name": "account_id", - "columns": ["account_id"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "auth_id_pk": { - "name": "auth_id_pk", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "benchmark": { - "name": "benchmark", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "agent": { - "name": "agent", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "result": { - "name": "result", - "type": "mediumtext", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "time_created": { - "name": "time_created", - "columns": ["time_created"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "benchmark_id_pk": { - "name": "benchmark_id_pk", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "billing": { - "name": "billing", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_type": { - "name": "payment_method_type", - "type": "varchar(32)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_trigger": { - "name": "reload_trigger", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_amount": { - "name": "reload_amount", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_error": { - "name": "reload_error", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_error": { - "name": "time_reload_error", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_locked_till": { - "name": "time_reload_locked_till", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_customer_id": { - "name": "global_customer_id", - "columns": ["customer_id"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "payment": { - "name": "payment", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "invoice_id": { - "name": "invoice_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_refunded": { - "name": "time_refunded", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "usage": { - "name": "usage", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "input_tokens": { - "name": "input_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "output_tokens": { - "name": "output_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_5m_tokens": { - "name": "cache_write_5m_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_1h_tokens": { - "name": "cache_write_1h_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "key_id": { - "name": "key_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "usage_time_created": { - "name": "usage_time_created", - "columns": ["workspace_id", "time_created"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "ip_rate_limit": { - "name": "ip_rate_limit", - "columns": { - "ip": { - "name": "ip", - "type": "varchar(45)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "interval": { - "name": "interval", - "type": "varchar(10)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "count": { - "name": "count", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "ip_rate_limit_ip_interval_pk": { - "name": "ip_rate_limit_ip_interval_pk", - "columns": ["ip", "interval"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "ip": { - "name": "ip", - "columns": { - "ip": { - "name": "ip", - "type": "varchar(45)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "usage": { - "name": "usage", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "ip_ip_pk": { - "name": "ip_ip_pk", - "columns": ["ip"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "key": { - "name": "key", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "key": { - "name": "key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_used": { - "name": "time_used", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_key": { - "name": "global_key", - "columns": ["key"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "key_workspace_id_id_pk": { - "name": "key_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "model": { - "name": "model", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "model_workspace_model": { - "name": "model_workspace_model", - "columns": ["workspace_id", "model"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "model_workspace_id_id_pk": { - "name": "model_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "provider": { - "name": "provider", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "credentials": { - "name": "credentials", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "workspace_provider": { - "name": "workspace_provider", - "columns": ["workspace_id", "provider"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "provider_workspace_id_id_pk": { - "name": "provider_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "account_id": { - "name": "account_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "color": { - "name": "color", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "role": { - "name": "role", - "type": "enum('admin','member')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "user_account_id": { - "name": "user_account_id", - "columns": ["workspace_id", "account_id"], - "isUnique": true - }, - "user_email": { - "name": "user_email", - "columns": ["workspace_id", "email"], - "isUnique": true - }, - "global_account_id": { - "name": "global_account_id", - "columns": ["account_id"], - "isUnique": false - }, - "global_email": { - "name": "global_email", - "columns": ["email"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "workspace": { - "name": "workspace", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": ["slug"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "workspace_id": { - "name": "workspace_id", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - } - }, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "tables": {}, - "indexes": {} - } -} diff --git a/packages/console/core/migrations/meta/0042_snapshot.json b/packages/console/core/migrations/meta/0042_snapshot.json deleted file mode 100644 index e0f731e397..0000000000 --- a/packages/console/core/migrations/meta/0042_snapshot.json +++ /dev/null @@ -1,1144 +0,0 @@ -{ - "version": "5", - "dialect": "mysql", - "id": "4775571c-ad9c-4104-a202-2374b1963cfe", - "prevId": "9cf10c24-6029-4cb4-866e-ff9b501eaf7e", - "tables": { - "account": { - "name": "account", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "account_id_pk": { - "name": "account_id_pk", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "auth": { - "name": "auth", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "enum('email','github','google')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "subject": { - "name": "subject", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "account_id": { - "name": "account_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "provider": { - "name": "provider", - "columns": ["provider", "subject"], - "isUnique": true - }, - "account_id": { - "name": "account_id", - "columns": ["account_id"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "auth_id_pk": { - "name": "auth_id_pk", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "benchmark": { - "name": "benchmark", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "agent": { - "name": "agent", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "result": { - "name": "result", - "type": "mediumtext", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "time_created": { - "name": "time_created", - "columns": ["time_created"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "benchmark_id_pk": { - "name": "benchmark_id_pk", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "billing": { - "name": "billing", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_type": { - "name": "payment_method_type", - "type": "varchar(32)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_trigger": { - "name": "reload_trigger", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_amount": { - "name": "reload_amount", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_error": { - "name": "reload_error", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_error": { - "name": "time_reload_error", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_locked_till": { - "name": "time_reload_locked_till", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "subscription_id": { - "name": "subscription_id", - "type": "varchar(28)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_customer_id": { - "name": "global_customer_id", - "columns": ["customer_id"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "payment": { - "name": "payment", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "invoice_id": { - "name": "invoice_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_refunded": { - "name": "time_refunded", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "usage": { - "name": "usage", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "input_tokens": { - "name": "input_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "output_tokens": { - "name": "output_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_5m_tokens": { - "name": "cache_write_5m_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_1h_tokens": { - "name": "cache_write_1h_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "key_id": { - "name": "key_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "data": { - "name": "data", - "type": "json", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "usage_time_created": { - "name": "usage_time_created", - "columns": ["workspace_id", "time_created"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "ip_rate_limit": { - "name": "ip_rate_limit", - "columns": { - "ip": { - "name": "ip", - "type": "varchar(45)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "interval": { - "name": "interval", - "type": "varchar(10)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "count": { - "name": "count", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "ip_rate_limit_ip_interval_pk": { - "name": "ip_rate_limit_ip_interval_pk", - "columns": ["ip", "interval"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "ip": { - "name": "ip", - "columns": { - "ip": { - "name": "ip", - "type": "varchar(45)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "usage": { - "name": "usage", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "ip_ip_pk": { - "name": "ip_ip_pk", - "columns": ["ip"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "key": { - "name": "key", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "key": { - "name": "key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_used": { - "name": "time_used", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_key": { - "name": "global_key", - "columns": ["key"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "key_workspace_id_id_pk": { - "name": "key_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "model": { - "name": "model", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "model_workspace_model": { - "name": "model_workspace_model", - "columns": ["workspace_id", "model"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "model_workspace_id_id_pk": { - "name": "model_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "provider": { - "name": "provider", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "credentials": { - "name": "credentials", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "workspace_provider": { - "name": "workspace_provider", - "columns": ["workspace_id", "provider"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "provider_workspace_id_id_pk": { - "name": "provider_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "account_id": { - "name": "account_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "color": { - "name": "color", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "role": { - "name": "role", - "type": "enum('admin','member')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_subscribed": { - "name": "time_subscribed", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "sub_recent_usage": { - "name": "sub_recent_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "sub_monthly_usage": { - "name": "sub_monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "sub_time_recent_usage_updated": { - "name": "sub_time_recent_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "sub_time_monthly_usage_updated": { - "name": "sub_time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "user_account_id": { - "name": "user_account_id", - "columns": ["workspace_id", "account_id"], - "isUnique": true - }, - "user_email": { - "name": "user_email", - "columns": ["workspace_id", "email"], - "isUnique": true - }, - "global_account_id": { - "name": "global_account_id", - "columns": ["account_id"], - "isUnique": false - }, - "global_email": { - "name": "global_email", - "columns": ["email"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "workspace": { - "name": "workspace", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": ["slug"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "workspace_id": { - "name": "workspace_id", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - } - }, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "tables": {}, - "indexes": {} - } -} diff --git a/packages/console/core/migrations/meta/0043_snapshot.json b/packages/console/core/migrations/meta/0043_snapshot.json deleted file mode 100644 index ef9caa74e6..0000000000 --- a/packages/console/core/migrations/meta/0043_snapshot.json +++ /dev/null @@ -1,1147 +0,0 @@ -{ - "version": "5", - "dialect": "mysql", - "id": "3ff862f3-eeb6-4b10-8c78-254de3778ab3", - "prevId": "4775571c-ad9c-4104-a202-2374b1963cfe", - "tables": { - "account": { - "name": "account", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "account_id_pk": { - "name": "account_id_pk", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "auth": { - "name": "auth", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "enum('email','github','google')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "subject": { - "name": "subject", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "account_id": { - "name": "account_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "provider": { - "name": "provider", - "columns": ["provider", "subject"], - "isUnique": true - }, - "account_id": { - "name": "account_id", - "columns": ["account_id"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "auth_id_pk": { - "name": "auth_id_pk", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "benchmark": { - "name": "benchmark", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "agent": { - "name": "agent", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "result": { - "name": "result", - "type": "mediumtext", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "time_created": { - "name": "time_created", - "columns": ["time_created"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "benchmark_id_pk": { - "name": "benchmark_id_pk", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "billing": { - "name": "billing", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_type": { - "name": "payment_method_type", - "type": "varchar(32)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_trigger": { - "name": "reload_trigger", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_amount": { - "name": "reload_amount", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_error": { - "name": "reload_error", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_error": { - "name": "time_reload_error", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_locked_till": { - "name": "time_reload_locked_till", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "subscription_id": { - "name": "subscription_id", - "type": "varchar(28)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_customer_id": { - "name": "global_customer_id", - "columns": ["customer_id"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "payment": { - "name": "payment", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "invoice_id": { - "name": "invoice_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_refunded": { - "name": "time_refunded", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "usage": { - "name": "usage", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "input_tokens": { - "name": "input_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "output_tokens": { - "name": "output_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_5m_tokens": { - "name": "cache_write_5m_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_1h_tokens": { - "name": "cache_write_1h_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "key_id": { - "name": "key_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "data": { - "name": "data", - "type": "json", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "usage_time_created": { - "name": "usage_time_created", - "columns": ["workspace_id", "time_created"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "ip_rate_limit": { - "name": "ip_rate_limit", - "columns": { - "ip": { - "name": "ip", - "type": "varchar(45)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "interval": { - "name": "interval", - "type": "varchar(10)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "count": { - "name": "count", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "ip_rate_limit_ip_interval_pk": { - "name": "ip_rate_limit_ip_interval_pk", - "columns": ["ip", "interval"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "ip": { - "name": "ip", - "columns": { - "ip": { - "name": "ip", - "type": "varchar(45)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "usage": { - "name": "usage", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "ip_ip_pk": { - "name": "ip_ip_pk", - "columns": ["ip"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "key": { - "name": "key", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "key": { - "name": "key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_used": { - "name": "time_used", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_key": { - "name": "global_key", - "columns": ["key"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "key_workspace_id_id_pk": { - "name": "key_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "model": { - "name": "model", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "model_workspace_model": { - "name": "model_workspace_model", - "columns": ["workspace_id", "model"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "model_workspace_id_id_pk": { - "name": "model_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "provider": { - "name": "provider", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "credentials": { - "name": "credentials", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "workspace_provider": { - "name": "workspace_provider", - "columns": ["workspace_id", "provider"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "provider_workspace_id_id_pk": { - "name": "provider_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "account_id": { - "name": "account_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "color": { - "name": "color", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "role": { - "name": "role", - "type": "enum('admin','member')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_subscribed": { - "name": "time_subscribed", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "sub_interval_usage": { - "name": "sub_interval_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "sub_monthly_usage": { - "name": "sub_monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "sub_time_interval_usage_updated": { - "name": "sub_time_interval_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "sub_time_monthly_usage_updated": { - "name": "sub_time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "user_account_id": { - "name": "user_account_id", - "columns": ["workspace_id", "account_id"], - "isUnique": true - }, - "user_email": { - "name": "user_email", - "columns": ["workspace_id", "email"], - "isUnique": true - }, - "global_account_id": { - "name": "global_account_id", - "columns": ["account_id"], - "isUnique": false - }, - "global_email": { - "name": "global_email", - "columns": ["email"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "workspace": { - "name": "workspace", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": ["slug"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "workspace_id": { - "name": "workspace_id", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - } - }, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": { - "\"user\".\"sub_recent_usage\"": "\"user\".\"sub_interval_usage\"", - "\"user\".\"sub_time_recent_usage_updated\"": "\"user\".\"sub_time_interval_usage_updated\"" - } - }, - "internal": { - "tables": {}, - "indexes": {} - } -} diff --git a/packages/console/core/migrations/meta/0044_snapshot.json b/packages/console/core/migrations/meta/0044_snapshot.json deleted file mode 100644 index cde7fabf22..0000000000 --- a/packages/console/core/migrations/meta/0044_snapshot.json +++ /dev/null @@ -1,1146 +0,0 @@ -{ - "version": "5", - "dialect": "mysql", - "id": "70394850-2c28-4012-a3d5-69357e3348b6", - "prevId": "3ff862f3-eeb6-4b10-8c78-254de3778ab3", - "tables": { - "account": { - "name": "account", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "account_id_pk": { - "name": "account_id_pk", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "auth": { - "name": "auth", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "enum('email','github','google')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "subject": { - "name": "subject", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "account_id": { - "name": "account_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "provider": { - "name": "provider", - "columns": ["provider", "subject"], - "isUnique": true - }, - "account_id": { - "name": "account_id", - "columns": ["account_id"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "auth_id_pk": { - "name": "auth_id_pk", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "benchmark": { - "name": "benchmark", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "agent": { - "name": "agent", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "result": { - "name": "result", - "type": "mediumtext", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "time_created": { - "name": "time_created", - "columns": ["time_created"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "benchmark_id_pk": { - "name": "benchmark_id_pk", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "billing": { - "name": "billing", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_type": { - "name": "payment_method_type", - "type": "varchar(32)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_trigger": { - "name": "reload_trigger", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_amount": { - "name": "reload_amount", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_error": { - "name": "reload_error", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_error": { - "name": "time_reload_error", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_locked_till": { - "name": "time_reload_locked_till", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "subscription_id": { - "name": "subscription_id", - "type": "varchar(28)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_customer_id": { - "name": "global_customer_id", - "columns": ["customer_id"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "payment": { - "name": "payment", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "invoice_id": { - "name": "invoice_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_refunded": { - "name": "time_refunded", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "usage": { - "name": "usage", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "input_tokens": { - "name": "input_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "output_tokens": { - "name": "output_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_5m_tokens": { - "name": "cache_write_5m_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_1h_tokens": { - "name": "cache_write_1h_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "key_id": { - "name": "key_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "enrichment": { - "name": "enrichment", - "type": "json", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "usage_time_created": { - "name": "usage_time_created", - "columns": ["workspace_id", "time_created"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "ip_rate_limit": { - "name": "ip_rate_limit", - "columns": { - "ip": { - "name": "ip", - "type": "varchar(45)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "interval": { - "name": "interval", - "type": "varchar(10)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "count": { - "name": "count", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "ip_rate_limit_ip_interval_pk": { - "name": "ip_rate_limit_ip_interval_pk", - "columns": ["ip", "interval"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "ip": { - "name": "ip", - "columns": { - "ip": { - "name": "ip", - "type": "varchar(45)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "usage": { - "name": "usage", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "ip_ip_pk": { - "name": "ip_ip_pk", - "columns": ["ip"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "key": { - "name": "key", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "key": { - "name": "key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_used": { - "name": "time_used", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_key": { - "name": "global_key", - "columns": ["key"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "key_workspace_id_id_pk": { - "name": "key_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "model": { - "name": "model", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "model_workspace_model": { - "name": "model_workspace_model", - "columns": ["workspace_id", "model"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "model_workspace_id_id_pk": { - "name": "model_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "provider": { - "name": "provider", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "credentials": { - "name": "credentials", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "workspace_provider": { - "name": "workspace_provider", - "columns": ["workspace_id", "provider"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "provider_workspace_id_id_pk": { - "name": "provider_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "account_id": { - "name": "account_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "color": { - "name": "color", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "role": { - "name": "role", - "type": "enum('admin','member')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_subscribed": { - "name": "time_subscribed", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "sub_interval_usage": { - "name": "sub_interval_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "sub_monthly_usage": { - "name": "sub_monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "sub_time_interval_usage_updated": { - "name": "sub_time_interval_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "sub_time_monthly_usage_updated": { - "name": "sub_time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "user_account_id": { - "name": "user_account_id", - "columns": ["workspace_id", "account_id"], - "isUnique": true - }, - "user_email": { - "name": "user_email", - "columns": ["workspace_id", "email"], - "isUnique": true - }, - "global_account_id": { - "name": "global_account_id", - "columns": ["account_id"], - "isUnique": false - }, - "global_email": { - "name": "global_email", - "columns": ["email"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "workspace": { - "name": "workspace", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": ["slug"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "workspace_id": { - "name": "workspace_id", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - } - }, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": { - "\"usage\".\"data\"": "\"usage\".\"enrichment\"" - } - }, - "internal": { - "tables": {}, - "indexes": {} - } -} diff --git a/packages/console/core/migrations/meta/0045_snapshot.json b/packages/console/core/migrations/meta/0045_snapshot.json deleted file mode 100644 index 6ab9760c68..0000000000 --- a/packages/console/core/migrations/meta/0045_snapshot.json +++ /dev/null @@ -1,1149 +0,0 @@ -{ - "version": "5", - "dialect": "mysql", - "id": "27c1a3eb-b125-46d4-b436-abe5764fe4b7", - "prevId": "70394850-2c28-4012-a3d5-69357e3348b6", - "tables": { - "account": { - "name": "account", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "account_id_pk": { - "name": "account_id_pk", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "auth": { - "name": "auth", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "enum('email','github','google')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "subject": { - "name": "subject", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "account_id": { - "name": "account_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "provider": { - "name": "provider", - "columns": ["provider", "subject"], - "isUnique": true - }, - "account_id": { - "name": "account_id", - "columns": ["account_id"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "auth_id_pk": { - "name": "auth_id_pk", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "benchmark": { - "name": "benchmark", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "agent": { - "name": "agent", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "result": { - "name": "result", - "type": "mediumtext", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "time_created": { - "name": "time_created", - "columns": ["time_created"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "benchmark_id_pk": { - "name": "benchmark_id_pk", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "billing": { - "name": "billing", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_type": { - "name": "payment_method_type", - "type": "varchar(32)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_trigger": { - "name": "reload_trigger", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_amount": { - "name": "reload_amount", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_error": { - "name": "reload_error", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_error": { - "name": "time_reload_error", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_locked_till": { - "name": "time_reload_locked_till", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "subscription_id": { - "name": "subscription_id", - "type": "varchar(28)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_customer_id": { - "name": "global_customer_id", - "columns": ["customer_id"], - "isUnique": true - }, - "global_subscription_id": { - "name": "global_subscription_id", - "columns": ["subscription_id"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "payment": { - "name": "payment", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "invoice_id": { - "name": "invoice_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_refunded": { - "name": "time_refunded", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "usage": { - "name": "usage", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "input_tokens": { - "name": "input_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "output_tokens": { - "name": "output_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_5m_tokens": { - "name": "cache_write_5m_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_1h_tokens": { - "name": "cache_write_1h_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "key_id": { - "name": "key_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "enrichment": { - "name": "enrichment", - "type": "json", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "usage_time_created": { - "name": "usage_time_created", - "columns": ["workspace_id", "time_created"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "ip_rate_limit": { - "name": "ip_rate_limit", - "columns": { - "ip": { - "name": "ip", - "type": "varchar(45)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "interval": { - "name": "interval", - "type": "varchar(10)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "count": { - "name": "count", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "ip_rate_limit_ip_interval_pk": { - "name": "ip_rate_limit_ip_interval_pk", - "columns": ["ip", "interval"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "ip": { - "name": "ip", - "columns": { - "ip": { - "name": "ip", - "type": "varchar(45)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "usage": { - "name": "usage", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "ip_ip_pk": { - "name": "ip_ip_pk", - "columns": ["ip"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "key": { - "name": "key", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "key": { - "name": "key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_used": { - "name": "time_used", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_key": { - "name": "global_key", - "columns": ["key"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "key_workspace_id_id_pk": { - "name": "key_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "model": { - "name": "model", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "model_workspace_model": { - "name": "model_workspace_model", - "columns": ["workspace_id", "model"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "model_workspace_id_id_pk": { - "name": "model_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "provider": { - "name": "provider", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "credentials": { - "name": "credentials", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "workspace_provider": { - "name": "workspace_provider", - "columns": ["workspace_id", "provider"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "provider_workspace_id_id_pk": { - "name": "provider_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "account_id": { - "name": "account_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "color": { - "name": "color", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "role": { - "name": "role", - "type": "enum('admin','member')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_subscribed": { - "name": "time_subscribed", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "sub_interval_usage": { - "name": "sub_interval_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "sub_monthly_usage": { - "name": "sub_monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "sub_time_interval_usage_updated": { - "name": "sub_time_interval_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "sub_time_monthly_usage_updated": { - "name": "sub_time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "user_account_id": { - "name": "user_account_id", - "columns": ["workspace_id", "account_id"], - "isUnique": true - }, - "user_email": { - "name": "user_email", - "columns": ["workspace_id", "email"], - "isUnique": true - }, - "global_account_id": { - "name": "global_account_id", - "columns": ["account_id"], - "isUnique": false - }, - "global_email": { - "name": "global_email", - "columns": ["email"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "workspace": { - "name": "workspace", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": ["slug"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "workspace_id": { - "name": "workspace_id", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - } - }, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "tables": {}, - "indexes": {} - } -} diff --git a/packages/console/core/migrations/meta/0046_snapshot.json b/packages/console/core/migrations/meta/0046_snapshot.json deleted file mode 100644 index 46ff73e263..0000000000 --- a/packages/console/core/migrations/meta/0046_snapshot.json +++ /dev/null @@ -1,1236 +0,0 @@ -{ - "version": "5", - "dialect": "mysql", - "id": "f3725f6d-5f33-4497-b4ba-cf05c46fb873", - "prevId": "27c1a3eb-b125-46d4-b436-abe5764fe4b7", - "tables": { - "account": { - "name": "account", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "account_id_pk": { - "name": "account_id_pk", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "auth": { - "name": "auth", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "enum('email','github','google')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "subject": { - "name": "subject", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "account_id": { - "name": "account_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "provider": { - "name": "provider", - "columns": ["provider", "subject"], - "isUnique": true - }, - "account_id": { - "name": "account_id", - "columns": ["account_id"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "auth_id_pk": { - "name": "auth_id_pk", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "benchmark": { - "name": "benchmark", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "agent": { - "name": "agent", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "result": { - "name": "result", - "type": "mediumtext", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "time_created": { - "name": "time_created", - "columns": ["time_created"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "benchmark_id_pk": { - "name": "benchmark_id_pk", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "billing": { - "name": "billing", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_type": { - "name": "payment_method_type", - "type": "varchar(32)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_trigger": { - "name": "reload_trigger", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_amount": { - "name": "reload_amount", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_error": { - "name": "reload_error", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_error": { - "name": "time_reload_error", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_locked_till": { - "name": "time_reload_locked_till", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "subscription_id": { - "name": "subscription_id", - "type": "varchar(28)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_customer_id": { - "name": "global_customer_id", - "columns": ["customer_id"], - "isUnique": true - }, - "global_subscription_id": { - "name": "global_subscription_id", - "columns": ["subscription_id"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "payment": { - "name": "payment", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "invoice_id": { - "name": "invoice_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_refunded": { - "name": "time_refunded", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "subscription": { - "name": "subscription", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "rolling_usage": { - "name": "rolling_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "fixed_usage": { - "name": "fixed_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_rolling_updated": { - "name": "time_rolling_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_fixed_updated": { - "name": "time_fixed_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "subscription_workspace_id_id_pk": { - "name": "subscription_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "usage": { - "name": "usage", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "input_tokens": { - "name": "input_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "output_tokens": { - "name": "output_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_5m_tokens": { - "name": "cache_write_5m_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_1h_tokens": { - "name": "cache_write_1h_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "key_id": { - "name": "key_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "enrichment": { - "name": "enrichment", - "type": "json", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "usage_time_created": { - "name": "usage_time_created", - "columns": ["workspace_id", "time_created"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "ip_rate_limit": { - "name": "ip_rate_limit", - "columns": { - "ip": { - "name": "ip", - "type": "varchar(45)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "interval": { - "name": "interval", - "type": "varchar(10)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "count": { - "name": "count", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "ip_rate_limit_ip_interval_pk": { - "name": "ip_rate_limit_ip_interval_pk", - "columns": ["ip", "interval"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "ip": { - "name": "ip", - "columns": { - "ip": { - "name": "ip", - "type": "varchar(45)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "usage": { - "name": "usage", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "ip_ip_pk": { - "name": "ip_ip_pk", - "columns": ["ip"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "key": { - "name": "key", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "key": { - "name": "key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_used": { - "name": "time_used", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_key": { - "name": "global_key", - "columns": ["key"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "key_workspace_id_id_pk": { - "name": "key_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "model": { - "name": "model", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "model_workspace_model": { - "name": "model_workspace_model", - "columns": ["workspace_id", "model"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "model_workspace_id_id_pk": { - "name": "model_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "provider": { - "name": "provider", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "credentials": { - "name": "credentials", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "workspace_provider": { - "name": "workspace_provider", - "columns": ["workspace_id", "provider"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "provider_workspace_id_id_pk": { - "name": "provider_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "account_id": { - "name": "account_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "color": { - "name": "color", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "role": { - "name": "role", - "type": "enum('admin','member')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_subscribed": { - "name": "time_subscribed", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "sub_interval_usage": { - "name": "sub_interval_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "sub_monthly_usage": { - "name": "sub_monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "sub_time_interval_usage_updated": { - "name": "sub_time_interval_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "sub_time_monthly_usage_updated": { - "name": "sub_time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "user_account_id": { - "name": "user_account_id", - "columns": ["workspace_id", "account_id"], - "isUnique": true - }, - "user_email": { - "name": "user_email", - "columns": ["workspace_id", "email"], - "isUnique": true - }, - "global_account_id": { - "name": "global_account_id", - "columns": ["account_id"], - "isUnique": false - }, - "global_email": { - "name": "global_email", - "columns": ["email"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "workspace": { - "name": "workspace", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": ["slug"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "workspace_id": { - "name": "workspace_id", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - } - }, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "tables": {}, - "indexes": {} - } -} diff --git a/packages/console/core/migrations/meta/0047_snapshot.json b/packages/console/core/migrations/meta/0047_snapshot.json deleted file mode 100644 index f8002bd8bb..0000000000 --- a/packages/console/core/migrations/meta/0047_snapshot.json +++ /dev/null @@ -1,1207 +0,0 @@ -{ - "version": "5", - "dialect": "mysql", - "id": "fec4cb15-6f13-465d-a902-b76b026872f4", - "prevId": "f3725f6d-5f33-4497-b4ba-cf05c46fb873", - "tables": { - "account": { - "name": "account", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "account_id_pk": { - "name": "account_id_pk", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "auth": { - "name": "auth", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "enum('email','github','google')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "subject": { - "name": "subject", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "account_id": { - "name": "account_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "provider": { - "name": "provider", - "columns": ["provider", "subject"], - "isUnique": true - }, - "account_id": { - "name": "account_id", - "columns": ["account_id"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "auth_id_pk": { - "name": "auth_id_pk", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "benchmark": { - "name": "benchmark", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "agent": { - "name": "agent", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "result": { - "name": "result", - "type": "mediumtext", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "time_created": { - "name": "time_created", - "columns": ["time_created"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "benchmark_id_pk": { - "name": "benchmark_id_pk", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "billing": { - "name": "billing", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_type": { - "name": "payment_method_type", - "type": "varchar(32)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_trigger": { - "name": "reload_trigger", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_amount": { - "name": "reload_amount", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_error": { - "name": "reload_error", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_error": { - "name": "time_reload_error", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_locked_till": { - "name": "time_reload_locked_till", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "subscription_id": { - "name": "subscription_id", - "type": "varchar(28)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_customer_id": { - "name": "global_customer_id", - "columns": ["customer_id"], - "isUnique": true - }, - "global_subscription_id": { - "name": "global_subscription_id", - "columns": ["subscription_id"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "payment": { - "name": "payment", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "invoice_id": { - "name": "invoice_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_refunded": { - "name": "time_refunded", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "subscription": { - "name": "subscription", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "rolling_usage": { - "name": "rolling_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "fixed_usage": { - "name": "fixed_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_rolling_updated": { - "name": "time_rolling_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_fixed_updated": { - "name": "time_fixed_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "workspace_user_id": { - "name": "workspace_user_id", - "columns": ["workspace_id", "user_id"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "subscription_workspace_id_id_pk": { - "name": "subscription_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "usage": { - "name": "usage", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "input_tokens": { - "name": "input_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "output_tokens": { - "name": "output_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_5m_tokens": { - "name": "cache_write_5m_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_1h_tokens": { - "name": "cache_write_1h_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "key_id": { - "name": "key_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "enrichment": { - "name": "enrichment", - "type": "json", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "usage_time_created": { - "name": "usage_time_created", - "columns": ["workspace_id", "time_created"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "ip_rate_limit": { - "name": "ip_rate_limit", - "columns": { - "ip": { - "name": "ip", - "type": "varchar(45)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "interval": { - "name": "interval", - "type": "varchar(10)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "count": { - "name": "count", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "ip_rate_limit_ip_interval_pk": { - "name": "ip_rate_limit_ip_interval_pk", - "columns": ["ip", "interval"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "ip": { - "name": "ip", - "columns": { - "ip": { - "name": "ip", - "type": "varchar(45)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "usage": { - "name": "usage", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "ip_ip_pk": { - "name": "ip_ip_pk", - "columns": ["ip"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "key": { - "name": "key", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "key": { - "name": "key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_used": { - "name": "time_used", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_key": { - "name": "global_key", - "columns": ["key"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "key_workspace_id_id_pk": { - "name": "key_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "model": { - "name": "model", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "model_workspace_model": { - "name": "model_workspace_model", - "columns": ["workspace_id", "model"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "model_workspace_id_id_pk": { - "name": "model_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "provider": { - "name": "provider", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "credentials": { - "name": "credentials", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "workspace_provider": { - "name": "workspace_provider", - "columns": ["workspace_id", "provider"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "provider_workspace_id_id_pk": { - "name": "provider_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "account_id": { - "name": "account_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "color": { - "name": "color", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "role": { - "name": "role", - "type": "enum('admin','member')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "user_account_id": { - "name": "user_account_id", - "columns": ["workspace_id", "account_id"], - "isUnique": true - }, - "user_email": { - "name": "user_email", - "columns": ["workspace_id", "email"], - "isUnique": true - }, - "global_account_id": { - "name": "global_account_id", - "columns": ["account_id"], - "isUnique": false - }, - "global_email": { - "name": "global_email", - "columns": ["email"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "workspace": { - "name": "workspace", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": ["slug"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "workspace_id": { - "name": "workspace_id", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - } - }, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "tables": {}, - "indexes": {} - } -} diff --git a/packages/console/core/migrations/meta/0048_snapshot.json b/packages/console/core/migrations/meta/0048_snapshot.json deleted file mode 100644 index e0593749b3..0000000000 --- a/packages/console/core/migrations/meta/0048_snapshot.json +++ /dev/null @@ -1,1207 +0,0 @@ -{ - "version": "5", - "dialect": "mysql", - "id": "bb90bb3e-fd08-439a-b92f-5f433807480e", - "prevId": "fec4cb15-6f13-465d-a902-b76b026872f4", - "tables": { - "account": { - "name": "account", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "account_id_pk": { - "name": "account_id_pk", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "auth": { - "name": "auth", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "enum('email','github','google')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "subject": { - "name": "subject", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "account_id": { - "name": "account_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "provider": { - "name": "provider", - "columns": ["provider", "subject"], - "isUnique": true - }, - "account_id": { - "name": "account_id", - "columns": ["account_id"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "auth_id_pk": { - "name": "auth_id_pk", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "benchmark": { - "name": "benchmark", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "agent": { - "name": "agent", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "result": { - "name": "result", - "type": "mediumtext", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "time_created": { - "name": "time_created", - "columns": ["time_created"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "benchmark_id_pk": { - "name": "benchmark_id_pk", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "billing": { - "name": "billing", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_type": { - "name": "payment_method_type", - "type": "varchar(32)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_trigger": { - "name": "reload_trigger", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_amount": { - "name": "reload_amount", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_error": { - "name": "reload_error", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_error": { - "name": "time_reload_error", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_locked_till": { - "name": "time_reload_locked_till", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "subscription_id": { - "name": "subscription_id", - "type": "varchar(28)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_customer_id": { - "name": "global_customer_id", - "columns": ["customer_id"], - "isUnique": true - }, - "global_subscription_id": { - "name": "global_subscription_id", - "columns": ["subscription_id"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "payment": { - "name": "payment", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "invoice_id": { - "name": "invoice_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_refunded": { - "name": "time_refunded", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "subscription": { - "name": "subscription", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "rolling_usage": { - "name": "rolling_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "fixed_usage": { - "name": "fixed_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_rolling_updated": { - "name": "time_rolling_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_fixed_updated": { - "name": "time_fixed_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "workspace_user_id": { - "name": "workspace_user_id", - "columns": ["workspace_id", "user_id"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "subscription_workspace_id_id_pk": { - "name": "subscription_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "usage": { - "name": "usage", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "input_tokens": { - "name": "input_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "output_tokens": { - "name": "output_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_5m_tokens": { - "name": "cache_write_5m_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_1h_tokens": { - "name": "cache_write_1h_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "key_id": { - "name": "key_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "enrichment": { - "name": "enrichment", - "type": "json", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "usage_time_created": { - "name": "usage_time_created", - "columns": ["workspace_id", "time_created"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "ip_rate_limit": { - "name": "ip_rate_limit", - "columns": { - "ip": { - "name": "ip", - "type": "varchar(45)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "interval": { - "name": "interval", - "type": "varchar(10)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "count": { - "name": "count", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "ip_rate_limit_ip_interval_pk": { - "name": "ip_rate_limit_ip_interval_pk", - "columns": ["ip", "interval"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "ip": { - "name": "ip", - "columns": { - "ip": { - "name": "ip", - "type": "varchar(45)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "usage": { - "name": "usage", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "ip_ip_pk": { - "name": "ip_ip_pk", - "columns": ["ip"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "key": { - "name": "key", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "key": { - "name": "key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_used": { - "name": "time_used", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_key": { - "name": "global_key", - "columns": ["key"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "key_workspace_id_id_pk": { - "name": "key_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "model": { - "name": "model", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "model_workspace_model": { - "name": "model_workspace_model", - "columns": ["workspace_id", "model"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "model_workspace_id_id_pk": { - "name": "model_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "provider": { - "name": "provider", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "credentials": { - "name": "credentials", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "workspace_provider": { - "name": "workspace_provider", - "columns": ["workspace_id", "provider"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "provider_workspace_id_id_pk": { - "name": "provider_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "account_id": { - "name": "account_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "color": { - "name": "color", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "role": { - "name": "role", - "type": "enum('admin','member')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "user_account_id": { - "name": "user_account_id", - "columns": ["workspace_id", "account_id"], - "isUnique": true - }, - "user_email": { - "name": "user_email", - "columns": ["workspace_id", "email"], - "isUnique": true - }, - "global_account_id": { - "name": "global_account_id", - "columns": ["account_id"], - "isUnique": false - }, - "global_email": { - "name": "global_email", - "columns": ["email"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "workspace": { - "name": "workspace", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": ["slug"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "workspace_id": { - "name": "workspace_id", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - } - }, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "tables": {}, - "indexes": {} - } -} diff --git a/packages/console/core/migrations/meta/0049_snapshot.json b/packages/console/core/migrations/meta/0049_snapshot.json deleted file mode 100644 index 58679382e5..0000000000 --- a/packages/console/core/migrations/meta/0049_snapshot.json +++ /dev/null @@ -1,1214 +0,0 @@ -{ - "version": "5", - "dialect": "mysql", - "id": "2fd0308b-0653-437d-aea3-29428a4de9f1", - "prevId": "bb90bb3e-fd08-439a-b92f-5f433807480e", - "tables": { - "account": { - "name": "account", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "account_id_pk": { - "name": "account_id_pk", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "auth": { - "name": "auth", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "enum('email','github','google')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "subject": { - "name": "subject", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "account_id": { - "name": "account_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "provider": { - "name": "provider", - "columns": ["provider", "subject"], - "isUnique": true - }, - "account_id": { - "name": "account_id", - "columns": ["account_id"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "auth_id_pk": { - "name": "auth_id_pk", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "benchmark": { - "name": "benchmark", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "agent": { - "name": "agent", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "result": { - "name": "result", - "type": "mediumtext", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "time_created": { - "name": "time_created", - "columns": ["time_created"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "benchmark_id_pk": { - "name": "benchmark_id_pk", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "billing": { - "name": "billing", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_type": { - "name": "payment_method_type", - "type": "varchar(32)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_trigger": { - "name": "reload_trigger", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_amount": { - "name": "reload_amount", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_error": { - "name": "reload_error", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_error": { - "name": "time_reload_error", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_locked_till": { - "name": "time_reload_locked_till", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "subscription_id": { - "name": "subscription_id", - "type": "varchar(28)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "subscription_coupon_id": { - "name": "subscription_coupon_id", - "type": "varchar(28)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_customer_id": { - "name": "global_customer_id", - "columns": ["customer_id"], - "isUnique": true - }, - "global_subscription_id": { - "name": "global_subscription_id", - "columns": ["subscription_id"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "payment": { - "name": "payment", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "invoice_id": { - "name": "invoice_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_refunded": { - "name": "time_refunded", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "subscription": { - "name": "subscription", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "rolling_usage": { - "name": "rolling_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "fixed_usage": { - "name": "fixed_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_rolling_updated": { - "name": "time_rolling_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_fixed_updated": { - "name": "time_fixed_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "workspace_user_id": { - "name": "workspace_user_id", - "columns": ["workspace_id", "user_id"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "subscription_workspace_id_id_pk": { - "name": "subscription_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "usage": { - "name": "usage", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "input_tokens": { - "name": "input_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "output_tokens": { - "name": "output_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_5m_tokens": { - "name": "cache_write_5m_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_1h_tokens": { - "name": "cache_write_1h_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "key_id": { - "name": "key_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "enrichment": { - "name": "enrichment", - "type": "json", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "usage_time_created": { - "name": "usage_time_created", - "columns": ["workspace_id", "time_created"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "ip_rate_limit": { - "name": "ip_rate_limit", - "columns": { - "ip": { - "name": "ip", - "type": "varchar(45)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "interval": { - "name": "interval", - "type": "varchar(10)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "count": { - "name": "count", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "ip_rate_limit_ip_interval_pk": { - "name": "ip_rate_limit_ip_interval_pk", - "columns": ["ip", "interval"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "ip": { - "name": "ip", - "columns": { - "ip": { - "name": "ip", - "type": "varchar(45)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "usage": { - "name": "usage", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "ip_ip_pk": { - "name": "ip_ip_pk", - "columns": ["ip"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "key": { - "name": "key", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "key": { - "name": "key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_used": { - "name": "time_used", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_key": { - "name": "global_key", - "columns": ["key"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "key_workspace_id_id_pk": { - "name": "key_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "model": { - "name": "model", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "model_workspace_model": { - "name": "model_workspace_model", - "columns": ["workspace_id", "model"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "model_workspace_id_id_pk": { - "name": "model_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "provider": { - "name": "provider", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "credentials": { - "name": "credentials", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "workspace_provider": { - "name": "workspace_provider", - "columns": ["workspace_id", "provider"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "provider_workspace_id_id_pk": { - "name": "provider_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "account_id": { - "name": "account_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "color": { - "name": "color", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "role": { - "name": "role", - "type": "enum('admin','member')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "user_account_id": { - "name": "user_account_id", - "columns": ["workspace_id", "account_id"], - "isUnique": true - }, - "user_email": { - "name": "user_email", - "columns": ["workspace_id", "email"], - "isUnique": true - }, - "global_account_id": { - "name": "global_account_id", - "columns": ["account_id"], - "isUnique": false - }, - "global_email": { - "name": "global_email", - "columns": ["email"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "workspace": { - "name": "workspace", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": ["slug"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "workspace_id": { - "name": "workspace_id", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - } - }, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "tables": {}, - "indexes": {} - } -} diff --git a/packages/console/core/migrations/meta/0050_snapshot.json b/packages/console/core/migrations/meta/0050_snapshot.json deleted file mode 100644 index 75289bc262..0000000000 --- a/packages/console/core/migrations/meta/0050_snapshot.json +++ /dev/null @@ -1,1221 +0,0 @@ -{ - "version": "5", - "dialect": "mysql", - "id": "a0d18802-c390-47d4-98f1-d1f83869cf0c", - "prevId": "2fd0308b-0653-437d-aea3-29428a4de9f1", - "tables": { - "account": { - "name": "account", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "account_id_pk": { - "name": "account_id_pk", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "auth": { - "name": "auth", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "enum('email','github','google')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "subject": { - "name": "subject", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "account_id": { - "name": "account_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "provider": { - "name": "provider", - "columns": ["provider", "subject"], - "isUnique": true - }, - "account_id": { - "name": "account_id", - "columns": ["account_id"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "auth_id_pk": { - "name": "auth_id_pk", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "benchmark": { - "name": "benchmark", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "agent": { - "name": "agent", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "result": { - "name": "result", - "type": "mediumtext", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "time_created": { - "name": "time_created", - "columns": ["time_created"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "benchmark_id_pk": { - "name": "benchmark_id_pk", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "billing": { - "name": "billing", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_type": { - "name": "payment_method_type", - "type": "varchar(32)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_trigger": { - "name": "reload_trigger", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_amount": { - "name": "reload_amount", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_error": { - "name": "reload_error", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_error": { - "name": "time_reload_error", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_locked_till": { - "name": "time_reload_locked_till", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "subscription_id": { - "name": "subscription_id", - "type": "varchar(28)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "subscription_coupon_id": { - "name": "subscription_coupon_id", - "type": "varchar(28)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_customer_id": { - "name": "global_customer_id", - "columns": ["customer_id"], - "isUnique": true - }, - "global_subscription_id": { - "name": "global_subscription_id", - "columns": ["subscription_id"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "payment": { - "name": "payment", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "invoice_id": { - "name": "invoice_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_refunded": { - "name": "time_refunded", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "enrichment": { - "name": "enrichment", - "type": "json", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "subscription": { - "name": "subscription", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "rolling_usage": { - "name": "rolling_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "fixed_usage": { - "name": "fixed_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_rolling_updated": { - "name": "time_rolling_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_fixed_updated": { - "name": "time_fixed_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "workspace_user_id": { - "name": "workspace_user_id", - "columns": ["workspace_id", "user_id"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "subscription_workspace_id_id_pk": { - "name": "subscription_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "usage": { - "name": "usage", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "input_tokens": { - "name": "input_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "output_tokens": { - "name": "output_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_5m_tokens": { - "name": "cache_write_5m_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_1h_tokens": { - "name": "cache_write_1h_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "key_id": { - "name": "key_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "enrichment": { - "name": "enrichment", - "type": "json", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "usage_time_created": { - "name": "usage_time_created", - "columns": ["workspace_id", "time_created"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "ip_rate_limit": { - "name": "ip_rate_limit", - "columns": { - "ip": { - "name": "ip", - "type": "varchar(45)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "interval": { - "name": "interval", - "type": "varchar(10)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "count": { - "name": "count", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "ip_rate_limit_ip_interval_pk": { - "name": "ip_rate_limit_ip_interval_pk", - "columns": ["ip", "interval"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "ip": { - "name": "ip", - "columns": { - "ip": { - "name": "ip", - "type": "varchar(45)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "usage": { - "name": "usage", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "ip_ip_pk": { - "name": "ip_ip_pk", - "columns": ["ip"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "key": { - "name": "key", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "key": { - "name": "key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_used": { - "name": "time_used", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_key": { - "name": "global_key", - "columns": ["key"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "key_workspace_id_id_pk": { - "name": "key_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "model": { - "name": "model", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "model_workspace_model": { - "name": "model_workspace_model", - "columns": ["workspace_id", "model"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "model_workspace_id_id_pk": { - "name": "model_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "provider": { - "name": "provider", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "credentials": { - "name": "credentials", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "workspace_provider": { - "name": "workspace_provider", - "columns": ["workspace_id", "provider"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "provider_workspace_id_id_pk": { - "name": "provider_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "account_id": { - "name": "account_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "color": { - "name": "color", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "role": { - "name": "role", - "type": "enum('admin','member')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "user_account_id": { - "name": "user_account_id", - "columns": ["workspace_id", "account_id"], - "isUnique": true - }, - "user_email": { - "name": "user_email", - "columns": ["workspace_id", "email"], - "isUnique": true - }, - "global_account_id": { - "name": "global_account_id", - "columns": ["account_id"], - "isUnique": false - }, - "global_email": { - "name": "global_email", - "columns": ["email"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "workspace": { - "name": "workspace", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": ["slug"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "workspace_id": { - "name": "workspace_id", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - } - }, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "tables": {}, - "indexes": {} - } -} diff --git a/packages/console/core/migrations/meta/0051_snapshot.json b/packages/console/core/migrations/meta/0051_snapshot.json deleted file mode 100644 index 0f90479162..0000000000 --- a/packages/console/core/migrations/meta/0051_snapshot.json +++ /dev/null @@ -1,1228 +0,0 @@ -{ - "version": "5", - "dialect": "mysql", - "id": "14cbf4c8-55f1-4488-956f-56fb5ccb3a5a", - "prevId": "a0d18802-c390-47d4-98f1-d1f83869cf0c", - "tables": { - "account": { - "name": "account", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "account_id_pk": { - "name": "account_id_pk", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "auth": { - "name": "auth", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "enum('email','github','google')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "subject": { - "name": "subject", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "account_id": { - "name": "account_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "provider": { - "name": "provider", - "columns": ["provider", "subject"], - "isUnique": true - }, - "account_id": { - "name": "account_id", - "columns": ["account_id"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "auth_id_pk": { - "name": "auth_id_pk", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "benchmark": { - "name": "benchmark", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "agent": { - "name": "agent", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "result": { - "name": "result", - "type": "mediumtext", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "time_created": { - "name": "time_created", - "columns": ["time_created"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "benchmark_id_pk": { - "name": "benchmark_id_pk", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "billing": { - "name": "billing", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_type": { - "name": "payment_method_type", - "type": "varchar(32)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_trigger": { - "name": "reload_trigger", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_amount": { - "name": "reload_amount", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_error": { - "name": "reload_error", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_error": { - "name": "time_reload_error", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_locked_till": { - "name": "time_reload_locked_till", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "subscription_id": { - "name": "subscription_id", - "type": "varchar(28)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "subscription_coupon_id": { - "name": "subscription_coupon_id", - "type": "varchar(28)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_subscription_booked": { - "name": "time_subscription_booked", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_customer_id": { - "name": "global_customer_id", - "columns": ["customer_id"], - "isUnique": true - }, - "global_subscription_id": { - "name": "global_subscription_id", - "columns": ["subscription_id"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "payment": { - "name": "payment", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "invoice_id": { - "name": "invoice_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_refunded": { - "name": "time_refunded", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "enrichment": { - "name": "enrichment", - "type": "json", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "subscription": { - "name": "subscription", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "rolling_usage": { - "name": "rolling_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "fixed_usage": { - "name": "fixed_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_rolling_updated": { - "name": "time_rolling_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_fixed_updated": { - "name": "time_fixed_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "workspace_user_id": { - "name": "workspace_user_id", - "columns": ["workspace_id", "user_id"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "subscription_workspace_id_id_pk": { - "name": "subscription_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "usage": { - "name": "usage", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "input_tokens": { - "name": "input_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "output_tokens": { - "name": "output_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_5m_tokens": { - "name": "cache_write_5m_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_1h_tokens": { - "name": "cache_write_1h_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "key_id": { - "name": "key_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "enrichment": { - "name": "enrichment", - "type": "json", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "usage_time_created": { - "name": "usage_time_created", - "columns": ["workspace_id", "time_created"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "ip_rate_limit": { - "name": "ip_rate_limit", - "columns": { - "ip": { - "name": "ip", - "type": "varchar(45)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "interval": { - "name": "interval", - "type": "varchar(10)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "count": { - "name": "count", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "ip_rate_limit_ip_interval_pk": { - "name": "ip_rate_limit_ip_interval_pk", - "columns": ["ip", "interval"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "ip": { - "name": "ip", - "columns": { - "ip": { - "name": "ip", - "type": "varchar(45)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "usage": { - "name": "usage", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "ip_ip_pk": { - "name": "ip_ip_pk", - "columns": ["ip"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "key": { - "name": "key", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "key": { - "name": "key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_used": { - "name": "time_used", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_key": { - "name": "global_key", - "columns": ["key"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "key_workspace_id_id_pk": { - "name": "key_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "model": { - "name": "model", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "model_workspace_model": { - "name": "model_workspace_model", - "columns": ["workspace_id", "model"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "model_workspace_id_id_pk": { - "name": "model_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "provider": { - "name": "provider", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "credentials": { - "name": "credentials", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "workspace_provider": { - "name": "workspace_provider", - "columns": ["workspace_id", "provider"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "provider_workspace_id_id_pk": { - "name": "provider_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "account_id": { - "name": "account_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "color": { - "name": "color", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "role": { - "name": "role", - "type": "enum('admin','member')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "user_account_id": { - "name": "user_account_id", - "columns": ["workspace_id", "account_id"], - "isUnique": true - }, - "user_email": { - "name": "user_email", - "columns": ["workspace_id", "email"], - "isUnique": true - }, - "global_account_id": { - "name": "global_account_id", - "columns": ["account_id"], - "isUnique": false - }, - "global_email": { - "name": "global_email", - "columns": ["email"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "workspace": { - "name": "workspace", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": ["slug"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "workspace_id": { - "name": "workspace_id", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - } - }, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "tables": {}, - "indexes": {} - } -} diff --git a/packages/console/core/migrations/meta/0052_snapshot.json b/packages/console/core/migrations/meta/0052_snapshot.json deleted file mode 100644 index 339e153eba..0000000000 --- a/packages/console/core/migrations/meta/0052_snapshot.json +++ /dev/null @@ -1,1235 +0,0 @@ -{ - "version": "5", - "dialect": "mysql", - "id": "00774acd-a1e5-49c0-b296-cacc9506a566", - "prevId": "14cbf4c8-55f1-4488-956f-56fb5ccb3a5a", - "tables": { - "account": { - "name": "account", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "account_id_pk": { - "name": "account_id_pk", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "auth": { - "name": "auth", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "enum('email','github','google')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "subject": { - "name": "subject", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "account_id": { - "name": "account_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "provider": { - "name": "provider", - "columns": ["provider", "subject"], - "isUnique": true - }, - "account_id": { - "name": "account_id", - "columns": ["account_id"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "auth_id_pk": { - "name": "auth_id_pk", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "benchmark": { - "name": "benchmark", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "agent": { - "name": "agent", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "result": { - "name": "result", - "type": "mediumtext", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "time_created": { - "name": "time_created", - "columns": ["time_created"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "benchmark_id_pk": { - "name": "benchmark_id_pk", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "billing": { - "name": "billing", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_type": { - "name": "payment_method_type", - "type": "varchar(32)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_trigger": { - "name": "reload_trigger", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_amount": { - "name": "reload_amount", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_error": { - "name": "reload_error", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_error": { - "name": "time_reload_error", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_locked_till": { - "name": "time_reload_locked_till", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "subscription_id": { - "name": "subscription_id", - "type": "varchar(28)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "subscription_coupon_id": { - "name": "subscription_coupon_id", - "type": "varchar(28)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "subscription_plan": { - "name": "subscription_plan", - "type": "enum('20','100','200')", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_subscription_booked": { - "name": "time_subscription_booked", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_customer_id": { - "name": "global_customer_id", - "columns": ["customer_id"], - "isUnique": true - }, - "global_subscription_id": { - "name": "global_subscription_id", - "columns": ["subscription_id"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "payment": { - "name": "payment", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "invoice_id": { - "name": "invoice_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_refunded": { - "name": "time_refunded", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "enrichment": { - "name": "enrichment", - "type": "json", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "subscription": { - "name": "subscription", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "rolling_usage": { - "name": "rolling_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "fixed_usage": { - "name": "fixed_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_rolling_updated": { - "name": "time_rolling_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_fixed_updated": { - "name": "time_fixed_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "workspace_user_id": { - "name": "workspace_user_id", - "columns": ["workspace_id", "user_id"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "subscription_workspace_id_id_pk": { - "name": "subscription_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "usage": { - "name": "usage", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "input_tokens": { - "name": "input_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "output_tokens": { - "name": "output_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_5m_tokens": { - "name": "cache_write_5m_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_1h_tokens": { - "name": "cache_write_1h_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "key_id": { - "name": "key_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "enrichment": { - "name": "enrichment", - "type": "json", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "usage_time_created": { - "name": "usage_time_created", - "columns": ["workspace_id", "time_created"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "ip_rate_limit": { - "name": "ip_rate_limit", - "columns": { - "ip": { - "name": "ip", - "type": "varchar(45)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "interval": { - "name": "interval", - "type": "varchar(10)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "count": { - "name": "count", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "ip_rate_limit_ip_interval_pk": { - "name": "ip_rate_limit_ip_interval_pk", - "columns": ["ip", "interval"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "ip": { - "name": "ip", - "columns": { - "ip": { - "name": "ip", - "type": "varchar(45)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "usage": { - "name": "usage", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "ip_ip_pk": { - "name": "ip_ip_pk", - "columns": ["ip"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "key": { - "name": "key", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "key": { - "name": "key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_used": { - "name": "time_used", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_key": { - "name": "global_key", - "columns": ["key"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "key_workspace_id_id_pk": { - "name": "key_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "model": { - "name": "model", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "model_workspace_model": { - "name": "model_workspace_model", - "columns": ["workspace_id", "model"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "model_workspace_id_id_pk": { - "name": "model_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "provider": { - "name": "provider", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "credentials": { - "name": "credentials", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "workspace_provider": { - "name": "workspace_provider", - "columns": ["workspace_id", "provider"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "provider_workspace_id_id_pk": { - "name": "provider_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "account_id": { - "name": "account_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "color": { - "name": "color", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "role": { - "name": "role", - "type": "enum('admin','member')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "user_account_id": { - "name": "user_account_id", - "columns": ["workspace_id", "account_id"], - "isUnique": true - }, - "user_email": { - "name": "user_email", - "columns": ["workspace_id", "email"], - "isUnique": true - }, - "global_account_id": { - "name": "global_account_id", - "columns": ["account_id"], - "isUnique": false - }, - "global_email": { - "name": "global_email", - "columns": ["email"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "workspace": { - "name": "workspace", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": ["slug"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "workspace_id": { - "name": "workspace_id", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - } - }, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "tables": {}, - "indexes": {} - } -} diff --git a/packages/console/core/migrations/meta/0053_snapshot.json b/packages/console/core/migrations/meta/0053_snapshot.json deleted file mode 100644 index 75a2cb7c92..0000000000 --- a/packages/console/core/migrations/meta/0053_snapshot.json +++ /dev/null @@ -1,1242 +0,0 @@ -{ - "version": "5", - "dialect": "mysql", - "id": "32a0c40b-a269-4ad1-a5a0-52b1f18932aa", - "prevId": "00774acd-a1e5-49c0-b296-cacc9506a566", - "tables": { - "account": { - "name": "account", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "account_id_pk": { - "name": "account_id_pk", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "auth": { - "name": "auth", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "enum('email','github','google')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "subject": { - "name": "subject", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "account_id": { - "name": "account_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "provider": { - "name": "provider", - "columns": ["provider", "subject"], - "isUnique": true - }, - "account_id": { - "name": "account_id", - "columns": ["account_id"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "auth_id_pk": { - "name": "auth_id_pk", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "benchmark": { - "name": "benchmark", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "agent": { - "name": "agent", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "result": { - "name": "result", - "type": "mediumtext", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "time_created": { - "name": "time_created", - "columns": ["time_created"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "benchmark_id_pk": { - "name": "benchmark_id_pk", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "billing": { - "name": "billing", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_type": { - "name": "payment_method_type", - "type": "varchar(32)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_trigger": { - "name": "reload_trigger", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_amount": { - "name": "reload_amount", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_error": { - "name": "reload_error", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_error": { - "name": "time_reload_error", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_locked_till": { - "name": "time_reload_locked_till", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "subscription": { - "name": "subscription", - "type": "json", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "subscription_id": { - "name": "subscription_id", - "type": "varchar(28)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "subscription_coupon_id": { - "name": "subscription_coupon_id", - "type": "varchar(28)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "subscription_plan": { - "name": "subscription_plan", - "type": "enum('20','100','200')", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_subscription_booked": { - "name": "time_subscription_booked", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_customer_id": { - "name": "global_customer_id", - "columns": ["customer_id"], - "isUnique": true - }, - "global_subscription_id": { - "name": "global_subscription_id", - "columns": ["subscription_id"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "payment": { - "name": "payment", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "invoice_id": { - "name": "invoice_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_refunded": { - "name": "time_refunded", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "enrichment": { - "name": "enrichment", - "type": "json", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "subscription": { - "name": "subscription", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "rolling_usage": { - "name": "rolling_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "fixed_usage": { - "name": "fixed_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_rolling_updated": { - "name": "time_rolling_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_fixed_updated": { - "name": "time_fixed_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "workspace_user_id": { - "name": "workspace_user_id", - "columns": ["workspace_id", "user_id"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "subscription_workspace_id_id_pk": { - "name": "subscription_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "usage": { - "name": "usage", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "input_tokens": { - "name": "input_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "output_tokens": { - "name": "output_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_5m_tokens": { - "name": "cache_write_5m_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_1h_tokens": { - "name": "cache_write_1h_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "key_id": { - "name": "key_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "enrichment": { - "name": "enrichment", - "type": "json", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "usage_time_created": { - "name": "usage_time_created", - "columns": ["workspace_id", "time_created"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "ip_rate_limit": { - "name": "ip_rate_limit", - "columns": { - "ip": { - "name": "ip", - "type": "varchar(45)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "interval": { - "name": "interval", - "type": "varchar(10)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "count": { - "name": "count", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "ip_rate_limit_ip_interval_pk": { - "name": "ip_rate_limit_ip_interval_pk", - "columns": ["ip", "interval"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "ip": { - "name": "ip", - "columns": { - "ip": { - "name": "ip", - "type": "varchar(45)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "usage": { - "name": "usage", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "ip_ip_pk": { - "name": "ip_ip_pk", - "columns": ["ip"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "key": { - "name": "key", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "key": { - "name": "key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_used": { - "name": "time_used", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_key": { - "name": "global_key", - "columns": ["key"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "key_workspace_id_id_pk": { - "name": "key_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "model": { - "name": "model", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "model_workspace_model": { - "name": "model_workspace_model", - "columns": ["workspace_id", "model"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "model_workspace_id_id_pk": { - "name": "model_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "provider": { - "name": "provider", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "credentials": { - "name": "credentials", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "workspace_provider": { - "name": "workspace_provider", - "columns": ["workspace_id", "provider"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "provider_workspace_id_id_pk": { - "name": "provider_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "account_id": { - "name": "account_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "color": { - "name": "color", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "role": { - "name": "role", - "type": "enum('admin','member')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "user_account_id": { - "name": "user_account_id", - "columns": ["workspace_id", "account_id"], - "isUnique": true - }, - "user_email": { - "name": "user_email", - "columns": ["workspace_id", "email"], - "isUnique": true - }, - "global_account_id": { - "name": "global_account_id", - "columns": ["account_id"], - "isUnique": false - }, - "global_email": { - "name": "global_email", - "columns": ["email"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "workspace": { - "name": "workspace", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": ["slug"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "workspace_id": { - "name": "workspace_id", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - } - }, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "tables": {}, - "indexes": {} - } -} diff --git a/packages/console/core/migrations/meta/0054_snapshot.json b/packages/console/core/migrations/meta/0054_snapshot.json deleted file mode 100644 index a1e3851d85..0000000000 --- a/packages/console/core/migrations/meta/0054_snapshot.json +++ /dev/null @@ -1,1235 +0,0 @@ -{ - "version": "5", - "dialect": "mysql", - "id": "a0ade64b-b735-4a70-8d39-ebd84bc9e924", - "prevId": "32a0c40b-a269-4ad1-a5a0-52b1f18932aa", - "tables": { - "account": { - "name": "account", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "account_id_pk": { - "name": "account_id_pk", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "auth": { - "name": "auth", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "enum('email','github','google')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "subject": { - "name": "subject", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "account_id": { - "name": "account_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "provider": { - "name": "provider", - "columns": ["provider", "subject"], - "isUnique": true - }, - "account_id": { - "name": "account_id", - "columns": ["account_id"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "auth_id_pk": { - "name": "auth_id_pk", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "benchmark": { - "name": "benchmark", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "agent": { - "name": "agent", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "result": { - "name": "result", - "type": "mediumtext", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "time_created": { - "name": "time_created", - "columns": ["time_created"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "benchmark_id_pk": { - "name": "benchmark_id_pk", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "billing": { - "name": "billing", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_type": { - "name": "payment_method_type", - "type": "varchar(32)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_trigger": { - "name": "reload_trigger", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_amount": { - "name": "reload_amount", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_error": { - "name": "reload_error", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_error": { - "name": "time_reload_error", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_locked_till": { - "name": "time_reload_locked_till", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "subscription": { - "name": "subscription", - "type": "json", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "subscription_id": { - "name": "subscription_id", - "type": "varchar(28)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "subscription_plan": { - "name": "subscription_plan", - "type": "enum('20','100','200')", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_subscription_booked": { - "name": "time_subscription_booked", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_customer_id": { - "name": "global_customer_id", - "columns": ["customer_id"], - "isUnique": true - }, - "global_subscription_id": { - "name": "global_subscription_id", - "columns": ["subscription_id"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "payment": { - "name": "payment", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "invoice_id": { - "name": "invoice_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_refunded": { - "name": "time_refunded", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "enrichment": { - "name": "enrichment", - "type": "json", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "subscription": { - "name": "subscription", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "rolling_usage": { - "name": "rolling_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "fixed_usage": { - "name": "fixed_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_rolling_updated": { - "name": "time_rolling_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_fixed_updated": { - "name": "time_fixed_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "workspace_user_id": { - "name": "workspace_user_id", - "columns": ["workspace_id", "user_id"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "subscription_workspace_id_id_pk": { - "name": "subscription_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "usage": { - "name": "usage", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "input_tokens": { - "name": "input_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "output_tokens": { - "name": "output_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_5m_tokens": { - "name": "cache_write_5m_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_1h_tokens": { - "name": "cache_write_1h_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "key_id": { - "name": "key_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "enrichment": { - "name": "enrichment", - "type": "json", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "usage_time_created": { - "name": "usage_time_created", - "columns": ["workspace_id", "time_created"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "ip_rate_limit": { - "name": "ip_rate_limit", - "columns": { - "ip": { - "name": "ip", - "type": "varchar(45)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "interval": { - "name": "interval", - "type": "varchar(10)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "count": { - "name": "count", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "ip_rate_limit_ip_interval_pk": { - "name": "ip_rate_limit_ip_interval_pk", - "columns": ["ip", "interval"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "ip": { - "name": "ip", - "columns": { - "ip": { - "name": "ip", - "type": "varchar(45)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "usage": { - "name": "usage", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "ip_ip_pk": { - "name": "ip_ip_pk", - "columns": ["ip"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "key": { - "name": "key", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "key": { - "name": "key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_used": { - "name": "time_used", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_key": { - "name": "global_key", - "columns": ["key"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "key_workspace_id_id_pk": { - "name": "key_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "model": { - "name": "model", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "model_workspace_model": { - "name": "model_workspace_model", - "columns": ["workspace_id", "model"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "model_workspace_id_id_pk": { - "name": "model_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "provider": { - "name": "provider", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "credentials": { - "name": "credentials", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "workspace_provider": { - "name": "workspace_provider", - "columns": ["workspace_id", "provider"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "provider_workspace_id_id_pk": { - "name": "provider_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "account_id": { - "name": "account_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "color": { - "name": "color", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "role": { - "name": "role", - "type": "enum('admin','member')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "user_account_id": { - "name": "user_account_id", - "columns": ["workspace_id", "account_id"], - "isUnique": true - }, - "user_email": { - "name": "user_email", - "columns": ["workspace_id", "email"], - "isUnique": true - }, - "global_account_id": { - "name": "global_account_id", - "columns": ["account_id"], - "isUnique": false - }, - "global_email": { - "name": "global_email", - "columns": ["email"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "workspace": { - "name": "workspace", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": ["slug"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "workspace_id": { - "name": "workspace_id", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - } - }, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "tables": {}, - "indexes": {} - } -} diff --git a/packages/console/core/migrations/meta/0055_snapshot.json b/packages/console/core/migrations/meta/0055_snapshot.json deleted file mode 100644 index 82293d8666..0000000000 --- a/packages/console/core/migrations/meta/0055_snapshot.json +++ /dev/null @@ -1,1242 +0,0 @@ -{ - "version": "5", - "dialect": "mysql", - "id": "e630f63c-04a8-4b59-bf56-03efcdd1b011", - "prevId": "a0ade64b-b735-4a70-8d39-ebd84bc9e924", - "tables": { - "account": { - "name": "account", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "account_id_pk": { - "name": "account_id_pk", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "auth": { - "name": "auth", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "enum('email','github','google')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "subject": { - "name": "subject", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "account_id": { - "name": "account_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "provider": { - "name": "provider", - "columns": ["provider", "subject"], - "isUnique": true - }, - "account_id": { - "name": "account_id", - "columns": ["account_id"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "auth_id_pk": { - "name": "auth_id_pk", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "benchmark": { - "name": "benchmark", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "agent": { - "name": "agent", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "result": { - "name": "result", - "type": "mediumtext", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "time_created": { - "name": "time_created", - "columns": ["time_created"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "benchmark_id_pk": { - "name": "benchmark_id_pk", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "billing": { - "name": "billing", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_id": { - "name": "payment_method_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_type": { - "name": "payment_method_type", - "type": "varchar(32)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_method_last4": { - "name": "payment_method_last4", - "type": "varchar(4)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "balance": { - "name": "balance", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload": { - "name": "reload", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_trigger": { - "name": "reload_trigger", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_amount": { - "name": "reload_amount", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reload_error": { - "name": "reload_error", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_error": { - "name": "time_reload_error", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_reload_locked_till": { - "name": "time_reload_locked_till", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "subscription": { - "name": "subscription", - "type": "json", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "subscription_id": { - "name": "subscription_id", - "type": "varchar(28)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "subscription_plan": { - "name": "subscription_plan", - "type": "enum('20','100','200')", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_subscription_booked": { - "name": "time_subscription_booked", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_subscription_selected": { - "name": "time_subscription_selected", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_customer_id": { - "name": "global_customer_id", - "columns": ["customer_id"], - "isUnique": true - }, - "global_subscription_id": { - "name": "global_subscription_id", - "columns": ["subscription_id"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "billing_workspace_id_id_pk": { - "name": "billing_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "payment": { - "name": "payment", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "customer_id": { - "name": "customer_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "invoice_id": { - "name": "invoice_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payment_id": { - "name": "payment_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "amount": { - "name": "amount", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_refunded": { - "name": "time_refunded", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "enrichment": { - "name": "enrichment", - "type": "json", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "payment_workspace_id_id_pk": { - "name": "payment_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "subscription": { - "name": "subscription", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "rolling_usage": { - "name": "rolling_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "fixed_usage": { - "name": "fixed_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_rolling_updated": { - "name": "time_rolling_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_fixed_updated": { - "name": "time_fixed_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "workspace_user_id": { - "name": "workspace_user_id", - "columns": ["workspace_id", "user_id"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "subscription_workspace_id_id_pk": { - "name": "subscription_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "usage": { - "name": "usage", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "input_tokens": { - "name": "input_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "output_tokens": { - "name": "output_tokens", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reasoning_tokens": { - "name": "reasoning_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_read_tokens": { - "name": "cache_read_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_5m_tokens": { - "name": "cache_write_5m_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cache_write_1h_tokens": { - "name": "cache_write_1h_tokens", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cost": { - "name": "cost", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "key_id": { - "name": "key_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "enrichment": { - "name": "enrichment", - "type": "json", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "usage_time_created": { - "name": "usage_time_created", - "columns": ["workspace_id", "time_created"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "usage_workspace_id_id_pk": { - "name": "usage_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "ip_rate_limit": { - "name": "ip_rate_limit", - "columns": { - "ip": { - "name": "ip", - "type": "varchar(45)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "interval": { - "name": "interval", - "type": "varchar(10)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "count": { - "name": "count", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "ip_rate_limit_ip_interval_pk": { - "name": "ip_rate_limit_ip_interval_pk", - "columns": ["ip", "interval"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "ip": { - "name": "ip", - "columns": { - "ip": { - "name": "ip", - "type": "varchar(45)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "usage": { - "name": "usage", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "ip_ip_pk": { - "name": "ip_ip_pk", - "columns": ["ip"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "key": { - "name": "key", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "key": { - "name": "key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_used": { - "name": "time_used", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "global_key": { - "name": "global_key", - "columns": ["key"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "key_workspace_id_id_pk": { - "name": "key_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "model": { - "name": "model", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "model": { - "name": "model", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "model_workspace_model": { - "name": "model_workspace_model", - "columns": ["workspace_id", "model"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "model_workspace_id_id_pk": { - "name": "model_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "provider": { - "name": "provider", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "varchar(64)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "credentials": { - "name": "credentials", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "workspace_provider": { - "name": "workspace_provider", - "columns": ["workspace_id", "provider"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "provider_workspace_id_id_pk": { - "name": "provider_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "workspace_id": { - "name": "workspace_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "account_id": { - "name": "account_id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_seen": { - "name": "time_seen", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "color": { - "name": "color", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "role": { - "name": "role", - "type": "enum('admin','member')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "monthly_limit": { - "name": "monthly_limit", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "monthly_usage": { - "name": "monthly_usage", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "time_monthly_usage_updated": { - "name": "time_monthly_usage_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "user_account_id": { - "name": "user_account_id", - "columns": ["workspace_id", "account_id"], - "isUnique": true - }, - "user_email": { - "name": "user_email", - "columns": ["workspace_id", "email"], - "isUnique": true - }, - "global_account_id": { - "name": "global_account_id", - "columns": ["account_id"], - "isUnique": false - }, - "global_email": { - "name": "global_email", - "columns": ["email"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_workspace_id_id_pk": { - "name": "user_workspace_id_id_pk", - "columns": ["workspace_id", "id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "workspace": { - "name": "workspace", - "columns": { - "id": { - "name": "id", - "type": "varchar(30)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "time_created": { - "name": "time_created", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "time_updated": { - "name": "time_updated", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" - }, - "time_deleted": { - "name": "time_deleted", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "slug": { - "name": "slug", - "columns": ["slug"], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": { - "workspace_id": { - "name": "workspace_id", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - } - }, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "tables": {}, - "indexes": {} - } -} diff --git a/packages/console/core/migrations/meta/_journal.json b/packages/console/core/migrations/meta/_journal.json deleted file mode 100644 index f807eab668..0000000000 --- a/packages/console/core/migrations/meta/_journal.json +++ /dev/null @@ -1,398 +0,0 @@ -{ - "version": "7", - "dialect": "mysql", - "entries": [ - { - "idx": 0, - "version": "5", - "when": 1756796050935, - "tag": "0000_fluffy_raza", - "breakpoints": true - }, - { - "idx": 1, - "version": "5", - "when": 1756871639102, - "tag": "0001_serious_whistler", - "breakpoints": true - }, - { - "idx": 2, - "version": "5", - "when": 1757597611832, - "tag": "0002_violet_loners", - "breakpoints": true - }, - { - "idx": 3, - "version": "5", - "when": 1757600397194, - "tag": "0003_dusty_clint_barton", - "breakpoints": true - }, - { - "idx": 4, - "version": "5", - "when": 1757627357232, - "tag": "0004_first_mockingbird", - "breakpoints": true - }, - { - "idx": 5, - "version": "5", - "when": 1757632304856, - "tag": "0005_jazzy_skrulls", - "breakpoints": true - }, - { - "idx": 6, - "version": "5", - "when": 1757643108507, - "tag": "0006_parallel_gauntlet", - "breakpoints": true - }, - { - "idx": 7, - "version": "5", - "when": 1757693869142, - "tag": "0007_familiar_nightshade", - "breakpoints": true - }, - { - "idx": 8, - "version": "5", - "when": 1757885904718, - "tag": "0008_eminent_ultimatum", - "breakpoints": true - }, - { - "idx": 9, - "version": "5", - "when": 1757888582598, - "tag": "0009_redundant_piledriver", - "breakpoints": true - }, - { - "idx": 10, - "version": "5", - "when": 1757892305788, - "tag": "0010_needy_sue_storm", - "breakpoints": true - }, - { - "idx": 11, - "version": "5", - "when": 1757948881012, - "tag": "0011_freezing_phil_sheldon", - "breakpoints": true - }, - { - "idx": 12, - "version": "5", - "when": 1757956814524, - "tag": "0012_bright_photon", - "breakpoints": true - }, - { - "idx": 13, - "version": "5", - "when": 1757956978089, - "tag": "0013_absurd_hobgoblin", - "breakpoints": true - }, - { - "idx": 14, - "version": "5", - "when": 1758289919722, - "tag": "0014_demonic_princess_powerful", - "breakpoints": true - }, - { - "idx": 15, - "version": "5", - "when": 1758428484500, - "tag": "0015_cloudy_revanche", - "breakpoints": true - }, - { - "idx": 16, - "version": "5", - "when": 1758663086739, - "tag": "0016_cold_la_nuit", - "breakpoints": true - }, - { - "idx": 17, - "version": "5", - "when": 1758755183232, - "tag": "0017_woozy_thaddeus_ross", - "breakpoints": true - }, - { - "idx": 18, - "version": "5", - "when": 1759077265040, - "tag": "0018_nervous_iron_lad", - "breakpoints": true - }, - { - "idx": 19, - "version": "5", - "when": 1759103696975, - "tag": "0019_dazzling_cable", - "breakpoints": true - }, - { - "idx": 20, - "version": "5", - "when": 1759169697658, - "tag": "0020_supreme_jack_power", - "breakpoints": true - }, - { - "idx": 21, - "version": "5", - "when": 1759186023755, - "tag": "0021_flawless_clea", - "breakpoints": true - }, - { - "idx": 22, - "version": "5", - "when": 1759427432588, - "tag": "0022_nice_dreadnoughts", - "breakpoints": true - }, - { - "idx": 23, - "version": "5", - "when": 1759444220653, - "tag": "0023_optimal_paibok", - "breakpoints": true - }, - { - "idx": 24, - "version": "5", - "when": 1759522925614, - "tag": "0024_early_black_crow", - "breakpoints": true - }, - { - "idx": 25, - "version": "5", - "when": 1759525451885, - "tag": "0025_legal_joseph", - "breakpoints": true - }, - { - "idx": 26, - "version": "5", - "when": 1759546980316, - "tag": "0026_numerous_prodigy", - "breakpoints": true - }, - { - "idx": 27, - "version": "5", - "when": 1759553466608, - "tag": "0027_hot_wong", - "breakpoints": true - }, - { - "idx": 28, - "version": "5", - "when": 1759805025276, - "tag": "0028_careful_cerise", - "breakpoints": true - }, - { - "idx": 29, - "version": "5", - "when": 1759811835558, - "tag": "0029_panoramic_harrier", - "breakpoints": true - }, - { - "idx": 30, - "version": "5", - "when": 1759878278492, - "tag": "0030_ordinary_ultragirl", - "breakpoints": true - }, - { - "idx": 31, - "version": "5", - "when": 1759940238478, - "tag": "0031_outgoing_outlaw_kid", - "breakpoints": true - }, - { - "idx": 32, - "version": "5", - "when": 1759976329502, - "tag": "0032_white_doctor_doom", - "breakpoints": true - }, - { - "idx": 33, - "version": "5", - "when": 1760637384217, - "tag": "0033_cynical_jack_flag", - "breakpoints": true - }, - { - "idx": 34, - "version": "5", - "when": 1760651120251, - "tag": "0034_short_bulldozer", - "breakpoints": true - }, - { - "idx": 35, - "version": "5", - "when": 1760666253896, - "tag": "0035_narrow_blindfold", - "breakpoints": true - }, - { - "idx": 36, - "version": "5", - "when": 1760668952329, - "tag": "0036_slimy_energizer", - "breakpoints": true - }, - { - "idx": 37, - "version": "5", - "when": 1761928273807, - "tag": "0037_messy_jackal", - "breakpoints": true - }, - { - "idx": 38, - "version": "5", - "when": 1764110043942, - "tag": "0038_famous_magik", - "breakpoints": true - }, - { - "idx": 39, - "version": "5", - "when": 1766946179892, - "tag": "0039_striped_forge", - "breakpoints": true - }, - { - "idx": 40, - "version": "5", - "when": 1767584617316, - "tag": "0040_broken_gamora", - "breakpoints": true - }, - { - "idx": 41, - "version": "5", - "when": 1767732559197, - "tag": "0041_odd_misty_knight", - "breakpoints": true - }, - { - "idx": 42, - "version": "5", - "when": 1767744077346, - "tag": "0042_flat_nightmare", - "breakpoints": true - }, - { - "idx": 43, - "version": "5", - "when": 1767752636118, - "tag": "0043_lame_calypso", - "breakpoints": true - }, - { - "idx": 44, - "version": "5", - "when": 1767759322451, - "tag": "0044_tiny_captain_midlands", - "breakpoints": true - }, - { - "idx": 45, - "version": "5", - "when": 1767765497502, - "tag": "0045_cuddly_diamondback", - "breakpoints": true - }, - { - "idx": 46, - "version": "5", - "when": 1767912262458, - "tag": "0046_charming_black_bolt", - "breakpoints": true - }, - { - "idx": 47, - "version": "5", - "when": 1767916965243, - "tag": "0047_huge_omega_red", - "breakpoints": true - }, - { - "idx": 48, - "version": "5", - "when": 1767917785224, - "tag": "0048_mean_frank_castle", - "breakpoints": true - }, - { - "idx": 49, - "version": "5", - "when": 1767922954153, - "tag": "0049_noisy_domino", - "breakpoints": true - }, - { - "idx": 50, - "version": "5", - "when": 1767931290031, - "tag": "0050_bumpy_mephistopheles", - "breakpoints": true - }, - { - "idx": 51, - "version": "5", - "when": 1768341152722, - "tag": "0051_jazzy_green_goblin", - "breakpoints": true - }, - { - "idx": 52, - "version": "5", - "when": 1768343920467, - "tag": "0052_aromatic_agent_zero", - "breakpoints": true - }, - { - "idx": 53, - "version": "5", - "when": 1768599366758, - "tag": "0053_gigantic_hardball", - "breakpoints": true - }, - { - "idx": 54, - "version": "5", - "when": 1768603665356, - "tag": "0054_numerous_annihilus", - "breakpoints": true - }, - { - "idx": 55, - "version": "5", - "when": 1769108945841, - "tag": "0055_moaning_karnak", - "breakpoints": true - } - ] -} diff --git a/packages/console/core/package.json b/packages/console/core/package.json index a99f1ec323..209a0e2df3 100644 --- a/packages/console/core/package.json +++ b/packages/console/core/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/console-core", - "version": "1.2.10", + "version": "1.2.24", "private": true, "type": "module", "license": "MIT", @@ -34,9 +34,9 @@ "promote-models-to-prod": "script/promote-models.ts production", "pull-models-from-dev": "script/pull-models.ts dev", "pull-models-from-prod": "script/pull-models.ts production", - "update-black": "script/update-black.ts", - "promote-black-to-dev": "script/promote-black.ts dev", - "promote-black-to-prod": "script/promote-black.ts production", + "update-limits": "script/update-limits.ts", + "promote-limits-to-dev": "script/promote-limits.ts dev", + "promote-limits-to-prod": "script/promote-limits.ts production", "typecheck": "tsgo --noEmit" }, "devDependencies": { diff --git a/packages/console/core/script/black-select-workspaces.ts b/packages/console/core/script/black-select-workspaces.ts index f22478e1b3..63bfab8875 100644 --- a/packages/console/core/script/black-select-workspaces.ts +++ b/packages/console/core/script/black-select-workspaces.ts @@ -1,10 +1,10 @@ import { Database, eq, and, sql, inArray, isNull, count } from "../src/drizzle/index.js" -import { BillingTable, SubscriptionPlan } from "../src/schema/billing.sql.js" +import { BillingTable, BlackPlans } from "../src/schema/billing.sql.js" import { UserTable } from "../src/schema/user.sql.js" import { AuthTable } from "../src/schema/auth.sql.js" -const plan = process.argv[2] as (typeof SubscriptionPlan)[number] -if (!SubscriptionPlan.includes(plan)) { +const plan = process.argv[2] as (typeof BlackPlans)[number] +if (!BlackPlans.includes(plan)) { console.error("Usage: bun foo.ts ") process.exit(1) } diff --git a/packages/console/core/script/black-stats.ts b/packages/console/core/script/black-stats.ts new file mode 100644 index 0000000000..de7cf5e415 --- /dev/null +++ b/packages/console/core/script/black-stats.ts @@ -0,0 +1,312 @@ +import { Database, and, eq, inArray, isNotNull, sql } from "../src/drizzle/index.js" +import { BillingTable, BlackPlans, SubscriptionTable, UsageTable } from "../src/schema/billing.sql.js" + +if (process.argv.length < 3) { + console.error("Usage: bun black-stats.ts ") + process.exit(1) +} +const plan = process.argv[2] as (typeof BlackPlans)[number] +if (!BlackPlans.includes(plan)) { + console.error("Usage: bun black-stats.ts ") + process.exit(1) +} +const cutoff = new Date(Date.UTC(2026, 1, 0, 23, 59, 59, 999)) + +// get workspaces +const workspaces = await Database.use((tx) => + tx + .select({ workspaceID: BillingTable.workspaceID }) + .from(BillingTable) + .where( + and(isNotNull(BillingTable.subscriptionID), sql`JSON_UNQUOTE(JSON_EXTRACT(subscription, '$.plan')) = ${plan}`), + ), +) +if (workspaces.length === 0) throw new Error(`No active Black ${plan} subscriptions found`) + +const week = sql`YEARWEEK(${UsageTable.timeCreated}, 3)` +const workspaceIDs = workspaces.map((row) => row.workspaceID) +// Get subscription spend +const spend = await Database.use((tx) => + tx + .select({ + workspaceID: UsageTable.workspaceID, + week, + amount: sql`COALESCE(SUM(${UsageTable.cost}), 0)`, + }) + .from(UsageTable) + .where( + and(inArray(UsageTable.workspaceID, workspaceIDs), sql`JSON_UNQUOTE(JSON_EXTRACT(enrichment, '$.plan')) = 'sub'`), + ) + .groupBy(UsageTable.workspaceID, week), +) + +// Get pay per use spend +const ppu = await Database.use((tx) => + tx + .select({ + workspaceID: UsageTable.workspaceID, + week, + amount: sql`COALESCE(SUM(${UsageTable.cost}), 0)`, + }) + .from(UsageTable) + .where( + and( + inArray(UsageTable.workspaceID, workspaceIDs), + sql`(${UsageTable.enrichment} IS NULL OR JSON_UNQUOTE(JSON_EXTRACT(enrichment, '$.plan')) != 'sub')`, + ), + ) + .groupBy(UsageTable.workspaceID, week), +) + +const models = await Database.use((tx) => + tx + .select({ + workspaceID: UsageTable.workspaceID, + model: UsageTable.model, + amount: sql`COALESCE(SUM(${UsageTable.cost}), 0)`, + }) + .from(UsageTable) + .where( + and(inArray(UsageTable.workspaceID, workspaceIDs), sql`JSON_UNQUOTE(JSON_EXTRACT(enrichment, '$.plan')) = 'sub'`), + ) + .groupBy(UsageTable.workspaceID, UsageTable.model), +) + +const tokens = await Database.use((tx) => + tx + .select({ + workspaceID: UsageTable.workspaceID, + week, + input: sql`COALESCE(SUM(${UsageTable.inputTokens}), 0)`, + cacheRead: sql`COALESCE(SUM(${UsageTable.cacheReadTokens}), 0)`, + output: sql`COALESCE(SUM(${UsageTable.outputTokens}), 0) + COALESCE(SUM(${UsageTable.reasoningTokens}), 0)`, + }) + .from(UsageTable) + .where( + and(inArray(UsageTable.workspaceID, workspaceIDs), sql`JSON_UNQUOTE(JSON_EXTRACT(enrichment, '$.plan')) = 'sub'`), + ) + .groupBy(UsageTable.workspaceID, week), +) + +const allWeeks = [...spend, ...ppu].map((row) => row.week) +const weeks = [...new Set(allWeeks)].sort((a, b) => a - b) +const spendMap = new Map>() +const totals = new Map() +const ppuMap = new Map>() +const ppuTotals = new Map() +const modelMap = new Map() +const tokenMap = new Map>() + +for (const row of spend) { + const workspace = spendMap.get(row.workspaceID) ?? new Map() + const total = totals.get(row.workspaceID) ?? 0 + const amount = toNumber(row.amount) + workspace.set(row.week, amount) + totals.set(row.workspaceID, total + amount) + spendMap.set(row.workspaceID, workspace) +} + +for (const row of ppu) { + const workspace = ppuMap.get(row.workspaceID) ?? new Map() + const total = ppuTotals.get(row.workspaceID) ?? 0 + const amount = toNumber(row.amount) + workspace.set(row.week, amount) + ppuTotals.set(row.workspaceID, total + amount) + ppuMap.set(row.workspaceID, workspace) +} + +for (const row of models) { + const current = modelMap.get(row.workspaceID) ?? [] + current.push({ model: row.model, amount: toNumber(row.amount) }) + modelMap.set(row.workspaceID, current) +} + +for (const row of tokens) { + const workspace = tokenMap.get(row.workspaceID) ?? new Map() + workspace.set(row.week, { + input: toNumber(row.input), + cacheRead: toNumber(row.cacheRead), + output: toNumber(row.output), + }) + tokenMap.set(row.workspaceID, workspace) +} + +const users = await Database.use((tx) => + tx + .select({ + workspaceID: SubscriptionTable.workspaceID, + subscribed: SubscriptionTable.timeCreated, + subscription: BillingTable.subscription, + }) + .from(SubscriptionTable) + .innerJoin(BillingTable, eq(SubscriptionTable.workspaceID, BillingTable.workspaceID)) + .where( + and(inArray(SubscriptionTable.workspaceID, workspaceIDs), sql`${SubscriptionTable.timeCreated} <= ${cutoff}`), + ), +) + +const counts = new Map() +for (const user of users) { + const current = counts.get(user.workspaceID) ?? 0 + counts.set(user.workspaceID, current + 1) +} + +const rows = users + .map((user) => { + const workspace = spendMap.get(user.workspaceID) ?? new Map() + const ppuWorkspace = ppuMap.get(user.workspaceID) ?? new Map() + const count = counts.get(user.workspaceID) ?? 1 + const amount = (totals.get(user.workspaceID) ?? 0) / count + const ppuAmount = (ppuTotals.get(user.workspaceID) ?? 0) / count + const monthStart = user.subscribed ? startOfMonth(user.subscribed) : null + const modelRows = (modelMap.get(user.workspaceID) ?? []).sort((a, b) => b.amount - a.amount).slice(0, 3) + const modelTotal = totals.get(user.workspaceID) ?? 0 + const modelCells = modelRows.map((row) => ({ + model: row.model, + percent: modelTotal > 0 ? `${((row.amount / modelTotal) * 100).toFixed(1)}%` : "0.0%", + })) + const modelData = [0, 1, 2].map((index) => modelCells[index] ?? { model: "-", percent: "-" }) + const weekly = Object.fromEntries( + weeks.map((item) => { + const value = (workspace.get(item) ?? 0) / count + const beforeMonth = monthStart ? isoWeekStart(item) < monthStart : false + return [formatWeek(item), beforeMonth ? "-" : formatMicroCents(value)] + }), + ) + const ppuWeekly = Object.fromEntries( + weeks.map((item) => { + const value = (ppuWorkspace.get(item) ?? 0) / count + const beforeMonth = monthStart ? isoWeekStart(item) < monthStart : false + return [formatWeek(item), beforeMonth ? "-" : formatMicroCents(value)] + }), + ) + const tokenWorkspace = tokenMap.get(user.workspaceID) ?? new Map() + const weeklyTokens = Object.fromEntries( + weeks.map((item) => { + const t = tokenWorkspace.get(item) ?? { input: 0, cacheRead: 0, output: 0 } + const beforeMonth = monthStart ? isoWeekStart(item) < monthStart : false + return [ + formatWeek(item), + beforeMonth + ? { input: "-", cacheRead: "-", output: "-" } + : { + input: Math.round(t.input / count), + cacheRead: Math.round(t.cacheRead / count), + output: Math.round(t.output / count), + }, + ] + }), + ) + return { + workspaceID: user.workspaceID, + useBalance: user.subscription?.useBalance ?? false, + subscribed: formatDate(user.subscribed), + subscribedAt: user.subscribed?.getTime() ?? 0, + amount, + ppuAmount, + models: modelData, + weekly, + ppuWeekly, + weeklyTokens, + } + }) + .sort((a, b) => a.subscribedAt - b.subscribedAt) + +console.log(`Black ${plan} subscribers: ${rows.length}`) +const header = [ + "workspaceID", + "subscribed", + "useCredit", + "subTotal", + "ppuTotal", + "model1", + "model1%", + "model2", + "model2%", + "model3", + "model3%", + ...weeks.flatMap((item) => [ + formatWeek(item) + " sub", + formatWeek(item) + " ppu", + formatWeek(item) + " input", + formatWeek(item) + " cache", + formatWeek(item) + " output", + ]), +] +const lines = [header.map(csvCell).join(",")] +for (const row of rows) { + const model1 = row.models[0] + const model2 = row.models[1] + const model3 = row.models[2] + const cells = [ + row.workspaceID, + row.subscribed ?? "", + row.useBalance ? "yes" : "no", + formatMicroCents(row.amount), + formatMicroCents(row.ppuAmount), + model1.model, + model1.percent, + model2.model, + model2.percent, + model3.model, + model3.percent, + ...weeks.flatMap((item) => { + const t = row.weeklyTokens[formatWeek(item)] ?? { input: "-", cacheRead: "-", output: "-" } + return [ + row.weekly[formatWeek(item)] ?? "", + row.ppuWeekly[formatWeek(item)] ?? "", + String(t.input), + String(t.cacheRead), + String(t.output), + ] + }), + ] + lines.push(cells.map(csvCell).join(",")) +} +const output = `${lines.join("\n")}\n` +const file = Bun.file(`black-stats-${plan}.csv`) +await file.write(output) +console.log(`Wrote ${lines.length - 1} rows to ${file.name}`) +const total = rows.reduce((sum, row) => sum + row.amount, 0) +const average = rows.length === 0 ? 0 : total / rows.length +console.log(`Average spending per user: ${formatMicroCents(average)}`) + +function formatMicroCents(value: number) { + return `$${(value / 100000000).toFixed(2)}` +} + +function formatDate(value: Date | null | undefined) { + if (!value) return null + return value.toISOString().split("T")[0] +} + +function formatWeek(value: number) { + return formatDate(isoWeekStart(value)) ?? "" +} + +function startOfMonth(value: Date) { + return new Date(Date.UTC(value.getUTCFullYear(), value.getUTCMonth(), 1)) +} + +function isoWeekStart(value: number) { + const year = Math.floor(value / 100) + const weekNumber = value % 100 + const jan4 = new Date(Date.UTC(year, 0, 4)) + const day = jan4.getUTCDay() || 7 + const weekStart = new Date(Date.UTC(year, 0, 4 - (day - 1))) + weekStart.setUTCDate(weekStart.getUTCDate() + (weekNumber - 1) * 7) + return weekStart +} + +function toNumber(value: unknown) { + if (typeof value === "number") return value + if (typeof value === "bigint") return Number(value) + if (typeof value === "string") return Number(value) + return 0 +} + +function csvCell(value: string | number) { + const text = String(value) + if (!/[",\n]/.test(text)) return text + return `"${text.replace(/"/g, '""')}"` +} diff --git a/packages/console/core/script/lookup-user.ts b/packages/console/core/script/lookup-user.ts index 6367fd89a4..0dfda24116 100644 --- a/packages/console/core/script/lookup-user.ts +++ b/packages/console/core/script/lookup-user.ts @@ -1,13 +1,7 @@ import { Database, and, eq, sql } from "../src/drizzle/index.js" import { AuthTable } from "../src/schema/auth.sql.js" import { UserTable } from "../src/schema/user.sql.js" -import { - BillingTable, - PaymentTable, - SubscriptionTable, - SubscriptionPlan, - UsageTable, -} from "../src/schema/billing.sql.js" +import { BillingTable, PaymentTable, SubscriptionTable, BlackPlans, UsageTable } from "../src/schema/billing.sql.js" import { WorkspaceTable } from "../src/schema/workspace.sql.js" import { BlackData } from "../src/black.js" import { centsToMicroCents } from "../src/util/price.js" @@ -235,7 +229,7 @@ function formatRetryTime(seconds: number) { function getSubscriptionStatus(row: { subscription: { - plan: (typeof SubscriptionPlan)[number] + plan: (typeof BlackPlans)[number] } | null timeSubscriptionCreated: Date | null fixedUsage: number | null diff --git a/packages/console/core/script/promote-black.ts b/packages/console/core/script/promote-limits.ts similarity index 54% rename from packages/console/core/script/promote-black.ts rename to packages/console/core/script/promote-limits.ts index 4338d0e421..f488aba02d 100755 --- a/packages/console/core/script/promote-black.ts +++ b/packages/console/core/script/promote-limits.ts @@ -2,7 +2,7 @@ import { $ } from "bun" import path from "path" -import { BlackData } from "../src/black" +import { Subscription } from "../src/subscription" const stage = process.argv[2] if (!stage) throw new Error("Stage is required") @@ -12,11 +12,11 @@ const root = path.resolve(process.cwd(), "..", "..", "..") // read the secret const ret = await $`bun sst secret list`.cwd(root).text() const lines = ret.split("\n") -const value = lines.find((line) => line.startsWith("ZEN_BLACK_LIMITS"))?.split("=")[1] -if (!value) throw new Error("ZEN_BLACK_LIMITS not found") +const value = lines.find((line) => line.startsWith("ZEN_LIMITS"))?.split("=")[1] +if (!value) throw new Error("ZEN_LIMITS not found") // validate value -BlackData.validate(JSON.parse(value)) +Subscription.validate(JSON.parse(value)) // update the secret -await $`bun sst secret set ZEN_BLACK_LIMITS ${value} --stage ${stage}` +await $`bun sst secret set ZEN_LIMITS ${value} --stage ${stage}` diff --git a/packages/console/core/script/update-black.ts b/packages/console/core/script/update-limits.ts similarity index 65% rename from packages/console/core/script/update-black.ts rename to packages/console/core/script/update-limits.ts index 695a5d3ce4..8f25793126 100755 --- a/packages/console/core/script/update-black.ts +++ b/packages/console/core/script/update-limits.ts @@ -3,18 +3,18 @@ import { $ } from "bun" import path from "path" import os from "os" -import { BlackData } from "../src/black" +import { Subscription } from "../src/subscription" const root = path.resolve(process.cwd(), "..", "..", "..") const secrets = await $`bun sst secret list`.cwd(root).text() // read value const lines = secrets.split("\n") -const oldValue = lines.find((line) => line.startsWith("ZEN_BLACK_LIMITS"))?.split("=")[1] ?? "{}" -if (!oldValue) throw new Error("ZEN_BLACK_LIMITS not found") +const oldValue = lines.find((line) => line.startsWith("ZEN_LIMITS"))?.split("=")[1] ?? "{}" +if (!oldValue) throw new Error("ZEN_LIMITS not found") // store the prettified json to a temp file -const filename = `black-${Date.now()}.json` +const filename = `limits-${Date.now()}.json` const tempFile = Bun.file(path.join(os.tmpdir(), filename)) await tempFile.write(JSON.stringify(JSON.parse(oldValue), null, 2)) console.log("tempFile", tempFile.name) @@ -22,7 +22,7 @@ console.log("tempFile", tempFile.name) // open temp file in vim and read the file on close await $`vim ${tempFile.name}` const newValue = JSON.stringify(JSON.parse(await tempFile.text())) -BlackData.validate(JSON.parse(newValue)) +Subscription.validate(JSON.parse(newValue)) // update the secret -await $`bun sst secret set ZEN_BLACK_LIMITS ${newValue}` +await $`bun sst secret set ZEN_LIMITS ${newValue}` diff --git a/packages/console/core/src/billing.ts b/packages/console/core/src/billing.ts index 2c1cdb0687..fcf238a353 100644 --- a/packages/console/core/src/billing.ts +++ b/packages/console/core/src/billing.ts @@ -1,6 +1,6 @@ import { Stripe } from "stripe" import { Database, eq, sql } from "./drizzle" -import { BillingTable, PaymentTable, SubscriptionTable, UsageTable } from "./schema/billing.sql" +import { BillingTable, LiteTable, PaymentTable, SubscriptionTable, UsageTable } from "./schema/billing.sql" import { Actor } from "./actor" import { fn } from "./util/fn" import { z } from "zod" @@ -9,6 +9,7 @@ import { Identifier } from "./identifier" import { centsToMicroCents } from "./util/price" import { User } from "./user" import { BlackData } from "./black" +import { LiteData } from "./lite" export namespace Billing { export const ITEM_CREDIT_NAME = "opencode credits" @@ -233,6 +234,56 @@ export namespace Billing { }, ) + export const generateLiteCheckoutUrl = fn( + z.object({ + successUrl: z.string(), + cancelUrl: z.string(), + }), + async (input) => { + const user = Actor.assert("user") + const { successUrl, cancelUrl } = input + + const email = await User.getAuthEmail(user.properties.userID) + const billing = await Billing.get() + + if (billing.subscriptionID) throw new Error("Already subscribed to Black") + if (billing.liteSubscriptionID) throw new Error("Already subscribed to Lite") + + const session = await Billing.stripe().checkout.sessions.create({ + mode: "subscription", + billing_address_collection: "required", + line_items: [{ price: LiteData.priceID(), quantity: 1 }], + ...(billing.customerID + ? { + customer: billing.customerID, + customer_update: { + name: "auto", + address: "auto", + }, + } + : { + customer_email: email!, + }), + currency: "usd", + payment_method_types: ["card"], + tax_id_collection: { + enabled: true, + }, + success_url: successUrl, + cancel_url: cancelUrl, + subscription_data: { + metadata: { + workspaceID: Actor.workspace(), + userID: user.properties.userID, + type: "lite", + }, + }, + }) + + return session.url + }, + ) + export const generateSessionUrl = fn( z.object({ returnUrl: z.string(), @@ -271,7 +322,7 @@ export namespace Billing { }, ) - export const subscribe = fn( + export const subscribeBlack = fn( z.object({ seats: z.number(), coupon: z.string().optional(), @@ -336,7 +387,7 @@ export namespace Billing { }, ) - export const unsubscribe = fn( + export const unsubscribeBlack = fn( z.object({ subscriptionID: z.string(), }), @@ -360,4 +411,29 @@ export namespace Billing { }) }, ) + + export const unsubscribeLite = fn( + z.object({ + subscriptionID: z.string(), + }), + async ({ subscriptionID }) => { + const workspaceID = await Database.use((tx) => + tx + .select({ workspaceID: BillingTable.workspaceID }) + .from(BillingTable) + .where(eq(BillingTable.liteSubscriptionID, subscriptionID)) + .then((rows) => rows[0]?.workspaceID), + ) + if (!workspaceID) throw new Error("Workspace ID not found for subscription") + + await Database.transaction(async (tx) => { + await tx + .update(BillingTable) + .set({ liteSubscriptionID: null, lite: null }) + .where(eq(BillingTable.workspaceID, workspaceID)) + + await tx.delete(LiteTable).where(eq(LiteTable.workspaceID, workspaceID)) + }) + }, + ) } diff --git a/packages/console/core/src/black.ts b/packages/console/core/src/black.ts index 5f8db62738..1908403a27 100644 --- a/packages/console/core/src/black.ts +++ b/packages/console/core/src/black.ts @@ -1,46 +1,24 @@ import { z } from "zod" import { fn } from "./util/fn" import { Resource } from "@opencode-ai/console-resource" -import { centsToMicroCents } from "./util/price" -import { getWeekBounds } from "./util/date" -import { SubscriptionPlan } from "./schema/billing.sql" +import { BlackPlans } from "./schema/billing.sql" +import { Subscription } from "./subscription" export namespace BlackData { - const Schema = z.object({ - "200": z.object({ - fixedLimit: z.number().int(), - rollingLimit: z.number().int(), - rollingWindow: z.number().int(), - }), - "100": z.object({ - fixedLimit: z.number().int(), - rollingLimit: z.number().int(), - rollingWindow: z.number().int(), - }), - "20": z.object({ - fixedLimit: z.number().int(), - rollingLimit: z.number().int(), - rollingWindow: z.number().int(), - }), - }) - - export const validate = fn(Schema, (input) => { - return input - }) - export const getLimits = fn( z.object({ - plan: z.enum(SubscriptionPlan), + plan: z.enum(BlackPlans), }), ({ plan }) => { - const json = JSON.parse(Resource.ZEN_BLACK_LIMITS.value) - return Schema.parse(json)[plan] + return Subscription.getLimits()["black"][plan] }, ) + export const productID = fn(z.void(), () => Resource.ZEN_BLACK_PRICE.product) + export const planToPriceID = fn( z.object({ - plan: z.enum(SubscriptionPlan), + plan: z.enum(BlackPlans), }), ({ plan }) => { if (plan === "200") return Resource.ZEN_BLACK_PRICE.plan200 @@ -60,75 +38,3 @@ export namespace BlackData { }, ) } - -export namespace Black { - export const analyzeRollingUsage = fn( - z.object({ - plan: z.enum(SubscriptionPlan), - usage: z.number().int(), - timeUpdated: z.date(), - }), - ({ plan, usage, timeUpdated }) => { - const now = new Date() - const black = BlackData.getLimits({ plan }) - const rollingWindowMs = black.rollingWindow * 3600 * 1000 - const rollingLimitInMicroCents = centsToMicroCents(black.rollingLimit * 100) - const windowStart = new Date(now.getTime() - rollingWindowMs) - if (timeUpdated < windowStart) { - return { - status: "ok" as const, - resetInSec: black.rollingWindow * 3600, - usagePercent: 0, - } - } - - const windowEnd = new Date(timeUpdated.getTime() + rollingWindowMs) - if (usage < rollingLimitInMicroCents) { - return { - status: "ok" as const, - resetInSec: Math.ceil((windowEnd.getTime() - now.getTime()) / 1000), - usagePercent: Math.ceil(Math.min(100, (usage / rollingLimitInMicroCents) * 100)), - } - } - return { - status: "rate-limited" as const, - resetInSec: Math.ceil((windowEnd.getTime() - now.getTime()) / 1000), - usagePercent: 100, - } - }, - ) - - export const analyzeWeeklyUsage = fn( - z.object({ - plan: z.enum(SubscriptionPlan), - usage: z.number().int(), - timeUpdated: z.date(), - }), - ({ plan, usage, timeUpdated }) => { - const black = BlackData.getLimits({ plan }) - const now = new Date() - const week = getWeekBounds(now) - const fixedLimitInMicroCents = centsToMicroCents(black.fixedLimit * 100) - if (timeUpdated < week.start) { - return { - status: "ok" as const, - resetInSec: Math.ceil((week.end.getTime() - now.getTime()) / 1000), - usagePercent: 0, - } - } - if (usage < fixedLimitInMicroCents) { - return { - status: "ok" as const, - resetInSec: Math.ceil((week.end.getTime() - now.getTime()) / 1000), - usagePercent: Math.ceil(Math.min(100, (usage / fixedLimitInMicroCents) * 100)), - } - } - - return { - status: "rate-limited" as const, - resetInSec: Math.ceil((week.end.getTime() - now.getTime()) / 1000), - usagePercent: 100, - } - }, - ) -} diff --git a/packages/console/core/src/identifier.ts b/packages/console/core/src/identifier.ts index b10bf32f6f..8aa324ba07 100644 --- a/packages/console/core/src/identifier.ts +++ b/packages/console/core/src/identifier.ts @@ -8,6 +8,7 @@ export namespace Identifier { benchmark: "ben", billing: "bil", key: "key", + lite: "lit", model: "mod", payment: "pay", provider: "prv", diff --git a/packages/console/core/src/lite.ts b/packages/console/core/src/lite.ts new file mode 100644 index 0000000000..c6f7d5a3e4 --- /dev/null +++ b/packages/console/core/src/lite.ts @@ -0,0 +1,14 @@ +import { z } from "zod" +import { fn } from "./util/fn" +import { Resource } from "@opencode-ai/console-resource" +import { Subscription } from "./subscription" + +export namespace LiteData { + export const getLimits = fn(z.void(), () => { + return Subscription.getLimits()["lite"] + }) + + export const productID = fn(z.void(), () => Resource.ZEN_LITE_PRICE.product) + export const priceID = fn(z.void(), () => Resource.ZEN_LITE_PRICE.price) + export const planName = fn(z.void(), () => "lite") +} diff --git a/packages/console/core/src/model.ts b/packages/console/core/src/model.ts index 6011cac376..e4fa022494 100644 --- a/packages/console/core/src/model.ts +++ b/packages/console/core/src/model.ts @@ -9,24 +9,7 @@ import { Resource } from "@opencode-ai/console-resource" export namespace ZenData { const FormatSchema = z.enum(["anthropic", "google", "openai", "oa-compat"]) - const TrialSchema = z.object({ - provider: z.string(), - limits: z.array( - z.object({ - limit: z.number(), - client: z.enum(["cli", "desktop"]).optional(), - }), - ), - }) - const RateLimitSchema = z.object({ - period: z.enum(["day", "rolling"]), - value: z.number().int(), - checkHeader: z.string().optional(), - fallbackValue: z.number().int().optional(), - }) export type Format = z.infer - export type Trial = z.infer - export type RateLimit = z.infer const ModelCostSchema = z.object({ input: z.number(), @@ -43,8 +26,7 @@ export namespace ZenData { allowAnonymous: z.boolean().optional(), byokProvider: z.enum(["openai", "anthropic", "google"]).optional(), stickyProvider: z.enum(["strict", "prefer"]).optional(), - trial: TrialSchema.optional(), - rateLimit: RateLimitSchema.optional(), + trialProvider: z.string().optional(), fallbackProvider: z.string().optional(), providers: z.array( z.object({ @@ -63,25 +45,19 @@ export namespace ZenData { format: FormatSchema.optional(), headerMappings: z.record(z.string(), z.string()).optional(), payloadModifier: z.record(z.string(), z.any()).optional(), - family: z.string().optional(), - }) - - const ProviderFamilySchema = z.object({ - headers: z.record(z.string(), z.string()).optional(), - responseModifier: z.record(z.string(), z.string()).optional(), }) const ModelsSchema = z.object({ models: z.record(z.string(), z.union([ModelSchema, z.array(ModelSchema.extend({ formatFilter: FormatSchema }))])), + liteModels: z.record(z.string(), ModelSchema), providers: z.record(z.string(), ProviderSchema), - providerFamilies: z.record(z.string(), ProviderFamilySchema), }) export const validate = fn(ModelsSchema, (input) => { return input }) - export const list = fn(z.void(), () => { + export const list = fn(z.enum(["lite", "full"]), (modelList) => { const json = JSON.parse( Resource.ZEN_MODELS1.value + Resource.ZEN_MODELS2.value + @@ -114,15 +90,10 @@ export namespace ZenData { Resource.ZEN_MODELS29.value + Resource.ZEN_MODELS30.value, ) - const { models, providers, providerFamilies } = ModelsSchema.parse(json) + const { models, liteModels, providers } = ModelsSchema.parse(json) return { - models, - providers: Object.fromEntries( - Object.entries(providers).map(([id, provider]) => [ - id, - { ...provider, ...(provider.family ? providerFamilies[provider.family] : {}) }, - ]), - ), + models: modelList === "lite" ? liteModels : models, + providers, } }) } diff --git a/packages/console/core/src/schema/billing.sql.ts b/packages/console/core/src/schema/billing.sql.ts index ba8f892806..a5c70c2115 100644 --- a/packages/console/core/src/schema/billing.sql.ts +++ b/packages/console/core/src/schema/billing.sql.ts @@ -2,7 +2,7 @@ import { bigint, boolean, index, int, json, mysqlEnum, mysqlTable, uniqueIndex, import { timestamps, ulid, utc, workspaceColumns } from "../drizzle/types" import { workspaceIndexes } from "./workspace.sql" -export const SubscriptionPlan = ["20", "100", "200"] as const +export const BlackPlans = ["20", "100", "200"] as const export const BillingTable = mysqlTable( "billing", { @@ -25,14 +25,18 @@ export const BillingTable = mysqlTable( subscription: json("subscription").$type<{ status: "subscribed" seats: number - plan: "20" | "100" | "200" + plan: (typeof BlackPlans)[number] useBalance?: boolean coupon?: string }>(), subscriptionID: varchar("subscription_id", { length: 28 }), - subscriptionPlan: mysqlEnum("subscription_plan", SubscriptionPlan), + subscriptionPlan: mysqlEnum("subscription_plan", BlackPlans), timeSubscriptionBooked: utc("time_subscription_booked"), timeSubscriptionSelected: utc("time_subscription_selected"), + liteSubscriptionID: varchar("lite_subscription_id", { length: 28 }), + lite: json("lite").$type<{ + useBalance?: boolean + }>(), }, (table) => [ ...workspaceIndexes(table), @@ -55,6 +59,22 @@ export const SubscriptionTable = mysqlTable( (table) => [...workspaceIndexes(table), uniqueIndex("workspace_user_id").on(table.workspaceID, table.userID)], ) +export const LiteTable = mysqlTable( + "lite", + { + ...workspaceColumns, + ...timestamps, + userID: ulid("user_id").notNull(), + rollingUsage: bigint("rolling_usage", { mode: "number" }), + weeklyUsage: bigint("weekly_usage", { mode: "number" }), + monthlyUsage: bigint("monthly_usage", { mode: "number" }), + timeRollingUpdated: utc("time_rolling_updated"), + timeWeeklyUpdated: utc("time_weekly_updated"), + timeMonthlyUpdated: utc("time_monthly_updated"), + }, + (table) => [...workspaceIndexes(table), uniqueIndex("workspace_user_id").on(table.workspaceID, table.userID)], +) + export const PaymentTable = mysqlTable( "payment", { @@ -67,7 +87,7 @@ export const PaymentTable = mysqlTable( timeRefunded: utc("time_refunded"), enrichment: json("enrichment").$type< | { - type: "subscription" + type: "subscription" | "lite" couponID?: string } | { @@ -93,8 +113,9 @@ export const UsageTable = mysqlTable( cacheWrite1hTokens: int("cache_write_1h_tokens"), cost: bigint("cost", { mode: "number" }).notNull(), keyID: ulid("key_id"), + sessionID: varchar("session_id", { length: 30 }), enrichment: json("enrichment").$type<{ - plan: "sub" + plan: "sub" | "byok" | "lite" }>(), }, (table) => [...workspaceIndexes(table), index("usage_time_created").on(table.workspaceID, table.timeCreated)], diff --git a/packages/console/core/src/subscription.ts b/packages/console/core/src/subscription.ts new file mode 100644 index 0000000000..9d6c3ce2b5 --- /dev/null +++ b/packages/console/core/src/subscription.ts @@ -0,0 +1,155 @@ +import { z } from "zod" +import { fn } from "./util/fn" +import { centsToMicroCents } from "./util/price" +import { getWeekBounds, getMonthlyBounds } from "./util/date" +import { Resource } from "@opencode-ai/console-resource" + +export namespace Subscription { + const LimitsSchema = z.object({ + free: z.object({ + promoTokens: z.number().int(), + dailyRequests: z.number().int(), + checkHeader: z.string(), + fallbackValue: z.number().int(), + }), + lite: z.object({ + rollingLimit: z.number().int(), + rollingWindow: z.number().int(), + weeklyLimit: z.number().int(), + monthlyLimit: z.number().int(), + }), + black: z.object({ + "20": z.object({ + fixedLimit: z.number().int(), + rollingLimit: z.number().int(), + rollingWindow: z.number().int(), + }), + "100": z.object({ + fixedLimit: z.number().int(), + rollingLimit: z.number().int(), + rollingWindow: z.number().int(), + }), + "200": z.object({ + fixedLimit: z.number().int(), + rollingLimit: z.number().int(), + rollingWindow: z.number().int(), + }), + }), + }) + + export const validate = fn(LimitsSchema, (input) => { + return input + }) + + export const getLimits = fn(z.void(), () => { + const json = JSON.parse(Resource.ZEN_LIMITS.value) + return LimitsSchema.parse(json) + }) + + export const getFreeLimits = fn(z.void(), () => { + return getLimits()["free"] + }) + + export const analyzeRollingUsage = fn( + z.object({ + limit: z.number().int(), + window: z.number().int(), + usage: z.number().int(), + timeUpdated: z.date(), + }), + ({ limit, window, usage, timeUpdated }) => { + const now = new Date() + const rollingWindowMs = window * 3600 * 1000 + const rollingLimitInMicroCents = centsToMicroCents(limit * 100) + const windowStart = new Date(now.getTime() - rollingWindowMs) + if (timeUpdated < windowStart) { + return { + status: "ok" as const, + resetInSec: window * 3600, + usagePercent: 0, + } + } + + const windowEnd = new Date(timeUpdated.getTime() + rollingWindowMs) + if (usage < rollingLimitInMicroCents) { + return { + status: "ok" as const, + resetInSec: Math.ceil((windowEnd.getTime() - now.getTime()) / 1000), + usagePercent: Math.floor(Math.min(100, (usage / rollingLimitInMicroCents) * 100)), + } + } + return { + status: "rate-limited" as const, + resetInSec: Math.ceil((windowEnd.getTime() - now.getTime()) / 1000), + usagePercent: 100, + } + }, + ) + + export const analyzeWeeklyUsage = fn( + z.object({ + limit: z.number().int(), + usage: z.number().int(), + timeUpdated: z.date(), + }), + ({ limit, usage, timeUpdated }) => { + const now = new Date() + const week = getWeekBounds(now) + const fixedLimitInMicroCents = centsToMicroCents(limit * 100) + if (timeUpdated < week.start) { + return { + status: "ok" as const, + resetInSec: Math.ceil((week.end.getTime() - now.getTime()) / 1000), + usagePercent: 0, + } + } + if (usage < fixedLimitInMicroCents) { + return { + status: "ok" as const, + resetInSec: Math.ceil((week.end.getTime() - now.getTime()) / 1000), + usagePercent: Math.floor(Math.min(100, (usage / fixedLimitInMicroCents) * 100)), + } + } + + return { + status: "rate-limited" as const, + resetInSec: Math.ceil((week.end.getTime() - now.getTime()) / 1000), + usagePercent: 100, + } + }, + ) + + export const analyzeMonthlyUsage = fn( + z.object({ + limit: z.number().int(), + usage: z.number().int(), + timeUpdated: z.date(), + timeSubscribed: z.date(), + }), + ({ limit, usage, timeUpdated, timeSubscribed }) => { + const now = new Date() + const month = getMonthlyBounds(now, timeSubscribed) + const fixedLimitInMicroCents = centsToMicroCents(limit * 100) + if (timeUpdated < month.start) { + return { + status: "ok" as const, + resetInSec: Math.ceil((month.end.getTime() - now.getTime()) / 1000), + usagePercent: 0, + } + } + if (usage < fixedLimitInMicroCents) { + return { + status: "ok" as const, + resetInSec: Math.ceil((month.end.getTime() - now.getTime()) / 1000), + usagePercent: Math.floor(Math.min(100, (usage / fixedLimitInMicroCents) * 100)), + } + } + + return { + status: "rate-limited" as const, + resetInSec: Math.ceil((month.end.getTime() - now.getTime()) / 1000), + usagePercent: 100, + } + }, + ) +} diff --git a/packages/console/core/src/util/date.test.ts b/packages/console/core/src/util/date.test.ts deleted file mode 100644 index 074df8a2fa..0000000000 --- a/packages/console/core/src/util/date.test.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { describe, expect, test } from "bun:test" -import { getWeekBounds } from "./date" - -describe("util.date.getWeekBounds", () => { - test("returns a Monday-based week for Sunday dates", () => { - const date = new Date("2026-01-18T12:00:00Z") - const bounds = getWeekBounds(date) - - expect(bounds.start.toISOString()).toBe("2026-01-12T00:00:00.000Z") - expect(bounds.end.toISOString()).toBe("2026-01-19T00:00:00.000Z") - }) - - test("returns a seven day window", () => { - const date = new Date("2026-01-14T12:00:00Z") - const bounds = getWeekBounds(date) - - const span = bounds.end.getTime() - bounds.start.getTime() - expect(span).toBe(7 * 24 * 60 * 60 * 1000) - }) -}) diff --git a/packages/console/core/src/util/date.ts b/packages/console/core/src/util/date.ts index 9c1ab12d2c..dea9c390e0 100644 --- a/packages/console/core/src/util/date.ts +++ b/packages/console/core/src/util/date.ts @@ -7,3 +7,32 @@ export function getWeekBounds(date: Date) { end.setUTCDate(start.getUTCDate() + 7) return { start, end } } + +export function getMonthlyBounds(now: Date, subscribed: Date) { + const day = subscribed.getUTCDate() + const hh = subscribed.getUTCHours() + const mm = subscribed.getUTCMinutes() + const ss = subscribed.getUTCSeconds() + const ms = subscribed.getUTCMilliseconds() + + function anchor(year: number, month: number) { + const max = new Date(Date.UTC(year, month + 1, 0)).getUTCDate() + return new Date(Date.UTC(year, month, Math.min(day, max), hh, mm, ss, ms)) + } + + function shift(year: number, month: number, delta: number) { + const total = year * 12 + month + delta + return [Math.floor(total / 12), ((total % 12) + 12) % 12] as const + } + + let y = now.getUTCFullYear() + let m = now.getUTCMonth() + let start = anchor(y, m) + if (start > now) { + ;[y, m] = shift(y, m, -1) + start = anchor(y, m) + } + const [ny, nm] = shift(y, m, 1) + const end = anchor(ny, nm) + return { start, end } +} diff --git a/packages/console/core/sst-env.d.ts b/packages/console/core/sst-env.d.ts index 73f83d1676..23ae6e44bf 100644 --- a/packages/console/core/sst-env.d.ts +++ b/packages/console/core/sst-env.d.ts @@ -119,10 +119,6 @@ declare module "sst" { "type": "sst.cloudflare.StaticSite" "url": string } - "ZEN_BLACK_LIMITS": { - "type": "sst.sst.Secret" - "value": string - } "ZEN_BLACK_PRICE": { "plan100": string "plan20": string @@ -130,6 +126,15 @@ declare module "sst" { "product": string "type": "sst.sst.Linkable" } + "ZEN_LIMITS": { + "type": "sst.sst.Secret" + "value": string + } + "ZEN_LITE_PRICE": { + "price": string + "product": string + "type": "sst.sst.Linkable" + } "ZEN_MODELS1": { "type": "sst.sst.Secret" "value": string diff --git a/packages/console/core/test/date.test.ts b/packages/console/core/test/date.test.ts new file mode 100644 index 0000000000..e5a0a90e55 --- /dev/null +++ b/packages/console/core/test/date.test.ts @@ -0,0 +1,76 @@ +import { describe, expect, test } from "bun:test" +import { getWeekBounds, getMonthlyBounds } from "../src/util/date" + +describe("util.date.getWeekBounds", () => { + test("returns a Monday-based week for Sunday dates", () => { + const date = new Date("2026-01-18T12:00:00Z") + const bounds = getWeekBounds(date) + + expect(bounds.start.toISOString()).toBe("2026-01-12T00:00:00.000Z") + expect(bounds.end.toISOString()).toBe("2026-01-19T00:00:00.000Z") + }) + + test("returns a seven day window", () => { + const date = new Date("2026-01-14T12:00:00Z") + const bounds = getWeekBounds(date) + + const span = bounds.end.getTime() - bounds.start.getTime() + expect(span).toBe(7 * 24 * 60 * 60 * 1000) + }) +}) + +describe("util.date.getMonthlyBounds", () => { + test("resets on subscription day mid-month", () => { + const now = new Date("2026-03-20T10:00:00Z") + const subscribed = new Date("2026-01-15T08:00:00Z") + const bounds = getMonthlyBounds(now, subscribed) + + expect(bounds.start.toISOString()).toBe("2026-03-15T08:00:00.000Z") + expect(bounds.end.toISOString()).toBe("2026-04-15T08:00:00.000Z") + }) + + test("before subscription day in current month uses previous month anchor", () => { + const now = new Date("2026-03-10T10:00:00Z") + const subscribed = new Date("2026-01-15T08:00:00Z") + const bounds = getMonthlyBounds(now, subscribed) + + expect(bounds.start.toISOString()).toBe("2026-02-15T08:00:00.000Z") + expect(bounds.end.toISOString()).toBe("2026-03-15T08:00:00.000Z") + }) + + test("clamps day for short months", () => { + const now = new Date("2026-03-01T10:00:00Z") + const subscribed = new Date("2026-01-31T12:00:00Z") + const bounds = getMonthlyBounds(now, subscribed) + + expect(bounds.start.toISOString()).toBe("2026-02-28T12:00:00.000Z") + expect(bounds.end.toISOString()).toBe("2026-03-31T12:00:00.000Z") + }) + + test("handles subscription on the 1st", () => { + const now = new Date("2026-04-15T00:00:00Z") + const subscribed = new Date("2026-01-01T00:00:00Z") + const bounds = getMonthlyBounds(now, subscribed) + + expect(bounds.start.toISOString()).toBe("2026-04-01T00:00:00.000Z") + expect(bounds.end.toISOString()).toBe("2026-05-01T00:00:00.000Z") + }) + + test("exactly on the reset boundary uses current period", () => { + const now = new Date("2026-03-15T08:00:00Z") + const subscribed = new Date("2026-01-15T08:00:00Z") + const bounds = getMonthlyBounds(now, subscribed) + + expect(bounds.start.toISOString()).toBe("2026-03-15T08:00:00.000Z") + expect(bounds.end.toISOString()).toBe("2026-04-15T08:00:00.000Z") + }) + + test("february to march with day 30 subscription", () => { + const now = new Date("2026-02-15T06:00:00Z") + const subscribed = new Date("2025-12-30T06:00:00Z") + const bounds = getMonthlyBounds(now, subscribed) + + expect(bounds.start.toISOString()).toBe("2026-01-30T06:00:00.000Z") + expect(bounds.end.toISOString()).toBe("2026-02-28T06:00:00.000Z") + }) +}) diff --git a/packages/console/core/test/subscription.test.ts b/packages/console/core/test/subscription.test.ts new file mode 100644 index 0000000000..57e63f94c4 --- /dev/null +++ b/packages/console/core/test/subscription.test.ts @@ -0,0 +1,106 @@ +import { describe, expect, test, setSystemTime, afterEach } from "bun:test" +import { Subscription } from "../src/subscription" +import { centsToMicroCents } from "../src/util/price" + +afterEach(() => { + setSystemTime() +}) + +describe("Subscription.analyzeMonthlyUsage", () => { + const subscribed = new Date("2026-01-15T08:00:00Z") + + test("returns ok with 0% when usage was last updated before current period", () => { + setSystemTime(new Date("2026-03-20T10:00:00Z")) + const result = Subscription.analyzeMonthlyUsage({ + limit: 10, + usage: centsToMicroCents(500), + timeUpdated: new Date("2026-02-10T00:00:00Z"), + timeSubscribed: subscribed, + }) + + expect(result.status).toBe("ok") + expect(result.usagePercent).toBe(0) + // reset should be seconds until 2026-04-15T08:00:00Z + const expected = Math.ceil( + (new Date("2026-04-15T08:00:00Z").getTime() - new Date("2026-03-20T10:00:00Z").getTime()) / 1000, + ) + expect(result.resetInSec).toBe(expected) + }) + + test("returns ok with usage percent when under limit", () => { + setSystemTime(new Date("2026-03-20T10:00:00Z")) + const limit = 10 // $10 + const half = centsToMicroCents(10 * 100) / 2 + const result = Subscription.analyzeMonthlyUsage({ + limit, + usage: half, + timeUpdated: new Date("2026-03-18T00:00:00Z"), + timeSubscribed: subscribed, + }) + + expect(result.status).toBe("ok") + expect(result.usagePercent).toBe(50) + }) + + test("returns rate-limited when at or over limit", () => { + setSystemTime(new Date("2026-03-20T10:00:00Z")) + const limit = 10 + const result = Subscription.analyzeMonthlyUsage({ + limit, + usage: centsToMicroCents(limit * 100), + timeUpdated: new Date("2026-03-18T00:00:00Z"), + timeSubscribed: subscribed, + }) + + expect(result.status).toBe("rate-limited") + expect(result.usagePercent).toBe(100) + }) + + test("resets usage when crossing monthly boundary", () => { + // subscribed on 15th, now is April 16th — period is Apr 15 to May 15 + // timeUpdated is March 20 (previous period) + setSystemTime(new Date("2026-04-16T10:00:00Z")) + const result = Subscription.analyzeMonthlyUsage({ + limit: 10, + usage: centsToMicroCents(10 * 100), + timeUpdated: new Date("2026-03-20T00:00:00Z"), + timeSubscribed: subscribed, + }) + + expect(result.status).toBe("ok") + expect(result.usagePercent).toBe(0) + }) + + test("caps usage percent at 100", () => { + setSystemTime(new Date("2026-03-20T10:00:00Z")) + const limit = 10 + const result = Subscription.analyzeMonthlyUsage({ + limit, + usage: centsToMicroCents(limit * 100) - 1, + timeUpdated: new Date("2026-03-18T00:00:00Z"), + timeSubscribed: subscribed, + }) + + expect(result.status).toBe("ok") + expect(result.usagePercent).toBeLessThanOrEqual(100) + }) + + test("handles subscription day 31 in short month", () => { + const sub31 = new Date("2026-01-31T12:00:00Z") + // now is March 1 — period should be Feb 28 to Mar 31 + setSystemTime(new Date("2026-03-01T10:00:00Z")) + const result = Subscription.analyzeMonthlyUsage({ + limit: 10, + usage: 0, + timeUpdated: new Date("2026-03-01T09:00:00Z"), + timeSubscribed: sub31, + }) + + expect(result.status).toBe("ok") + expect(result.usagePercent).toBe(0) + const expected = Math.ceil( + (new Date("2026-03-31T12:00:00Z").getTime() - new Date("2026-03-01T10:00:00Z").getTime()) / 1000, + ) + expect(result.resetInSec).toBe(expected) + }) +}) diff --git a/packages/console/function/package.json b/packages/console/function/package.json index 386ee19df2..377ab97cf6 100644 --- a/packages/console/function/package.json +++ b/packages/console/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-function", - "version": "1.2.10", + "version": "1.2.24", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/console/function/src/log-processor.ts b/packages/console/function/src/log-processor.ts index 327fc930b7..f8b2cf5270 100644 --- a/packages/console/function/src/log-processor.ts +++ b/packages/console/function/src/log-processor.ts @@ -13,7 +13,11 @@ export default { url.pathname !== "/zen/v1/chat/completions" && url.pathname !== "/zen/v1/messages" && url.pathname !== "/zen/v1/responses" && - !url.pathname.startsWith("/zen/v1/models/") + !url.pathname.startsWith("/zen/v1/models/") && + url.pathname !== "/zen/go/v1/chat/completions" && + url.pathname !== "/zen/go/v1/messages" && + url.pathname !== "/zen/go/v1/responses" && + !url.pathname.startsWith("/zen/go/v1/models/") ) return diff --git a/packages/console/function/sst-env.d.ts b/packages/console/function/sst-env.d.ts index 73f83d1676..23ae6e44bf 100644 --- a/packages/console/function/sst-env.d.ts +++ b/packages/console/function/sst-env.d.ts @@ -119,10 +119,6 @@ declare module "sst" { "type": "sst.cloudflare.StaticSite" "url": string } - "ZEN_BLACK_LIMITS": { - "type": "sst.sst.Secret" - "value": string - } "ZEN_BLACK_PRICE": { "plan100": string "plan20": string @@ -130,6 +126,15 @@ declare module "sst" { "product": string "type": "sst.sst.Linkable" } + "ZEN_LIMITS": { + "type": "sst.sst.Secret" + "value": string + } + "ZEN_LITE_PRICE": { + "price": string + "product": string + "type": "sst.sst.Linkable" + } "ZEN_MODELS1": { "type": "sst.sst.Secret" "value": string diff --git a/packages/console/mail/package.json b/packages/console/mail/package.json index 7a08244bb6..9a383f19fb 100644 --- a/packages/console/mail/package.json +++ b/packages/console/mail/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-mail", - "version": "1.2.10", + "version": "1.2.24", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", diff --git a/packages/console/resource/sst-env.d.ts b/packages/console/resource/sst-env.d.ts index 73f83d1676..23ae6e44bf 100644 --- a/packages/console/resource/sst-env.d.ts +++ b/packages/console/resource/sst-env.d.ts @@ -119,10 +119,6 @@ declare module "sst" { "type": "sst.cloudflare.StaticSite" "url": string } - "ZEN_BLACK_LIMITS": { - "type": "sst.sst.Secret" - "value": string - } "ZEN_BLACK_PRICE": { "plan100": string "plan20": string @@ -130,6 +126,15 @@ declare module "sst" { "product": string "type": "sst.sst.Linkable" } + "ZEN_LIMITS": { + "type": "sst.sst.Secret" + "value": string + } + "ZEN_LITE_PRICE": { + "price": string + "product": string + "type": "sst.sst.Linkable" + } "ZEN_MODELS1": { "type": "sst.sst.Secret" "value": string diff --git a/packages/desktop-electron/.gitignore b/packages/desktop-electron/.gitignore new file mode 100644 index 0000000000..ac9d8db969 --- /dev/null +++ b/packages/desktop-electron/.gitignore @@ -0,0 +1,28 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? +out/ + +resources/opencode-cli* +resources/icons diff --git a/packages/desktop-electron/AGENTS.md b/packages/desktop-electron/AGENTS.md new file mode 100644 index 0000000000..7805ea835f --- /dev/null +++ b/packages/desktop-electron/AGENTS.md @@ -0,0 +1,4 @@ +# Desktop package notes + +- Renderer process should only call `window.api` from `src/preload`. +- Main process should register IPC handlers in `src/main/ipc.ts`. diff --git a/packages/desktop-electron/README.md b/packages/desktop-electron/README.md new file mode 100644 index 0000000000..ebaf488223 --- /dev/null +++ b/packages/desktop-electron/README.md @@ -0,0 +1,32 @@ +# OpenCode Desktop + +Native OpenCode desktop app, built with Tauri v2. + +## Development + +From the repo root: + +```bash +bun install +bun run --cwd packages/desktop tauri dev +``` + +This starts the Vite dev server on http://localhost:1420 and opens the native window. + +If you only want the web dev server (no native shell): + +```bash +bun run --cwd packages/desktop dev +``` + +## Build + +To create a production `dist/` and build the native app bundle: + +```bash +bun run --cwd packages/desktop tauri build +``` + +## Prerequisites + +Running the desktop app requires additional Tauri dependencies (Rust toolchain, platform-specific libraries). See the [Tauri prerequisites](https://v2.tauri.app/start/prerequisites/) for setup instructions. diff --git a/packages/desktop-electron/electron-builder.config.ts b/packages/desktop-electron/electron-builder.config.ts new file mode 100644 index 0000000000..e6b4bcd2b9 --- /dev/null +++ b/packages/desktop-electron/electron-builder.config.ts @@ -0,0 +1,97 @@ +import type { Configuration } from "electron-builder" + +const channel = (() => { + const raw = process.env.OPENCODE_CHANNEL + if (raw === "dev" || raw === "beta" || raw === "prod") return raw + return "dev" +})() + +const getBase = (): Configuration => ({ + artifactName: "opencode-electron-${os}-${arch}.${ext}", + directories: { + output: "dist", + buildResources: "resources", + }, + files: ["out/**/*", "resources/**/*"], + extraResources: [ + { + from: "resources/", + to: "", + filter: ["opencode-cli*"], + }, + { + from: "native/", + to: "native/", + filter: ["index.js", "index.d.ts", "build/Release/mac_window.node", "swift-build/**"], + }, + ], + mac: { + category: "public.app-category.developer-tools", + icon: `resources/icons/icon.icns`, + hardenedRuntime: true, + gatekeeperAssess: false, + entitlements: "resources/entitlements.plist", + entitlementsInherit: "resources/entitlements.plist", + notarize: true, + target: ["dmg", "zip"], + }, + dmg: { + sign: true, + }, + protocols: { + name: "OpenCode", + schemes: ["opencode"], + }, + win: { + icon: `resources/icons/icon.ico`, + target: ["nsis"], + }, + nsis: { + oneClick: false, + allowToChangeInstallationDirectory: true, + installerIcon: `resources/icons/icon.ico`, + installerHeaderIcon: `resources/icons/icon.ico`, + }, + linux: { + icon: `resources/icons`, + category: "Development", + target: ["AppImage", "deb", "rpm"], + }, +}) + +function getConfig() { + const base = getBase() + + switch (channel) { + case "dev": { + return { + ...base, + appId: "ai.opencode.desktop.dev", + productName: "OpenCode Dev", + rpm: { packageName: "opencode-dev" }, + } + } + case "beta": { + return { + ...base, + appId: "ai.opencode.desktop.beta", + productName: "OpenCode Beta", + protocols: { name: "OpenCode Beta", schemes: ["opencode"] }, + publish: { provider: "github", owner: "anomalyco", repo: "opencode-beta", channel: "latest" }, + rpm: { packageName: "opencode-beta" }, + } + } + case "prod": { + return { + ...base, + appId: "ai.opencode.desktop", + productName: "OpenCode", + protocols: { name: "OpenCode", schemes: ["opencode"] }, + publish: { provider: "github", owner: "anomalyco", repo: "opencode", channel: "latest" }, + rpm: { packageName: "opencode" }, + } + } + } +} + +export default getConfig() diff --git a/packages/desktop-electron/electron.vite.config.ts b/packages/desktop-electron/electron.vite.config.ts new file mode 100644 index 0000000000..80c1d6b704 --- /dev/null +++ b/packages/desktop-electron/electron.vite.config.ts @@ -0,0 +1,41 @@ +import { defineConfig } from "electron-vite" +import appPlugin from "@opencode-ai/app/vite" + +const channel = (() => { + const raw = process.env.OPENCODE_CHANNEL + if (raw === "dev" || raw === "beta" || raw === "prod") return raw + return "dev" +})() + +export default defineConfig({ + main: { + define: { + "import.meta.env.OPENCODE_CHANNEL": JSON.stringify(channel), + }, + build: { + rollupOptions: { + input: { index: "src/main/index.ts" }, + }, + }, + }, + preload: { + build: { + rollupOptions: { + input: { index: "src/preload/index.ts" }, + }, + }, + }, + renderer: { + plugins: [appPlugin], + publicDir: "../app/public", + root: "src/renderer", + build: { + rollupOptions: { + input: { + main: "src/renderer/index.html", + loading: "src/renderer/loading.html", + }, + }, + }, + }, +}) diff --git a/packages/desktop-electron/icons/README.md b/packages/desktop-electron/icons/README.md new file mode 100644 index 0000000000..fa219a77ef --- /dev/null +++ b/packages/desktop-electron/icons/README.md @@ -0,0 +1,11 @@ +# Tauri Icons + +Here's the process I've been using to create icons: + +- Save source image as `app-icon.png` in `packages/desktop` +- `cd` to `packages/desktop` +- Run `bun tauri icon -o src-tauri/icons/{environment}` +- Use [Image2Icon](https://img2icnsapp.com/)'s 'Big Sur Icon' preset to generate an `icon.icns` file and place it in the appropriate icons folder + +The Image2Icon step is necessary as the `icon.icns` generated by `app-icon.png` does not apply the shadow/padding expected by macOS, +so app icons appear larger than expected. diff --git a/packages/desktop-electron/icons/beta/128x128.png b/packages/desktop-electron/icons/beta/128x128.png new file mode 100644 index 0000000000..751e80f1fd Binary files /dev/null and b/packages/desktop-electron/icons/beta/128x128.png differ diff --git a/packages/desktop-electron/icons/beta/128x128@2x.png b/packages/desktop-electron/icons/beta/128x128@2x.png new file mode 100644 index 0000000000..fe330df419 Binary files /dev/null and b/packages/desktop-electron/icons/beta/128x128@2x.png differ diff --git a/packages/desktop-electron/icons/beta/32x32.png b/packages/desktop-electron/icons/beta/32x32.png new file mode 100644 index 0000000000..2703048eed Binary files /dev/null and b/packages/desktop-electron/icons/beta/32x32.png differ diff --git a/packages/desktop-electron/icons/beta/64x64.png b/packages/desktop-electron/icons/beta/64x64.png new file mode 100644 index 0000000000..ecd7fe3142 Binary files /dev/null and b/packages/desktop-electron/icons/beta/64x64.png differ diff --git a/packages/desktop-electron/icons/beta/Square107x107Logo.png b/packages/desktop-electron/icons/beta/Square107x107Logo.png new file mode 100644 index 0000000000..e6ea73f4da Binary files /dev/null and b/packages/desktop-electron/icons/beta/Square107x107Logo.png differ diff --git a/packages/desktop-electron/icons/beta/Square142x142Logo.png b/packages/desktop-electron/icons/beta/Square142x142Logo.png new file mode 100644 index 0000000000..74ae729c42 Binary files /dev/null and b/packages/desktop-electron/icons/beta/Square142x142Logo.png differ diff --git a/packages/desktop-electron/icons/beta/Square150x150Logo.png b/packages/desktop-electron/icons/beta/Square150x150Logo.png new file mode 100644 index 0000000000..0b109b8f4a Binary files /dev/null and b/packages/desktop-electron/icons/beta/Square150x150Logo.png differ diff --git a/packages/desktop-electron/icons/beta/Square284x284Logo.png b/packages/desktop-electron/icons/beta/Square284x284Logo.png new file mode 100644 index 0000000000..0261ded42c Binary files /dev/null and b/packages/desktop-electron/icons/beta/Square284x284Logo.png differ diff --git a/packages/desktop-electron/icons/beta/Square30x30Logo.png b/packages/desktop-electron/icons/beta/Square30x30Logo.png new file mode 100644 index 0000000000..34158f10a4 Binary files /dev/null and b/packages/desktop-electron/icons/beta/Square30x30Logo.png differ diff --git a/packages/desktop-electron/icons/beta/Square310x310Logo.png b/packages/desktop-electron/icons/beta/Square310x310Logo.png new file mode 100644 index 0000000000..f18bfada4c Binary files /dev/null and b/packages/desktop-electron/icons/beta/Square310x310Logo.png differ diff --git a/packages/desktop-electron/icons/beta/Square44x44Logo.png b/packages/desktop-electron/icons/beta/Square44x44Logo.png new file mode 100644 index 0000000000..6d1cc06c08 Binary files /dev/null and b/packages/desktop-electron/icons/beta/Square44x44Logo.png differ diff --git a/packages/desktop-electron/icons/beta/Square71x71Logo.png b/packages/desktop-electron/icons/beta/Square71x71Logo.png new file mode 100644 index 0000000000..a26084dc2f Binary files /dev/null and b/packages/desktop-electron/icons/beta/Square71x71Logo.png differ diff --git a/packages/desktop-electron/icons/beta/Square89x89Logo.png b/packages/desktop-electron/icons/beta/Square89x89Logo.png new file mode 100644 index 0000000000..58b0eb6053 Binary files /dev/null and b/packages/desktop-electron/icons/beta/Square89x89Logo.png differ diff --git a/packages/desktop-electron/icons/beta/StoreLogo.png b/packages/desktop-electron/icons/beta/StoreLogo.png new file mode 100644 index 0000000000..648fd2114d Binary files /dev/null and b/packages/desktop-electron/icons/beta/StoreLogo.png differ diff --git a/packages/desktop-electron/icons/beta/android/mipmap-anydpi-v26/ic_launcher.xml b/packages/desktop-electron/icons/beta/android/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000000..2ffbf24b68 --- /dev/null +++ b/packages/desktop-electron/icons/beta/android/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/packages/desktop-electron/icons/beta/android/mipmap-hdpi/ic_launcher.png b/packages/desktop-electron/icons/beta/android/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000..39d1dd0d51 Binary files /dev/null and b/packages/desktop-electron/icons/beta/android/mipmap-hdpi/ic_launcher.png differ diff --git a/packages/desktop-electron/icons/beta/android/mipmap-hdpi/ic_launcher_foreground.png b/packages/desktop-electron/icons/beta/android/mipmap-hdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000..84908e71c1 Binary files /dev/null and b/packages/desktop-electron/icons/beta/android/mipmap-hdpi/ic_launcher_foreground.png differ diff --git a/packages/desktop-electron/icons/beta/android/mipmap-hdpi/ic_launcher_round.png b/packages/desktop-electron/icons/beta/android/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 0000000000..a6b8cb6162 Binary files /dev/null and b/packages/desktop-electron/icons/beta/android/mipmap-hdpi/ic_launcher_round.png differ diff --git a/packages/desktop-electron/icons/beta/android/mipmap-mdpi/ic_launcher.png b/packages/desktop-electron/icons/beta/android/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000000..6522e0fba8 Binary files /dev/null and b/packages/desktop-electron/icons/beta/android/mipmap-mdpi/ic_launcher.png differ diff --git a/packages/desktop-electron/icons/beta/android/mipmap-mdpi/ic_launcher_foreground.png b/packages/desktop-electron/icons/beta/android/mipmap-mdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000..b3449bd4f3 Binary files /dev/null and b/packages/desktop-electron/icons/beta/android/mipmap-mdpi/ic_launcher_foreground.png differ diff --git a/packages/desktop-electron/icons/beta/android/mipmap-mdpi/ic_launcher_round.png b/packages/desktop-electron/icons/beta/android/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 0000000000..7aa97d8276 Binary files /dev/null and b/packages/desktop-electron/icons/beta/android/mipmap-mdpi/ic_launcher_round.png differ diff --git a/packages/desktop-electron/icons/beta/android/mipmap-xhdpi/ic_launcher.png b/packages/desktop-electron/icons/beta/android/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000000..82bc9d22a6 Binary files /dev/null and b/packages/desktop-electron/icons/beta/android/mipmap-xhdpi/ic_launcher.png differ diff --git a/packages/desktop-electron/icons/beta/android/mipmap-xhdpi/ic_launcher_foreground.png b/packages/desktop-electron/icons/beta/android/mipmap-xhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000..6b031ce851 Binary files /dev/null and b/packages/desktop-electron/icons/beta/android/mipmap-xhdpi/ic_launcher_foreground.png differ diff --git a/packages/desktop-electron/icons/beta/android/mipmap-xhdpi/ic_launcher_round.png b/packages/desktop-electron/icons/beta/android/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 0000000000..34859de5ef Binary files /dev/null and b/packages/desktop-electron/icons/beta/android/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/packages/desktop-electron/icons/beta/android/mipmap-xxhdpi/ic_launcher.png b/packages/desktop-electron/icons/beta/android/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000..4cdb71d62b Binary files /dev/null and b/packages/desktop-electron/icons/beta/android/mipmap-xxhdpi/ic_launcher.png differ diff --git a/packages/desktop-electron/icons/beta/android/mipmap-xxhdpi/ic_launcher_foreground.png b/packages/desktop-electron/icons/beta/android/mipmap-xxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000..a64be6ada1 Binary files /dev/null and b/packages/desktop-electron/icons/beta/android/mipmap-xxhdpi/ic_launcher_foreground.png differ diff --git a/packages/desktop-electron/icons/beta/android/mipmap-xxhdpi/ic_launcher_round.png b/packages/desktop-electron/icons/beta/android/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 0000000000..2de3c27342 Binary files /dev/null and b/packages/desktop-electron/icons/beta/android/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/packages/desktop-electron/icons/beta/android/mipmap-xxxhdpi/ic_launcher.png b/packages/desktop-electron/icons/beta/android/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000000..0ead288664 Binary files /dev/null and b/packages/desktop-electron/icons/beta/android/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/packages/desktop-electron/icons/beta/android/mipmap-xxxhdpi/ic_launcher_foreground.png b/packages/desktop-electron/icons/beta/android/mipmap-xxxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000..bdd1748258 Binary files /dev/null and b/packages/desktop-electron/icons/beta/android/mipmap-xxxhdpi/ic_launcher_foreground.png differ diff --git a/packages/desktop-electron/icons/beta/android/mipmap-xxxhdpi/ic_launcher_round.png b/packages/desktop-electron/icons/beta/android/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 0000000000..69f74758ec Binary files /dev/null and b/packages/desktop-electron/icons/beta/android/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/packages/desktop-electron/icons/beta/android/values/ic_launcher_background.xml b/packages/desktop-electron/icons/beta/android/values/ic_launcher_background.xml new file mode 100644 index 0000000000..ea9c223a6c --- /dev/null +++ b/packages/desktop-electron/icons/beta/android/values/ic_launcher_background.xml @@ -0,0 +1,4 @@ + + + #fff + \ No newline at end of file diff --git a/packages/desktop-electron/icons/beta/icon.icns b/packages/desktop-electron/icons/beta/icon.icns new file mode 100644 index 0000000000..f98de5da88 Binary files /dev/null and b/packages/desktop-electron/icons/beta/icon.icns differ diff --git a/packages/desktop-electron/icons/beta/icon.ico b/packages/desktop-electron/icons/beta/icon.ico new file mode 100644 index 0000000000..df8588c8e4 Binary files /dev/null and b/packages/desktop-electron/icons/beta/icon.ico differ diff --git a/packages/desktop-electron/icons/beta/icon.png b/packages/desktop-electron/icons/beta/icon.png new file mode 100644 index 0000000000..5313049562 Binary files /dev/null and b/packages/desktop-electron/icons/beta/icon.png differ diff --git a/packages/desktop-electron/icons/beta/ios/AppIcon-20x20@1x.png b/packages/desktop-electron/icons/beta/ios/AppIcon-20x20@1x.png new file mode 100644 index 0000000000..e8ebb28efe Binary files /dev/null and b/packages/desktop-electron/icons/beta/ios/AppIcon-20x20@1x.png differ diff --git a/packages/desktop-electron/icons/beta/ios/AppIcon-20x20@2x-1.png b/packages/desktop-electron/icons/beta/ios/AppIcon-20x20@2x-1.png new file mode 100644 index 0000000000..50c8015dea Binary files /dev/null and b/packages/desktop-electron/icons/beta/ios/AppIcon-20x20@2x-1.png differ diff --git a/packages/desktop-electron/icons/beta/ios/AppIcon-20x20@2x.png b/packages/desktop-electron/icons/beta/ios/AppIcon-20x20@2x.png new file mode 100644 index 0000000000..50c8015dea Binary files /dev/null and b/packages/desktop-electron/icons/beta/ios/AppIcon-20x20@2x.png differ diff --git a/packages/desktop-electron/icons/beta/ios/AppIcon-20x20@3x.png b/packages/desktop-electron/icons/beta/ios/AppIcon-20x20@3x.png new file mode 100644 index 0000000000..6e290dbc68 Binary files /dev/null and b/packages/desktop-electron/icons/beta/ios/AppIcon-20x20@3x.png differ diff --git a/packages/desktop-electron/icons/beta/ios/AppIcon-29x29@1x.png b/packages/desktop-electron/icons/beta/ios/AppIcon-29x29@1x.png new file mode 100644 index 0000000000..4ef554b4de Binary files /dev/null and b/packages/desktop-electron/icons/beta/ios/AppIcon-29x29@1x.png differ diff --git a/packages/desktop-electron/icons/beta/ios/AppIcon-29x29@2x-1.png b/packages/desktop-electron/icons/beta/ios/AppIcon-29x29@2x-1.png new file mode 100644 index 0000000000..b9ddfd47c8 Binary files /dev/null and b/packages/desktop-electron/icons/beta/ios/AppIcon-29x29@2x-1.png differ diff --git a/packages/desktop-electron/icons/beta/ios/AppIcon-29x29@2x.png b/packages/desktop-electron/icons/beta/ios/AppIcon-29x29@2x.png new file mode 100644 index 0000000000..b9ddfd47c8 Binary files /dev/null and b/packages/desktop-electron/icons/beta/ios/AppIcon-29x29@2x.png differ diff --git a/packages/desktop-electron/icons/beta/ios/AppIcon-29x29@3x.png b/packages/desktop-electron/icons/beta/ios/AppIcon-29x29@3x.png new file mode 100644 index 0000000000..052322d682 Binary files /dev/null and b/packages/desktop-electron/icons/beta/ios/AppIcon-29x29@3x.png differ diff --git a/packages/desktop-electron/icons/beta/ios/AppIcon-40x40@1x.png b/packages/desktop-electron/icons/beta/ios/AppIcon-40x40@1x.png new file mode 100644 index 0000000000..50c8015dea Binary files /dev/null and b/packages/desktop-electron/icons/beta/ios/AppIcon-40x40@1x.png differ diff --git a/packages/desktop-electron/icons/beta/ios/AppIcon-40x40@2x-1.png b/packages/desktop-electron/icons/beta/ios/AppIcon-40x40@2x-1.png new file mode 100644 index 0000000000..9317b25001 Binary files /dev/null and b/packages/desktop-electron/icons/beta/ios/AppIcon-40x40@2x-1.png differ diff --git a/packages/desktop-electron/icons/beta/ios/AppIcon-40x40@2x.png b/packages/desktop-electron/icons/beta/ios/AppIcon-40x40@2x.png new file mode 100644 index 0000000000..9317b25001 Binary files /dev/null and b/packages/desktop-electron/icons/beta/ios/AppIcon-40x40@2x.png differ diff --git a/packages/desktop-electron/icons/beta/ios/AppIcon-40x40@3x.png b/packages/desktop-electron/icons/beta/ios/AppIcon-40x40@3x.png new file mode 100644 index 0000000000..6b921a17e3 Binary files /dev/null and b/packages/desktop-electron/icons/beta/ios/AppIcon-40x40@3x.png differ diff --git a/packages/desktop-electron/icons/beta/ios/AppIcon-512@2x.png b/packages/desktop-electron/icons/beta/ios/AppIcon-512@2x.png new file mode 100644 index 0000000000..b83131d64b Binary files /dev/null and b/packages/desktop-electron/icons/beta/ios/AppIcon-512@2x.png differ diff --git a/packages/desktop-electron/icons/beta/ios/AppIcon-60x60@2x.png b/packages/desktop-electron/icons/beta/ios/AppIcon-60x60@2x.png new file mode 100644 index 0000000000..6b921a17e3 Binary files /dev/null and b/packages/desktop-electron/icons/beta/ios/AppIcon-60x60@2x.png differ diff --git a/packages/desktop-electron/icons/beta/ios/AppIcon-60x60@3x.png b/packages/desktop-electron/icons/beta/ios/AppIcon-60x60@3x.png new file mode 100644 index 0000000000..685004995c Binary files /dev/null and b/packages/desktop-electron/icons/beta/ios/AppIcon-60x60@3x.png differ diff --git a/packages/desktop-electron/icons/beta/ios/AppIcon-76x76@1x.png b/packages/desktop-electron/icons/beta/ios/AppIcon-76x76@1x.png new file mode 100644 index 0000000000..1ffceb752a Binary files /dev/null and b/packages/desktop-electron/icons/beta/ios/AppIcon-76x76@1x.png differ diff --git a/packages/desktop-electron/icons/beta/ios/AppIcon-76x76@2x.png b/packages/desktop-electron/icons/beta/ios/AppIcon-76x76@2x.png new file mode 100644 index 0000000000..81c4178c91 Binary files /dev/null and b/packages/desktop-electron/icons/beta/ios/AppIcon-76x76@2x.png differ diff --git a/packages/desktop-electron/icons/beta/ios/AppIcon-83.5x83.5@2x.png b/packages/desktop-electron/icons/beta/ios/AppIcon-83.5x83.5@2x.png new file mode 100644 index 0000000000..d5453adffb Binary files /dev/null and b/packages/desktop-electron/icons/beta/ios/AppIcon-83.5x83.5@2x.png differ diff --git a/packages/desktop-electron/icons/dev/128x128.png b/packages/desktop-electron/icons/dev/128x128.png new file mode 100644 index 0000000000..d7fc4db149 Binary files /dev/null and b/packages/desktop-electron/icons/dev/128x128.png differ diff --git a/packages/desktop-electron/icons/dev/128x128@2x.png b/packages/desktop-electron/icons/dev/128x128@2x.png new file mode 100644 index 0000000000..5918823064 Binary files /dev/null and b/packages/desktop-electron/icons/dev/128x128@2x.png differ diff --git a/packages/desktop-electron/icons/dev/32x32.png b/packages/desktop-electron/icons/dev/32x32.png new file mode 100644 index 0000000000..53925cc4f5 Binary files /dev/null and b/packages/desktop-electron/icons/dev/32x32.png differ diff --git a/packages/desktop-electron/icons/dev/64x64.png b/packages/desktop-electron/icons/dev/64x64.png new file mode 100644 index 0000000000..a88ef15c64 Binary files /dev/null and b/packages/desktop-electron/icons/dev/64x64.png differ diff --git a/packages/desktop-electron/icons/dev/Square107x107Logo.png b/packages/desktop-electron/icons/dev/Square107x107Logo.png new file mode 100644 index 0000000000..0de29ec828 Binary files /dev/null and b/packages/desktop-electron/icons/dev/Square107x107Logo.png differ diff --git a/packages/desktop-electron/icons/dev/Square142x142Logo.png b/packages/desktop-electron/icons/dev/Square142x142Logo.png new file mode 100644 index 0000000000..af62e8e1e9 Binary files /dev/null and b/packages/desktop-electron/icons/dev/Square142x142Logo.png differ diff --git a/packages/desktop-electron/icons/dev/Square150x150Logo.png b/packages/desktop-electron/icons/dev/Square150x150Logo.png new file mode 100644 index 0000000000..2b19dc39cc Binary files /dev/null and b/packages/desktop-electron/icons/dev/Square150x150Logo.png differ diff --git a/packages/desktop-electron/icons/dev/Square284x284Logo.png b/packages/desktop-electron/icons/dev/Square284x284Logo.png new file mode 100644 index 0000000000..eda6d9901f Binary files /dev/null and b/packages/desktop-electron/icons/dev/Square284x284Logo.png differ diff --git a/packages/desktop-electron/icons/dev/Square30x30Logo.png b/packages/desktop-electron/icons/dev/Square30x30Logo.png new file mode 100644 index 0000000000..dad821ba84 Binary files /dev/null and b/packages/desktop-electron/icons/dev/Square30x30Logo.png differ diff --git a/packages/desktop-electron/icons/dev/Square310x310Logo.png b/packages/desktop-electron/icons/dev/Square310x310Logo.png new file mode 100644 index 0000000000..555b3b1979 Binary files /dev/null and b/packages/desktop-electron/icons/dev/Square310x310Logo.png differ diff --git a/packages/desktop-electron/icons/dev/Square44x44Logo.png b/packages/desktop-electron/icons/dev/Square44x44Logo.png new file mode 100644 index 0000000000..9f8ad001f7 Binary files /dev/null and b/packages/desktop-electron/icons/dev/Square44x44Logo.png differ diff --git a/packages/desktop-electron/icons/dev/Square71x71Logo.png b/packages/desktop-electron/icons/dev/Square71x71Logo.png new file mode 100644 index 0000000000..43feb78488 Binary files /dev/null and b/packages/desktop-electron/icons/dev/Square71x71Logo.png differ diff --git a/packages/desktop-electron/icons/dev/Square89x89Logo.png b/packages/desktop-electron/icons/dev/Square89x89Logo.png new file mode 100644 index 0000000000..628cc597f0 Binary files /dev/null and b/packages/desktop-electron/icons/dev/Square89x89Logo.png differ diff --git a/packages/desktop-electron/icons/dev/StoreLogo.png b/packages/desktop-electron/icons/dev/StoreLogo.png new file mode 100644 index 0000000000..8d3aa53cff Binary files /dev/null and b/packages/desktop-electron/icons/dev/StoreLogo.png differ diff --git a/packages/desktop-electron/icons/dev/android/mipmap-anydpi-v26/ic_launcher.xml b/packages/desktop-electron/icons/dev/android/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000000..2ffbf24b68 --- /dev/null +++ b/packages/desktop-electron/icons/dev/android/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/packages/desktop-electron/icons/dev/android/mipmap-hdpi/ic_launcher.png b/packages/desktop-electron/icons/dev/android/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000..b355e37fea Binary files /dev/null and b/packages/desktop-electron/icons/dev/android/mipmap-hdpi/ic_launcher.png differ diff --git a/packages/desktop-electron/icons/dev/android/mipmap-hdpi/ic_launcher_foreground.png b/packages/desktop-electron/icons/dev/android/mipmap-hdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000..c33f8713bc Binary files /dev/null and b/packages/desktop-electron/icons/dev/android/mipmap-hdpi/ic_launcher_foreground.png differ diff --git a/packages/desktop-electron/icons/dev/android/mipmap-hdpi/ic_launcher_round.png b/packages/desktop-electron/icons/dev/android/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 0000000000..04e37aa654 Binary files /dev/null and b/packages/desktop-electron/icons/dev/android/mipmap-hdpi/ic_launcher_round.png differ diff --git a/packages/desktop-electron/icons/dev/android/mipmap-mdpi/ic_launcher.png b/packages/desktop-electron/icons/dev/android/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000000..98e53cd220 Binary files /dev/null and b/packages/desktop-electron/icons/dev/android/mipmap-mdpi/ic_launcher.png differ diff --git a/packages/desktop-electron/icons/dev/android/mipmap-mdpi/ic_launcher_foreground.png b/packages/desktop-electron/icons/dev/android/mipmap-mdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000..40fe6e3786 Binary files /dev/null and b/packages/desktop-electron/icons/dev/android/mipmap-mdpi/ic_launcher_foreground.png differ diff --git a/packages/desktop-electron/icons/dev/android/mipmap-mdpi/ic_launcher_round.png b/packages/desktop-electron/icons/dev/android/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 0000000000..4814f1ddf5 Binary files /dev/null and b/packages/desktop-electron/icons/dev/android/mipmap-mdpi/ic_launcher_round.png differ diff --git a/packages/desktop-electron/icons/dev/android/mipmap-xhdpi/ic_launcher.png b/packages/desktop-electron/icons/dev/android/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000000..608493283e Binary files /dev/null and b/packages/desktop-electron/icons/dev/android/mipmap-xhdpi/ic_launcher.png differ diff --git a/packages/desktop-electron/icons/dev/android/mipmap-xhdpi/ic_launcher_foreground.png b/packages/desktop-electron/icons/dev/android/mipmap-xhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000..898066a3fc Binary files /dev/null and b/packages/desktop-electron/icons/dev/android/mipmap-xhdpi/ic_launcher_foreground.png differ diff --git a/packages/desktop-electron/icons/dev/android/mipmap-xhdpi/ic_launcher_round.png b/packages/desktop-electron/icons/dev/android/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 0000000000..64035c0f3c Binary files /dev/null and b/packages/desktop-electron/icons/dev/android/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/packages/desktop-electron/icons/dev/android/mipmap-xxhdpi/ic_launcher.png b/packages/desktop-electron/icons/dev/android/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000..f47691bf42 Binary files /dev/null and b/packages/desktop-electron/icons/dev/android/mipmap-xxhdpi/ic_launcher.png differ diff --git a/packages/desktop-electron/icons/dev/android/mipmap-xxhdpi/ic_launcher_foreground.png b/packages/desktop-electron/icons/dev/android/mipmap-xxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000..dba6f5635b Binary files /dev/null and b/packages/desktop-electron/icons/dev/android/mipmap-xxhdpi/ic_launcher_foreground.png differ diff --git a/packages/desktop-electron/icons/dev/android/mipmap-xxhdpi/ic_launcher_round.png b/packages/desktop-electron/icons/dev/android/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 0000000000..764702604e Binary files /dev/null and b/packages/desktop-electron/icons/dev/android/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/packages/desktop-electron/icons/dev/android/mipmap-xxxhdpi/ic_launcher.png b/packages/desktop-electron/icons/dev/android/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000000..2e8430a604 Binary files /dev/null and b/packages/desktop-electron/icons/dev/android/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/packages/desktop-electron/icons/dev/android/mipmap-xxxhdpi/ic_launcher_foreground.png b/packages/desktop-electron/icons/dev/android/mipmap-xxxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000..db953d128c Binary files /dev/null and b/packages/desktop-electron/icons/dev/android/mipmap-xxxhdpi/ic_launcher_foreground.png differ diff --git a/packages/desktop-electron/icons/dev/android/mipmap-xxxhdpi/ic_launcher_round.png b/packages/desktop-electron/icons/dev/android/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 0000000000..d5c9ba6a8d Binary files /dev/null and b/packages/desktop-electron/icons/dev/android/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/packages/desktop-electron/icons/dev/android/values/ic_launcher_background.xml b/packages/desktop-electron/icons/dev/android/values/ic_launcher_background.xml new file mode 100644 index 0000000000..ea9c223a6c --- /dev/null +++ b/packages/desktop-electron/icons/dev/android/values/ic_launcher_background.xml @@ -0,0 +1,4 @@ + + + #fff + \ No newline at end of file diff --git a/packages/desktop-electron/icons/dev/icon.icns b/packages/desktop-electron/icons/dev/icon.icns new file mode 100644 index 0000000000..d73a94904a Binary files /dev/null and b/packages/desktop-electron/icons/dev/icon.icns differ diff --git a/packages/desktop-electron/icons/dev/icon.ico b/packages/desktop-electron/icons/dev/icon.ico new file mode 100644 index 0000000000..bec385d9aa Binary files /dev/null and b/packages/desktop-electron/icons/dev/icon.ico differ diff --git a/packages/desktop-electron/icons/dev/icon.png b/packages/desktop-electron/icons/dev/icon.png new file mode 100644 index 0000000000..6de37ea294 Binary files /dev/null and b/packages/desktop-electron/icons/dev/icon.png differ diff --git a/packages/desktop-electron/icons/dev/ios/AppIcon-20x20@1x.png b/packages/desktop-electron/icons/dev/ios/AppIcon-20x20@1x.png new file mode 100644 index 0000000000..0e823043e7 Binary files /dev/null and b/packages/desktop-electron/icons/dev/ios/AppIcon-20x20@1x.png differ diff --git a/packages/desktop-electron/icons/dev/ios/AppIcon-20x20@2x-1.png b/packages/desktop-electron/icons/dev/ios/AppIcon-20x20@2x-1.png new file mode 100644 index 0000000000..54e4b2aaca Binary files /dev/null and b/packages/desktop-electron/icons/dev/ios/AppIcon-20x20@2x-1.png differ diff --git a/packages/desktop-electron/icons/dev/ios/AppIcon-20x20@2x.png b/packages/desktop-electron/icons/dev/ios/AppIcon-20x20@2x.png new file mode 100644 index 0000000000..54e4b2aaca Binary files /dev/null and b/packages/desktop-electron/icons/dev/ios/AppIcon-20x20@2x.png differ diff --git a/packages/desktop-electron/icons/dev/ios/AppIcon-20x20@3x.png b/packages/desktop-electron/icons/dev/ios/AppIcon-20x20@3x.png new file mode 100644 index 0000000000..645b01561a Binary files /dev/null and b/packages/desktop-electron/icons/dev/ios/AppIcon-20x20@3x.png differ diff --git a/packages/desktop-electron/icons/dev/ios/AppIcon-29x29@1x.png b/packages/desktop-electron/icons/dev/ios/AppIcon-29x29@1x.png new file mode 100644 index 0000000000..054225c6e9 Binary files /dev/null and b/packages/desktop-electron/icons/dev/ios/AppIcon-29x29@1x.png differ diff --git a/packages/desktop-electron/icons/dev/ios/AppIcon-29x29@2x-1.png b/packages/desktop-electron/icons/dev/ios/AppIcon-29x29@2x-1.png new file mode 100644 index 0000000000..0b1b2e0b7f Binary files /dev/null and b/packages/desktop-electron/icons/dev/ios/AppIcon-29x29@2x-1.png differ diff --git a/packages/desktop-electron/icons/dev/ios/AppIcon-29x29@2x.png b/packages/desktop-electron/icons/dev/ios/AppIcon-29x29@2x.png new file mode 100644 index 0000000000..0b1b2e0b7f Binary files /dev/null and b/packages/desktop-electron/icons/dev/ios/AppIcon-29x29@2x.png differ diff --git a/packages/desktop-electron/icons/dev/ios/AppIcon-29x29@3x.png b/packages/desktop-electron/icons/dev/ios/AppIcon-29x29@3x.png new file mode 100644 index 0000000000..d2c42592b3 Binary files /dev/null and b/packages/desktop-electron/icons/dev/ios/AppIcon-29x29@3x.png differ diff --git a/packages/desktop-electron/icons/dev/ios/AppIcon-40x40@1x.png b/packages/desktop-electron/icons/dev/ios/AppIcon-40x40@1x.png new file mode 100644 index 0000000000..54e4b2aaca Binary files /dev/null and b/packages/desktop-electron/icons/dev/ios/AppIcon-40x40@1x.png differ diff --git a/packages/desktop-electron/icons/dev/ios/AppIcon-40x40@2x-1.png b/packages/desktop-electron/icons/dev/ios/AppIcon-40x40@2x-1.png new file mode 100644 index 0000000000..471ed2eec3 Binary files /dev/null and b/packages/desktop-electron/icons/dev/ios/AppIcon-40x40@2x-1.png differ diff --git a/packages/desktop-electron/icons/dev/ios/AppIcon-40x40@2x.png b/packages/desktop-electron/icons/dev/ios/AppIcon-40x40@2x.png new file mode 100644 index 0000000000..471ed2eec3 Binary files /dev/null and b/packages/desktop-electron/icons/dev/ios/AppIcon-40x40@2x.png differ diff --git a/packages/desktop-electron/icons/dev/ios/AppIcon-40x40@3x.png b/packages/desktop-electron/icons/dev/ios/AppIcon-40x40@3x.png new file mode 100644 index 0000000000..1a490cbf16 Binary files /dev/null and b/packages/desktop-electron/icons/dev/ios/AppIcon-40x40@3x.png differ diff --git a/packages/desktop-electron/icons/dev/ios/AppIcon-512@2x.png b/packages/desktop-electron/icons/dev/ios/AppIcon-512@2x.png new file mode 100644 index 0000000000..f53b404e5f Binary files /dev/null and b/packages/desktop-electron/icons/dev/ios/AppIcon-512@2x.png differ diff --git a/packages/desktop-electron/icons/dev/ios/AppIcon-60x60@2x.png b/packages/desktop-electron/icons/dev/ios/AppIcon-60x60@2x.png new file mode 100644 index 0000000000..1a490cbf16 Binary files /dev/null and b/packages/desktop-electron/icons/dev/ios/AppIcon-60x60@2x.png differ diff --git a/packages/desktop-electron/icons/dev/ios/AppIcon-60x60@3x.png b/packages/desktop-electron/icons/dev/ios/AppIcon-60x60@3x.png new file mode 100644 index 0000000000..bdc759eefe Binary files /dev/null and b/packages/desktop-electron/icons/dev/ios/AppIcon-60x60@3x.png differ diff --git a/packages/desktop-electron/icons/dev/ios/AppIcon-76x76@1x.png b/packages/desktop-electron/icons/dev/ios/AppIcon-76x76@1x.png new file mode 100644 index 0000000000..d22096a2df Binary files /dev/null and b/packages/desktop-electron/icons/dev/ios/AppIcon-76x76@1x.png differ diff --git a/packages/desktop-electron/icons/dev/ios/AppIcon-76x76@2x.png b/packages/desktop-electron/icons/dev/ios/AppIcon-76x76@2x.png new file mode 100644 index 0000000000..d675773d17 Binary files /dev/null and b/packages/desktop-electron/icons/dev/ios/AppIcon-76x76@2x.png differ diff --git a/packages/desktop-electron/icons/dev/ios/AppIcon-83.5x83.5@2x.png b/packages/desktop-electron/icons/dev/ios/AppIcon-83.5x83.5@2x.png new file mode 100644 index 0000000000..31698afce2 Binary files /dev/null and b/packages/desktop-electron/icons/dev/ios/AppIcon-83.5x83.5@2x.png differ diff --git a/packages/desktop-electron/icons/prod/128x128.png b/packages/desktop-electron/icons/prod/128x128.png new file mode 100644 index 0000000000..caf7b02eb3 Binary files /dev/null and b/packages/desktop-electron/icons/prod/128x128.png differ diff --git a/packages/desktop-electron/icons/prod/128x128@2x.png b/packages/desktop-electron/icons/prod/128x128@2x.png new file mode 100644 index 0000000000..47fe4c61ea Binary files /dev/null and b/packages/desktop-electron/icons/prod/128x128@2x.png differ diff --git a/packages/desktop-electron/icons/prod/32x32.png b/packages/desktop-electron/icons/prod/32x32.png new file mode 100644 index 0000000000..5868bcc933 Binary files /dev/null and b/packages/desktop-electron/icons/prod/32x32.png differ diff --git a/packages/desktop-electron/icons/prod/64x64.png b/packages/desktop-electron/icons/prod/64x64.png new file mode 100644 index 0000000000..1ed7425d85 Binary files /dev/null and b/packages/desktop-electron/icons/prod/64x64.png differ diff --git a/packages/desktop-electron/icons/prod/Square107x107Logo.png b/packages/desktop-electron/icons/prod/Square107x107Logo.png new file mode 100644 index 0000000000..1db249bf72 Binary files /dev/null and b/packages/desktop-electron/icons/prod/Square107x107Logo.png differ diff --git a/packages/desktop-electron/icons/prod/Square142x142Logo.png b/packages/desktop-electron/icons/prod/Square142x142Logo.png new file mode 100644 index 0000000000..1961c34081 Binary files /dev/null and b/packages/desktop-electron/icons/prod/Square142x142Logo.png differ diff --git a/packages/desktop-electron/icons/prod/Square150x150Logo.png b/packages/desktop-electron/icons/prod/Square150x150Logo.png new file mode 100644 index 0000000000..abc507347e Binary files /dev/null and b/packages/desktop-electron/icons/prod/Square150x150Logo.png differ diff --git a/packages/desktop-electron/icons/prod/Square284x284Logo.png b/packages/desktop-electron/icons/prod/Square284x284Logo.png new file mode 100644 index 0000000000..51e2a1b9fe Binary files /dev/null and b/packages/desktop-electron/icons/prod/Square284x284Logo.png differ diff --git a/packages/desktop-electron/icons/prod/Square30x30Logo.png b/packages/desktop-electron/icons/prod/Square30x30Logo.png new file mode 100644 index 0000000000..066a1fd0c8 Binary files /dev/null and b/packages/desktop-electron/icons/prod/Square30x30Logo.png differ diff --git a/packages/desktop-electron/icons/prod/Square310x310Logo.png b/packages/desktop-electron/icons/prod/Square310x310Logo.png new file mode 100644 index 0000000000..2a85c8e952 Binary files /dev/null and b/packages/desktop-electron/icons/prod/Square310x310Logo.png differ diff --git a/packages/desktop-electron/icons/prod/Square44x44Logo.png b/packages/desktop-electron/icons/prod/Square44x44Logo.png new file mode 100644 index 0000000000..c855b80632 Binary files /dev/null and b/packages/desktop-electron/icons/prod/Square44x44Logo.png differ diff --git a/packages/desktop-electron/icons/prod/Square71x71Logo.png b/packages/desktop-electron/icons/prod/Square71x71Logo.png new file mode 100644 index 0000000000..c8168f7111 Binary files /dev/null and b/packages/desktop-electron/icons/prod/Square71x71Logo.png differ diff --git a/packages/desktop-electron/icons/prod/Square89x89Logo.png b/packages/desktop-electron/icons/prod/Square89x89Logo.png new file mode 100644 index 0000000000..19ec1777de Binary files /dev/null and b/packages/desktop-electron/icons/prod/Square89x89Logo.png differ diff --git a/packages/desktop-electron/icons/prod/StoreLogo.png b/packages/desktop-electron/icons/prod/StoreLogo.png new file mode 100644 index 0000000000..3fd053d349 Binary files /dev/null and b/packages/desktop-electron/icons/prod/StoreLogo.png differ diff --git a/packages/desktop-electron/icons/prod/android/mipmap-anydpi-v26/ic_launcher.xml b/packages/desktop-electron/icons/prod/android/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000000..2ffbf24b68 --- /dev/null +++ b/packages/desktop-electron/icons/prod/android/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/packages/desktop-electron/icons/prod/android/mipmap-hdpi/ic_launcher.png b/packages/desktop-electron/icons/prod/android/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000..4f3ea0e367 Binary files /dev/null and b/packages/desktop-electron/icons/prod/android/mipmap-hdpi/ic_launcher.png differ diff --git a/packages/desktop-electron/icons/prod/android/mipmap-hdpi/ic_launcher_foreground.png b/packages/desktop-electron/icons/prod/android/mipmap-hdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000..7db80699bc Binary files /dev/null and b/packages/desktop-electron/icons/prod/android/mipmap-hdpi/ic_launcher_foreground.png differ diff --git a/packages/desktop-electron/icons/prod/android/mipmap-hdpi/ic_launcher_round.png b/packages/desktop-electron/icons/prod/android/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 0000000000..a54ebe6528 Binary files /dev/null and b/packages/desktop-electron/icons/prod/android/mipmap-hdpi/ic_launcher_round.png differ diff --git a/packages/desktop-electron/icons/prod/android/mipmap-mdpi/ic_launcher.png b/packages/desktop-electron/icons/prod/android/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000000..9337ccfa3f Binary files /dev/null and b/packages/desktop-electron/icons/prod/android/mipmap-mdpi/ic_launcher.png differ diff --git a/packages/desktop-electron/icons/prod/android/mipmap-mdpi/ic_launcher_foreground.png b/packages/desktop-electron/icons/prod/android/mipmap-mdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000..0bfc1082e6 Binary files /dev/null and b/packages/desktop-electron/icons/prod/android/mipmap-mdpi/ic_launcher_foreground.png differ diff --git a/packages/desktop-electron/icons/prod/android/mipmap-mdpi/ic_launcher_round.png b/packages/desktop-electron/icons/prod/android/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 0000000000..5b02ec732e Binary files /dev/null and b/packages/desktop-electron/icons/prod/android/mipmap-mdpi/ic_launcher_round.png differ diff --git a/packages/desktop-electron/icons/prod/android/mipmap-xhdpi/ic_launcher.png b/packages/desktop-electron/icons/prod/android/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000000..322aeaeaaa Binary files /dev/null and b/packages/desktop-electron/icons/prod/android/mipmap-xhdpi/ic_launcher.png differ diff --git a/packages/desktop-electron/icons/prod/android/mipmap-xhdpi/ic_launcher_foreground.png b/packages/desktop-electron/icons/prod/android/mipmap-xhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000..ca1e336cc3 Binary files /dev/null and b/packages/desktop-electron/icons/prod/android/mipmap-xhdpi/ic_launcher_foreground.png differ diff --git a/packages/desktop-electron/icons/prod/android/mipmap-xhdpi/ic_launcher_round.png b/packages/desktop-electron/icons/prod/android/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 0000000000..f711107992 Binary files /dev/null and b/packages/desktop-electron/icons/prod/android/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/packages/desktop-electron/icons/prod/android/mipmap-xxhdpi/ic_launcher.png b/packages/desktop-electron/icons/prod/android/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000..287a6b500b Binary files /dev/null and b/packages/desktop-electron/icons/prod/android/mipmap-xxhdpi/ic_launcher.png differ diff --git a/packages/desktop-electron/icons/prod/android/mipmap-xxhdpi/ic_launcher_foreground.png b/packages/desktop-electron/icons/prod/android/mipmap-xxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000..9d3d06a867 Binary files /dev/null and b/packages/desktop-electron/icons/prod/android/mipmap-xxhdpi/ic_launcher_foreground.png differ diff --git a/packages/desktop-electron/icons/prod/android/mipmap-xxhdpi/ic_launcher_round.png b/packages/desktop-electron/icons/prod/android/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 0000000000..d4b6fde1b8 Binary files /dev/null and b/packages/desktop-electron/icons/prod/android/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/packages/desktop-electron/icons/prod/android/mipmap-xxxhdpi/ic_launcher.png b/packages/desktop-electron/icons/prod/android/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000000..bde8d75967 Binary files /dev/null and b/packages/desktop-electron/icons/prod/android/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/packages/desktop-electron/icons/prod/android/mipmap-xxxhdpi/ic_launcher_foreground.png b/packages/desktop-electron/icons/prod/android/mipmap-xxxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000..03df7809da Binary files /dev/null and b/packages/desktop-electron/icons/prod/android/mipmap-xxxhdpi/ic_launcher_foreground.png differ diff --git a/packages/desktop-electron/icons/prod/android/mipmap-xxxhdpi/ic_launcher_round.png b/packages/desktop-electron/icons/prod/android/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 0000000000..62363be047 Binary files /dev/null and b/packages/desktop-electron/icons/prod/android/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/packages/desktop-electron/icons/prod/android/values/ic_launcher_background.xml b/packages/desktop-electron/icons/prod/android/values/ic_launcher_background.xml new file mode 100644 index 0000000000..ea9c223a6c --- /dev/null +++ b/packages/desktop-electron/icons/prod/android/values/ic_launcher_background.xml @@ -0,0 +1,4 @@ + + + #fff + \ No newline at end of file diff --git a/packages/desktop-electron/icons/prod/icon.icns b/packages/desktop-electron/icons/prod/icon.icns new file mode 100644 index 0000000000..be910ad5f9 Binary files /dev/null and b/packages/desktop-electron/icons/prod/icon.icns differ diff --git a/packages/desktop-electron/icons/prod/icon.ico b/packages/desktop-electron/icons/prod/icon.ico new file mode 100644 index 0000000000..ff88d21e4c Binary files /dev/null and b/packages/desktop-electron/icons/prod/icon.ico differ diff --git a/packages/desktop-electron/icons/prod/icon.png b/packages/desktop-electron/icons/prod/icon.png new file mode 100644 index 0000000000..0ecbb6d5f8 Binary files /dev/null and b/packages/desktop-electron/icons/prod/icon.png differ diff --git a/packages/desktop-electron/icons/prod/ios/AppIcon-20x20@1x.png b/packages/desktop-electron/icons/prod/ios/AppIcon-20x20@1x.png new file mode 100644 index 0000000000..eb137e164a Binary files /dev/null and b/packages/desktop-electron/icons/prod/ios/AppIcon-20x20@1x.png differ diff --git a/packages/desktop-electron/icons/prod/ios/AppIcon-20x20@2x-1.png b/packages/desktop-electron/icons/prod/ios/AppIcon-20x20@2x-1.png new file mode 100644 index 0000000000..aa76ab10ba Binary files /dev/null and b/packages/desktop-electron/icons/prod/ios/AppIcon-20x20@2x-1.png differ diff --git a/packages/desktop-electron/icons/prod/ios/AppIcon-20x20@2x.png b/packages/desktop-electron/icons/prod/ios/AppIcon-20x20@2x.png new file mode 100644 index 0000000000..aa76ab10ba Binary files /dev/null and b/packages/desktop-electron/icons/prod/ios/AppIcon-20x20@2x.png differ diff --git a/packages/desktop-electron/icons/prod/ios/AppIcon-20x20@3x.png b/packages/desktop-electron/icons/prod/ios/AppIcon-20x20@3x.png new file mode 100644 index 0000000000..c58ea3d49b Binary files /dev/null and b/packages/desktop-electron/icons/prod/ios/AppIcon-20x20@3x.png differ diff --git a/packages/desktop-electron/icons/prod/ios/AppIcon-29x29@1x.png b/packages/desktop-electron/icons/prod/ios/AppIcon-29x29@1x.png new file mode 100644 index 0000000000..0eeb4d9bf9 Binary files /dev/null and b/packages/desktop-electron/icons/prod/ios/AppIcon-29x29@1x.png differ diff --git a/packages/desktop-electron/icons/prod/ios/AppIcon-29x29@2x-1.png b/packages/desktop-electron/icons/prod/ios/AppIcon-29x29@2x-1.png new file mode 100644 index 0000000000..32601c70a1 Binary files /dev/null and b/packages/desktop-electron/icons/prod/ios/AppIcon-29x29@2x-1.png differ diff --git a/packages/desktop-electron/icons/prod/ios/AppIcon-29x29@2x.png b/packages/desktop-electron/icons/prod/ios/AppIcon-29x29@2x.png new file mode 100644 index 0000000000..32601c70a1 Binary files /dev/null and b/packages/desktop-electron/icons/prod/ios/AppIcon-29x29@2x.png differ diff --git a/packages/desktop-electron/icons/prod/ios/AppIcon-29x29@3x.png b/packages/desktop-electron/icons/prod/ios/AppIcon-29x29@3x.png new file mode 100644 index 0000000000..a372c4a111 Binary files /dev/null and b/packages/desktop-electron/icons/prod/ios/AppIcon-29x29@3x.png differ diff --git a/packages/desktop-electron/icons/prod/ios/AppIcon-40x40@1x.png b/packages/desktop-electron/icons/prod/ios/AppIcon-40x40@1x.png new file mode 100644 index 0000000000..aa76ab10ba Binary files /dev/null and b/packages/desktop-electron/icons/prod/ios/AppIcon-40x40@1x.png differ diff --git a/packages/desktop-electron/icons/prod/ios/AppIcon-40x40@2x-1.png b/packages/desktop-electron/icons/prod/ios/AppIcon-40x40@2x-1.png new file mode 100644 index 0000000000..e82ce2765f Binary files /dev/null and b/packages/desktop-electron/icons/prod/ios/AppIcon-40x40@2x-1.png differ diff --git a/packages/desktop-electron/icons/prod/ios/AppIcon-40x40@2x.png b/packages/desktop-electron/icons/prod/ios/AppIcon-40x40@2x.png new file mode 100644 index 0000000000..e82ce2765f Binary files /dev/null and b/packages/desktop-electron/icons/prod/ios/AppIcon-40x40@2x.png differ diff --git a/packages/desktop-electron/icons/prod/ios/AppIcon-40x40@3x.png b/packages/desktop-electron/icons/prod/ios/AppIcon-40x40@3x.png new file mode 100644 index 0000000000..15ad593628 Binary files /dev/null and b/packages/desktop-electron/icons/prod/ios/AppIcon-40x40@3x.png differ diff --git a/packages/desktop-electron/icons/prod/ios/AppIcon-512@2x.png b/packages/desktop-electron/icons/prod/ios/AppIcon-512@2x.png new file mode 100644 index 0000000000..2260671c00 Binary files /dev/null and b/packages/desktop-electron/icons/prod/ios/AppIcon-512@2x.png differ diff --git a/packages/desktop-electron/icons/prod/ios/AppIcon-60x60@2x.png b/packages/desktop-electron/icons/prod/ios/AppIcon-60x60@2x.png new file mode 100644 index 0000000000..15ad593628 Binary files /dev/null and b/packages/desktop-electron/icons/prod/ios/AppIcon-60x60@2x.png differ diff --git a/packages/desktop-electron/icons/prod/ios/AppIcon-60x60@3x.png b/packages/desktop-electron/icons/prod/ios/AppIcon-60x60@3x.png new file mode 100644 index 0000000000..5c66bd3b18 Binary files /dev/null and b/packages/desktop-electron/icons/prod/ios/AppIcon-60x60@3x.png differ diff --git a/packages/desktop-electron/icons/prod/ios/AppIcon-76x76@1x.png b/packages/desktop-electron/icons/prod/ios/AppIcon-76x76@1x.png new file mode 100644 index 0000000000..a5b05f3b50 Binary files /dev/null and b/packages/desktop-electron/icons/prod/ios/AppIcon-76x76@1x.png differ diff --git a/packages/desktop-electron/icons/prod/ios/AppIcon-76x76@2x.png b/packages/desktop-electron/icons/prod/ios/AppIcon-76x76@2x.png new file mode 100644 index 0000000000..9c0615d411 Binary files /dev/null and b/packages/desktop-electron/icons/prod/ios/AppIcon-76x76@2x.png differ diff --git a/packages/desktop-electron/icons/prod/ios/AppIcon-83.5x83.5@2x.png b/packages/desktop-electron/icons/prod/ios/AppIcon-83.5x83.5@2x.png new file mode 100644 index 0000000000..6b792b36ad Binary files /dev/null and b/packages/desktop-electron/icons/prod/ios/AppIcon-83.5x83.5@2x.png differ diff --git a/packages/desktop-electron/package.json b/packages/desktop-electron/package.json new file mode 100644 index 0000000000..45fa7355f8 --- /dev/null +++ b/packages/desktop-electron/package.json @@ -0,0 +1,52 @@ +{ + "name": "@opencode-ai/desktop-electron", + "private": true, + "version": "1.2.24", + "type": "module", + "license": "MIT", + "homepage": "https://opencode.ai", + "author": { + "name": "OpenCode", + "email": "hello@opencode.ai" + }, + "scripts": { + "typecheck": "tsgo -b", + "predev": "bun ./scripts/predev.ts", + "dev": "electron-vite dev", + "prebuild": "bun ./scripts/copy-icons.ts", + "build": "electron-vite build", + "preview": "electron-vite preview", + "package": "electron-builder --config electron-builder.config.ts", + "package:mac": "electron-builder --mac --config electron-builder.config.ts", + "package:win": "electron-builder --win --config electron-builder.config.ts", + "package:linux": "electron-builder --linux --config electron-builder.config.ts", + "native:build": "bun install --cwd native" + }, + "main": "./out/main/index.js", + "dependencies": { + "@opencode-ai/app": "workspace:*", + "@opencode-ai/ui": "workspace:*", + "@solid-primitives/i18n": "2.2.1", + "@solid-primitives/storage": "catalog:", + "@solidjs/meta": "catalog:", + "@solidjs/router": "0.15.4", + "electron-log": "^5", + "electron-store": "^10", + "electron-updater": "^6", + "electron-window-state": "^5.0.3", + "marked": "^15", + "solid-js": "catalog:", + "tree-kill": "^1.2.2" + }, + "devDependencies": { + "@actions/artifact": "4.0.0", + "@types/bun": "catalog:", + "@types/node": "catalog:", + "@typescript/native-preview": "catalog:", + "electron": "40.4.1", + "electron-builder": "^26", + "electron-vite": "^5", + "typescript": "~5.6.2", + "vite": "catalog:" + } +} diff --git a/packages/desktop-electron/resources/entitlements.plist b/packages/desktop-electron/resources/entitlements.plist new file mode 100644 index 0000000000..b61dc02228 --- /dev/null +++ b/packages/desktop-electron/resources/entitlements.plist @@ -0,0 +1,18 @@ + + + + + com.apple.security.cs.allow-jit + + com.apple.security.cs.allow-unsigned-executable-memory + + com.apple.security.cs.disable-executable-page-protection + + com.apple.security.cs.allow-dyld-environment-variables + + com.apple.security.cs.disable-library-validation + + com.apple.security.device.audio-input + + + diff --git a/packages/desktop-electron/scripts/copy-bundles.ts b/packages/desktop-electron/scripts/copy-bundles.ts new file mode 100644 index 0000000000..6ef3335eb7 --- /dev/null +++ b/packages/desktop-electron/scripts/copy-bundles.ts @@ -0,0 +1,12 @@ +import { $ } from "bun" +import * as path from "node:path" + +import { RUST_TARGET } from "./utils" + +if (!RUST_TARGET) throw new Error("RUST_TARGET not defined") + +const BUNDLE_DIR = "dist" +const BUNDLES_OUT_DIR = path.join(process.cwd(), "dist/bundles") + +await $`mkdir -p ${BUNDLES_OUT_DIR}` +await $`cp -r ${BUNDLE_DIR}/* ${BUNDLES_OUT_DIR}` diff --git a/packages/desktop-electron/scripts/copy-icons.ts b/packages/desktop-electron/scripts/copy-icons.ts new file mode 100644 index 0000000000..400f427571 --- /dev/null +++ b/packages/desktop-electron/scripts/copy-icons.ts @@ -0,0 +1,12 @@ +import { $ } from "bun" +import { resolveChannel } from "./utils" + +const arg = process.argv[2] +const channel = arg === "dev" || arg === "beta" || arg === "prod" ? arg : resolveChannel() + +const src = `./icons/${channel}` +const dest = "resources/icons" + +await $`rm -rf ${dest}` +await $`cp -R ${src} ${dest}` +console.log(`Copied ${channel} icons from ${src} to ${dest}`) diff --git a/packages/desktop-electron/scripts/finalize-latest-yml.ts b/packages/desktop-electron/scripts/finalize-latest-yml.ts new file mode 100644 index 0000000000..42ec23b642 --- /dev/null +++ b/packages/desktop-electron/scripts/finalize-latest-yml.ts @@ -0,0 +1,116 @@ +#!/usr/bin/env bun + +import { $ } from "bun" +import path from "path" + +const dir = process.env.LATEST_YML_DIR! +if (!dir) throw new Error("LATEST_YML_DIR is required") + +const repo = process.env.GH_REPO +if (!repo) throw new Error("GH_REPO is required") + +const version = process.env.OPENCODE_VERSION +if (!version) throw new Error("OPENCODE_VERSION is required") + +type FileEntry = { + url: string + sha512: string + size: number + blockMapSize?: number +} + +type LatestYml = { + version: string + files: FileEntry[] + releaseDate: string +} + +function parse(content: string): LatestYml { + const lines = content.split("\n") + let version = "" + let releaseDate = "" + const files: FileEntry[] = [] + let current: Partial | undefined + + const flush = () => { + if (current?.url && current.sha512 && current.size) files.push(current as FileEntry) + current = undefined + } + + for (const line of lines) { + const indented = line.startsWith(" ") || line.startsWith(" -") + if (line.startsWith("version:")) version = line.slice("version:".length).trim() + else if (line.startsWith("releaseDate:")) + releaseDate = line.slice("releaseDate:".length).trim().replace(/^'|'$/g, "") + else if (line.trim().startsWith("- url:")) { + flush() + current = { url: line.trim().slice("- url:".length).trim() } + } else if (indented && current && line.trim().startsWith("sha512:")) + current.sha512 = line.trim().slice("sha512:".length).trim() + else if (indented && current && line.trim().startsWith("size:")) + current.size = Number(line.trim().slice("size:".length).trim()) + else if (indented && current && line.trim().startsWith("blockMapSize:")) + current.blockMapSize = Number(line.trim().slice("blockMapSize:".length).trim()) + else if (!indented && current) flush() + } + flush() + + return { version, files, releaseDate } +} + +function serialize(data: LatestYml) { + const lines = [`version: ${data.version}`, "files:"] + for (const file of data.files) { + lines.push(` - url: ${file.url}`) + lines.push(` sha512: ${file.sha512}`) + lines.push(` size: ${file.size}`) + if (file.blockMapSize) lines.push(` blockMapSize: ${file.blockMapSize}`) + } + lines.push(`releaseDate: '${data.releaseDate}'`) + return lines.join("\n") + "\n" +} + +async function read(subdir: string, filename: string): Promise { + const file = Bun.file(path.join(dir, subdir, filename)) + if (!(await file.exists())) return undefined + return parse(await file.text()) +} + +const output: Record = {} + +// Windows: single arch, pass through +const win = await read("latest-yml-x86_64-pc-windows-msvc", "latest.yml") +if (win) output["latest.yml"] = serialize(win) + +// Linux x64: pass through +const linuxX64 = await read("latest-yml-x86_64-unknown-linux-gnu", "latest-linux.yml") +if (linuxX64) output["latest-linux.yml"] = serialize(linuxX64) + +// Linux arm64: pass through +const linuxArm64 = await read("latest-yml-aarch64-unknown-linux-gnu", "latest-linux-arm64.yml") +if (linuxArm64) output["latest-linux-arm64.yml"] = serialize(linuxArm64) + +// macOS: merge arm64 + x64 into single file +const macX64 = await read("latest-yml-x86_64-apple-darwin", "latest-mac.yml") +const macArm64 = await read("latest-yml-aarch64-apple-darwin", "latest-mac.yml") +if (macX64 || macArm64) { + const base = macArm64 ?? macX64! + output["latest-mac.yml"] = serialize({ + version: base.version, + files: [...(macArm64?.files ?? []), ...(macX64?.files ?? [])], + releaseDate: base.releaseDate, + }) +} + +// Upload to release +const tag = `v${version}` +const tmp = process.env.RUNNER_TEMP ?? "/tmp" + +for (const [filename, content] of Object.entries(output)) { + const filepath = path.join(tmp, filename) + await Bun.write(filepath, content) + await $`gh release upload ${tag} ${filepath} --clobber --repo ${repo}` + console.log(`uploaded ${filename}`) +} + +console.log("finalized latest yml files") diff --git a/packages/desktop-electron/scripts/predev.ts b/packages/desktop-electron/scripts/predev.ts new file mode 100644 index 0000000000..a688d0e7f1 --- /dev/null +++ b/packages/desktop-electron/scripts/predev.ts @@ -0,0 +1,17 @@ +import { $ } from "bun" + +import { copyBinaryToSidecarFolder, getCurrentSidecar, windowsify } from "./utils" + +await $`bun ./scripts/copy-icons.ts ${process.env.OPENCODE_CHANNEL ?? "dev"}` + +const RUST_TARGET = Bun.env.RUST_TARGET + +const sidecarConfig = getCurrentSidecar(RUST_TARGET) + +const binaryPath = windowsify(`../opencode/dist/${sidecarConfig.ocBinary}/bin/opencode`) + +await (sidecarConfig.ocBinary.includes("-baseline") + ? $`cd ../opencode && bun run build --single --baseline` + : $`cd ../opencode && bun run build --single`) + +await copyBinaryToSidecarFolder(binaryPath, RUST_TARGET) diff --git a/packages/desktop-electron/scripts/prepare.ts b/packages/desktop-electron/scripts/prepare.ts new file mode 100755 index 0000000000..3764db9210 --- /dev/null +++ b/packages/desktop-electron/scripts/prepare.ts @@ -0,0 +1,24 @@ +#!/usr/bin/env bun +import { $ } from "bun" + +import { Script } from "@opencode-ai/script" +import { copyBinaryToSidecarFolder, getCurrentSidecar, resolveChannel, windowsify } from "./utils" + +const channel = resolveChannel() +await $`bun ./scripts/copy-icons.ts ${channel}` + +const pkg = await Bun.file("./package.json").json() +pkg.version = Script.version +await Bun.write("./package.json", JSON.stringify(pkg, null, 2) + "\n") +console.log(`Updated package.json version to ${Script.version}`) + +const sidecarConfig = getCurrentSidecar() + +const dir = "resources/opencode-binaries" + +await $`mkdir -p ${dir}` +await $`gh run download ${Bun.env.GITHUB_RUN_ID} -n opencode-cli`.cwd(dir) + +await copyBinaryToSidecarFolder(windowsify(`${dir}/${sidecarConfig.ocBinary}/bin/opencode`)) + +await $`rm -rf ${dir}` diff --git a/packages/desktop-electron/scripts/utils.ts b/packages/desktop-electron/scripts/utils.ts new file mode 100644 index 0000000000..4c9af1fc7e --- /dev/null +++ b/packages/desktop-electron/scripts/utils.ts @@ -0,0 +1,69 @@ +import { $ } from "bun" + +export type Channel = "dev" | "beta" | "prod" + +export function resolveChannel(): Channel { + const raw = Bun.env.OPENCODE_CHANNEL + if (raw === "dev" || raw === "beta" || raw === "prod") return raw + return "dev" +} + +export const SIDECAR_BINARIES: Array<{ rustTarget: string; ocBinary: string; assetExt: string }> = [ + { + rustTarget: "aarch64-apple-darwin", + ocBinary: "opencode-darwin-arm64", + assetExt: "zip", + }, + { + rustTarget: "x86_64-apple-darwin", + ocBinary: "opencode-darwin-x64-baseline", + assetExt: "zip", + }, + { + rustTarget: "x86_64-pc-windows-msvc", + ocBinary: "opencode-windows-x64-baseline", + assetExt: "zip", + }, + { + rustTarget: "x86_64-unknown-linux-gnu", + ocBinary: "opencode-linux-x64-baseline", + assetExt: "tar.gz", + }, + { + rustTarget: "aarch64-unknown-linux-gnu", + ocBinary: "opencode-linux-arm64", + assetExt: "tar.gz", + }, +] + +export const RUST_TARGET = Bun.env.RUST_TARGET + +function nativeTarget() { + const { platform, arch } = process + if (platform === "darwin") return arch === "arm64" ? "aarch64-apple-darwin" : "x86_64-apple-darwin" + if (platform === "win32") return "x86_64-pc-windows-msvc" + if (platform === "linux") return arch === "arm64" ? "aarch64-unknown-linux-gnu" : "x86_64-unknown-linux-gnu" + throw new Error(`Unsupported platform: ${platform}/${arch}`) +} + +export function getCurrentSidecar(target = RUST_TARGET ?? nativeTarget()) { + const binaryConfig = SIDECAR_BINARIES.find((b) => b.rustTarget === target) + if (!binaryConfig) throw new Error(`Sidecar configuration not available for Rust target '${target}'`) + + return binaryConfig +} + +export async function copyBinaryToSidecarFolder(source: string) { + const dir = `resources` + await $`mkdir -p ${dir}` + const dest = windowsify(`${dir}/opencode-cli`) + await $`cp ${source} ${dest}` + if (process.platform === "darwin") await $`codesign --force --sign - ${dest}` + + console.log(`Copied ${source} to ${dest}`) +} + +export function windowsify(path: string) { + if (path.endsWith(".exe")) return path + return `${path}${process.platform === "win32" ? ".exe" : ""}` +} diff --git a/packages/desktop-electron/src/main/apps.ts b/packages/desktop-electron/src/main/apps.ts new file mode 100644 index 0000000000..2b46037894 --- /dev/null +++ b/packages/desktop-electron/src/main/apps.ts @@ -0,0 +1,148 @@ +import { execFileSync } from "node:child_process" +import { existsSync, readFileSync, readdirSync } from "node:fs" +import { dirname, extname, join } from "node:path" + +export function checkAppExists(appName: string): boolean { + if (process.platform === "win32") return true + if (process.platform === "linux") return true + return checkMacosApp(appName) +} + +export function resolveAppPath(appName: string): string | null { + if (process.platform !== "win32") return appName + return resolveWindowsAppPath(appName) +} + +export function wslPath(path: string, mode: "windows" | "linux" | null): string { + if (process.platform !== "win32") return path + + const flag = mode === "windows" ? "-w" : "-u" + try { + if (path.startsWith("~")) { + const suffix = path.slice(1) + const cmd = `wslpath ${flag} \"$HOME${suffix.replace(/\"/g, '\\"')}\"` + const output = execFileSync("wsl", ["-e", "sh", "-lc", cmd]) + return output.toString().trim() + } + + const output = execFileSync("wsl", ["-e", "wslpath", flag, path]) + return output.toString().trim() + } catch (error) { + throw new Error(`Failed to run wslpath: ${String(error)}`) + } +} + +function checkMacosApp(appName: string) { + const locations = [`/Applications/${appName}.app`, `/System/Applications/${appName}.app`] + + const home = process.env.HOME + if (home) locations.push(`${home}/Applications/${appName}.app`) + + if (locations.some((location) => existsSync(location))) return true + + try { + execFileSync("which", [appName]) + return true + } catch { + return false + } +} + +function resolveWindowsAppPath(appName: string): string | null { + let output: string + try { + output = execFileSync("where", [appName]).toString() + } catch { + return null + } + + const paths = output + .split(/\r?\n/) + .map((line) => line.trim()) + .filter((line) => line.length > 0) + + const hasExt = (path: string, ext: string) => extname(path).toLowerCase() === `.${ext}` + + const exe = paths.find((path) => hasExt(path, "exe")) + if (exe) return exe + + const resolveCmd = (path: string) => { + const content = readFileSync(path, "utf8") + for (const token of content.split('"').map((value: string) => value.trim())) { + const lower = token.toLowerCase() + if (!lower.includes(".exe")) continue + + const index = lower.indexOf("%~dp0") + if (index >= 0) { + const base = dirname(path) + const suffix = token.slice(index + 5) + const resolved = suffix + .replace(/\//g, "\\") + .split("\\") + .filter((part: string) => part && part !== ".") + .reduce((current: string, part: string) => { + if (part === "..") return dirname(current) + return join(current, part) + }, base) + + if (existsSync(resolved)) return resolved + } + + if (existsSync(token)) return token + } + + return null + } + + for (const path of paths) { + if (hasExt(path, "cmd") || hasExt(path, "bat")) { + const resolved = resolveCmd(path) + if (resolved) return resolved + } + + if (!extname(path)) { + const cmd = `${path}.cmd` + if (existsSync(cmd)) { + const resolved = resolveCmd(cmd) + if (resolved) return resolved + } + + const bat = `${path}.bat` + if (existsSync(bat)) { + const resolved = resolveCmd(bat) + if (resolved) return resolved + } + } + } + + const key = appName + .split("") + .filter((value: string) => /[a-z0-9]/i.test(value)) + .map((value: string) => value.toLowerCase()) + .join("") + + if (key) { + for (const path of paths) { + const dirs = [dirname(path), dirname(dirname(path)), dirname(dirname(dirname(path)))] + for (const dir of dirs) { + try { + for (const entry of readdirSync(dir)) { + const candidate = join(dir, entry) + if (!hasExt(candidate, "exe")) continue + const stem = entry.replace(/\.exe$/i, "") + const name = stem + .split("") + .filter((value: string) => /[a-z0-9]/i.test(value)) + .map((value: string) => value.toLowerCase()) + .join("") + if (name.includes(key) || key.includes(name)) return candidate + } + } catch { + continue + } + } + } + } + + return paths[0] ?? null +} diff --git a/packages/desktop-electron/src/main/cli.ts b/packages/desktop-electron/src/main/cli.ts new file mode 100644 index 0000000000..e338d39138 --- /dev/null +++ b/packages/desktop-electron/src/main/cli.ts @@ -0,0 +1,279 @@ +import { execFileSync, spawn } from "node:child_process" +import { EventEmitter } from "node:events" +import { chmodSync, readFileSync, unlinkSync, writeFileSync } from "node:fs" +import { tmpdir } from "node:os" +import { dirname, join } from "node:path" +import readline from "node:readline" +import { fileURLToPath } from "node:url" +import { app } from "electron" +import treeKill from "tree-kill" + +import { WSL_ENABLED_KEY } from "./constants" +import { store } from "./store" + +const CLI_INSTALL_DIR = ".opencode/bin" +const CLI_BINARY_NAME = "opencode" + +export type ServerConfig = { + hostname?: string + port?: number +} + +export type Config = { + server?: ServerConfig +} + +export type TerminatedPayload = { code: number | null; signal: number | null } + +export type CommandEvent = + | { type: "stdout"; value: string } + | { type: "stderr"; value: string } + | { type: "error"; value: string } + | { type: "terminated"; value: TerminatedPayload } + | { type: "sqlite"; value: SqliteMigrationProgress } + +export type SqliteMigrationProgress = { type: "InProgress"; value: number } | { type: "Done" } + +export type CommandChild = { + kill: () => void +} + +const root = dirname(fileURLToPath(import.meta.url)) + +export function getSidecarPath() { + const suffix = process.platform === "win32" ? ".exe" : "" + const path = app.isPackaged + ? join(process.resourcesPath, `opencode-cli${suffix}`) + : join(root, "../../resources", `opencode-cli${suffix}`) + console.log(`[cli] Sidecar path resolved: ${path} (isPackaged: ${app.isPackaged})`) + return path +} + +export async function getConfig(): Promise { + const { events } = spawnCommand("debug config", {}) + let output = "" + + await new Promise((resolve) => { + events.on("stdout", (line: string) => { + output += line + }) + events.on("stderr", (line: string) => { + output += line + }) + events.on("terminated", () => resolve()) + events.on("error", () => resolve()) + }) + + try { + return JSON.parse(output) as Config + } catch { + return null + } +} + +export async function installCli(): Promise { + if (process.platform === "win32") { + throw new Error("CLI installation is only supported on macOS & Linux") + } + + const sidecar = getSidecarPath() + const scriptPath = join(app.getAppPath(), "install") + const script = readFileSync(scriptPath, "utf8") + const tempScript = join(tmpdir(), "opencode-install.sh") + + writeFileSync(tempScript, script, "utf8") + chmodSync(tempScript, 0o755) + + const cmd = spawn(tempScript, ["--binary", sidecar], { stdio: "pipe" }) + return await new Promise((resolve, reject) => { + cmd.on("exit", (code: number | null) => { + try { + unlinkSync(tempScript) + } catch {} + if (code === 0) { + const installPath = getCliInstallPath() + if (installPath) return resolve(installPath) + return reject(new Error("Could not determine install path")) + } + reject(new Error("Install script failed")) + }) + }) +} + +export function syncCli() { + if (!app.isPackaged) return + const installPath = getCliInstallPath() + if (!installPath) return + + let version = "" + try { + version = execFileSync(installPath, ["--version"]).toString().trim() + } catch { + return + } + + const cli = parseVersion(version) + const appVersion = parseVersion(app.getVersion()) + if (!cli || !appVersion) return + if (compareVersions(cli, appVersion) >= 0) return + void installCli().catch(() => undefined) +} + +export function serve(hostname: string, port: number, password: string) { + const args = `--print-logs --log-level WARN serve --hostname ${hostname} --port ${port}` + const env = { + OPENCODE_SERVER_USERNAME: "opencode", + OPENCODE_SERVER_PASSWORD: password, + } + + return spawnCommand(args, env) +} + +export function spawnCommand(args: string, extraEnv: Record) { + console.log(`[cli] Spawning command with args: ${args}`) + const base = Object.fromEntries( + Object.entries(process.env).filter((entry): entry is [string, string] => typeof entry[1] === "string"), + ) + const envs = { + ...base, + OPENCODE_EXPERIMENTAL_ICON_DISCOVERY: "true", + OPENCODE_EXPERIMENTAL_FILEWATCHER: "true", + OPENCODE_CLIENT: "desktop", + XDG_STATE_HOME: app.getPath("userData"), + ...extraEnv, + } + + const { cmd, cmdArgs } = buildCommand(args, envs) + console.log(`[cli] Executing: ${cmd} ${cmdArgs.join(" ")}`) + const child = spawn(cmd, cmdArgs, { + env: envs, + detached: true, + windowsHide: true, + stdio: ["ignore", "pipe", "pipe"], + }) + console.log(`[cli] Spawned process with PID: ${child.pid}`) + + const events = new EventEmitter() + const exit = new Promise((resolve) => { + child.on("exit", (code: number | null, signal: NodeJS.Signals | null) => { + console.log(`[cli] Process exited with code: ${code}, signal: ${signal}`) + resolve({ code: code ?? null, signal: null }) + }) + child.on("error", (error: Error) => { + console.error(`[cli] Process error: ${error.message}`) + events.emit("error", error.message) + }) + }) + + const stdout = child.stdout + const stderr = child.stderr + + if (stdout) { + readline.createInterface({ input: stdout }).on("line", (line: string) => { + if (handleSqliteProgress(events, line)) return + events.emit("stdout", `${line}\n`) + }) + } + + if (stderr) { + readline.createInterface({ input: stderr }).on("line", (line: string) => { + if (handleSqliteProgress(events, line)) return + events.emit("stderr", `${line}\n`) + }) + } + + exit.then((payload) => { + events.emit("terminated", payload) + }) + + const kill = () => { + if (!child.pid) return + treeKill(child.pid) + } + + return { events, child: { kill }, exit } +} + +function handleSqliteProgress(events: EventEmitter, line: string) { + const stripped = line.startsWith("sqlite-migration:") ? line.slice("sqlite-migration:".length).trim() : null + if (!stripped) return false + if (stripped === "done") { + events.emit("sqlite", { type: "Done" }) + return true + } + const value = Number.parseInt(stripped, 10) + if (!Number.isNaN(value)) { + events.emit("sqlite", { type: "InProgress", value }) + return true + } + return false +} + +function buildCommand(args: string, env: Record) { + if (process.platform === "win32" && isWslEnabled()) { + console.log(`[cli] Using WSL mode`) + const version = app.getVersion() + const script = [ + "set -e", + 'BIN="$HOME/.opencode/bin/opencode"', + 'if [ ! -x "$BIN" ]; then', + ` curl -fsSL https://opencode.ai/install | bash -s -- --version ${shellEscape(version)} --no-modify-path`, + "fi", + `${envPrefix(env)} exec "$BIN" ${args}`, + ].join("\n") + + return { cmd: "wsl", cmdArgs: ["-e", "bash", "-lc", script] } + } + + if (process.platform === "win32") { + const sidecar = getSidecarPath() + console.log(`[cli] Windows direct mode, sidecar: ${sidecar}`) + return { cmd: sidecar, cmdArgs: args.split(" ") } + } + + const sidecar = getSidecarPath() + const shell = process.env.SHELL || "/bin/sh" + const line = shell.endsWith("/nu") ? `^\"${sidecar}\" ${args}` : `\"${sidecar}\" ${args}` + console.log(`[cli] Unix mode, shell: ${shell}, command: ${line}`) + return { cmd: shell, cmdArgs: ["-l", "-c", line] } +} + +function envPrefix(env: Record) { + const entries = Object.entries(env).map(([key, value]) => `${key}=${shellEscape(value)}`) + return entries.join(" ") +} + +function shellEscape(input: string) { + if (!input) return "''" + return `'${input.replace(/'/g, `'"'"'`)}'` +} + +function getCliInstallPath() { + const home = process.env.HOME + if (!home) return null + return join(home, CLI_INSTALL_DIR, CLI_BINARY_NAME) +} + +function isWslEnabled() { + return store.get(WSL_ENABLED_KEY) === true +} + +function parseVersion(value: string) { + const parts = value + .replace(/^v/, "") + .split(".") + .map((part) => Number.parseInt(part, 10)) + if (parts.some((part) => Number.isNaN(part))) return null + return parts +} + +function compareVersions(a: number[], b: number[]) { + const len = Math.max(a.length, b.length) + for (let i = 0; i < len; i += 1) { + const left = a[i] ?? 0 + const right = b[i] ?? 0 + if (left > right) return 1 + if (left < right) return -1 + } + return 0 +} diff --git a/packages/desktop-electron/src/main/constants.ts b/packages/desktop-electron/src/main/constants.ts new file mode 100644 index 0000000000..1e21661c1a --- /dev/null +++ b/packages/desktop-electron/src/main/constants.ts @@ -0,0 +1,10 @@ +import { app } from "electron" + +type Channel = "dev" | "beta" | "prod" +const raw = import.meta.env.OPENCODE_CHANNEL +export const CHANNEL: Channel = raw === "dev" || raw === "beta" || raw === "prod" ? raw : "dev" + +export const SETTINGS_STORE = "opencode.settings" +export const DEFAULT_SERVER_URL_KEY = "defaultServerUrl" +export const WSL_ENABLED_KEY = "wslEnabled" +export const UPDATER_ENABLED = app.isPackaged && CHANNEL !== "dev" diff --git a/packages/desktop-electron/src/main/env.d.ts b/packages/desktop-electron/src/main/env.d.ts new file mode 100644 index 0000000000..0ee0c551df --- /dev/null +++ b/packages/desktop-electron/src/main/env.d.ts @@ -0,0 +1,7 @@ +interface ImportMetaEnv { + readonly OPENCODE_CHANNEL: string +} + +interface ImportMeta { + readonly env: ImportMetaEnv +} diff --git a/packages/desktop-electron/src/main/index.ts b/packages/desktop-electron/src/main/index.ts new file mode 100644 index 0000000000..7b6acd1477 --- /dev/null +++ b/packages/desktop-electron/src/main/index.ts @@ -0,0 +1,463 @@ +import { randomUUID } from "node:crypto" +import { EventEmitter } from "node:events" +import { existsSync } from "node:fs" +import { createServer } from "node:net" +import { homedir } from "node:os" +import { join } from "node:path" +import type { Event } from "electron" +import { app, type BrowserWindow, dialog } from "electron" +import pkg from "electron-updater" + +const APP_NAMES: Record = { + dev: "OpenCode Dev", + beta: "OpenCode Beta", + prod: "OpenCode", +} +const APP_IDS: Record = { + dev: "ai.opencode.desktop.dev", + beta: "ai.opencode.desktop.beta", + prod: "ai.opencode.desktop", +} +app.setName(app.isPackaged ? APP_NAMES[CHANNEL] : "OpenCode Dev") +app.setPath("userData", join(app.getPath("appData"), app.isPackaged ? APP_IDS[CHANNEL] : "ai.opencode.desktop.dev")) +const { autoUpdater } = pkg + +import type { InitStep, ServerReadyData, SqliteMigrationProgress, WslConfig } from "../preload/types" +import { checkAppExists, resolveAppPath, wslPath } from "./apps" +import type { CommandChild } from "./cli" +import { installCli, syncCli } from "./cli" +import { CHANNEL, UPDATER_ENABLED } from "./constants" +import { registerIpcHandlers, sendDeepLinks, sendMenuCommand, sendSqliteMigrationProgress } from "./ipc" +import { initLogging } from "./logging" +import { parseMarkdown } from "./markdown" +import { createMenu } from "./menu" +import { + checkHealth, + checkHealthOrAskRetry, + getDefaultServerUrl, + getSavedServerUrl, + getWslConfig, + setDefaultServerUrl, + setWslConfig, + spawnLocalServer, +} from "./server" +import { createLoadingWindow, createMainWindow, setDockIcon } from "./windows" + +type ServerConnection = + | { variant: "existing"; url: string } + | { + variant: "cli" + url: string + password: null | string + health: { + wait: Promise + } + events: any + } + +const initEmitter = new EventEmitter() +let initStep: InitStep = { phase: "server_waiting" } + +let mainWindow: BrowserWindow | null = null +const loadingWindow: BrowserWindow | null = null +let sidecar: CommandChild | null = null +const loadingComplete = defer() + +const pendingDeepLinks: string[] = [] + +const serverReady = defer() +const logger = initLogging() + +logger.log("app starting", { + version: app.getVersion(), + packaged: app.isPackaged, +}) + +setupApp() + +function setupApp() { + ensureLoopbackNoProxy() + app.commandLine.appendSwitch("proxy-bypass-list", "<-loopback>") + + if (!app.requestSingleInstanceLock()) { + app.quit() + return + } + + app.on("second-instance", (_event: Event, argv: string[]) => { + const urls = argv.filter((arg: string) => arg.startsWith("opencode://")) + if (urls.length) { + logger.log("deep link received via second-instance", { urls }) + emitDeepLinks(urls) + } + focusMainWindow() + }) + + app.on("open-url", (event: Event, url: string) => { + event.preventDefault() + logger.log("deep link received via open-url", { url }) + emitDeepLinks([url]) + }) + + app.on("before-quit", () => { + killSidecar() + }) + + void app.whenReady().then(async () => { + // migrate() + app.setAsDefaultProtocolClient("opencode") + setDockIcon() + setupAutoUpdater() + syncCli() + await initialize() + }) +} + +function emitDeepLinks(urls: string[]) { + if (urls.length === 0) return + pendingDeepLinks.push(...urls) + if (mainWindow) sendDeepLinks(mainWindow, urls) +} + +function focusMainWindow() { + if (!mainWindow) return + mainWindow.show() + mainWindow.focus() +} + +function setInitStep(step: InitStep) { + initStep = step + logger.log("init step", { step }) + initEmitter.emit("step", step) +} + +async function setupServerConnection(): Promise { + const customUrl = await getSavedServerUrl() + + if (customUrl && (await checkHealthOrAskRetry(customUrl))) { + serverReady.resolve({ url: customUrl, password: null }) + return { variant: "existing", url: customUrl } + } + + const port = await getSidecarPort() + const hostname = "127.0.0.1" + const localUrl = `http://${hostname}:${port}` + + if (await checkHealth(localUrl)) { + serverReady.resolve({ url: localUrl, password: null }) + return { variant: "existing", url: localUrl } + } + + const password = randomUUID() + const { child, health, events } = spawnLocalServer(hostname, port, password) + sidecar = child + + return { + variant: "cli", + url: localUrl, + password, + health, + events, + } +} + +async function initialize() { + const needsMigration = !sqliteFileExists() + const sqliteDone = needsMigration ? defer() : undefined + + const loadingTask = (async () => { + logger.log("setting up server connection") + const serverConnection = await setupServerConnection() + logger.log("server connection ready", { + variant: serverConnection.variant, + url: serverConnection.url, + }) + + const cliHealthCheck = (() => { + if (serverConnection.variant == "cli") { + return async () => { + const { events, health } = serverConnection + events.on("sqlite", (progress: SqliteMigrationProgress) => { + setInitStep({ phase: "sqlite_waiting" }) + if (loadingWindow) sendSqliteMigrationProgress(loadingWindow, progress) + if (mainWindow) sendSqliteMigrationProgress(mainWindow, progress) + if (progress.type === "Done") sqliteDone?.resolve() + }) + await health.wait + serverReady.resolve({ + url: serverConnection.url, + password: serverConnection.password, + }) + } + } else { + serverReady.resolve({ url: serverConnection.url, password: null }) + return null + } + })() + + logger.log("server connection started") + + if (cliHealthCheck) { + if (needsMigration) await sqliteDone?.promise + cliHealthCheck?.() + } + + logger.log("loading task finished") + })() + + const globals = { + updaterEnabled: UPDATER_ENABLED, + wsl: getWslConfig().enabled, + deepLinks: pendingDeepLinks, + } + + const loadingWindow = await (async () => { + if (needsMigration /** TOOD: 1 second timeout */) { + // showLoading = await Promise.race([init.then(() => false).catch(() => false), delay(1000).then(() => true)]) + const loadingWindow = createLoadingWindow(globals) + await delay(1000) + return loadingWindow + } else { + logger.log("showing main window without loading window") + mainWindow = createMainWindow(globals) + wireMenu() + } + })() + + await loadingTask + setInitStep({ phase: "done" }) + + if (loadingWindow) { + await loadingComplete.promise + } + + if (!mainWindow) { + mainWindow = createMainWindow(globals) + wireMenu() + } + + loadingWindow?.close() +} + +function wireMenu() { + if (!mainWindow) return + createMenu({ + trigger: (id) => mainWindow && sendMenuCommand(mainWindow, id), + installCli: () => { + void installCli() + }, + checkForUpdates: () => { + void checkForUpdates(true) + }, + reload: () => mainWindow?.reload(), + relaunch: () => { + killSidecar() + app.relaunch() + app.exit(0) + }, + }) +} + +registerIpcHandlers({ + killSidecar: () => killSidecar(), + installCli: async () => installCli(), + awaitInitialization: async (sendStep) => { + sendStep(initStep) + const listener = (step: InitStep) => sendStep(step) + initEmitter.on("step", listener) + try { + logger.log("awaiting server ready") + const res = await serverReady.promise + logger.log("server ready", { url: res.url }) + return res + } finally { + initEmitter.off("step", listener) + } + }, + getDefaultServerUrl: () => getDefaultServerUrl(), + setDefaultServerUrl: (url) => setDefaultServerUrl(url), + getWslConfig: () => Promise.resolve(getWslConfig()), + setWslConfig: (config: WslConfig) => setWslConfig(config), + getDisplayBackend: async () => null, + setDisplayBackend: async () => undefined, + parseMarkdown: async (markdown) => parseMarkdown(markdown), + checkAppExists: async (appName) => checkAppExists(appName), + wslPath: async (path, mode) => wslPath(path, mode), + resolveAppPath: async (appName) => resolveAppPath(appName), + loadingWindowComplete: () => loadingComplete.resolve(), + runUpdater: async (alertOnFail) => checkForUpdates(alertOnFail), + checkUpdate: async () => checkUpdate(), + installUpdate: async () => installUpdate(), +}) + +function killSidecar() { + if (!sidecar) return + sidecar.kill() + sidecar = null +} + +function ensureLoopbackNoProxy() { + const loopback = ["127.0.0.1", "localhost", "::1"] + const upsert = (key: string) => { + const items = (process.env[key] ?? "") + .split(",") + .map((value: string) => value.trim()) + .filter((value: string) => Boolean(value)) + + for (const host of loopback) { + if (items.some((value: string) => value.toLowerCase() === host)) continue + items.push(host) + } + + process.env[key] = items.join(",") + } + + upsert("NO_PROXY") + upsert("no_proxy") +} + +async function getSidecarPort() { + const fromEnv = process.env.OPENCODE_PORT + if (fromEnv) { + const parsed = Number.parseInt(fromEnv, 10) + if (!Number.isNaN(parsed)) return parsed + } + + return await new Promise((resolve, reject) => { + const server = createServer() + server.on("error", reject) + server.listen(0, "127.0.0.1", () => { + const address = server.address() + if (typeof address !== "object" || !address) { + server.close() + reject(new Error("Failed to get port")) + return + } + const port = address.port + server.close(() => resolve(port)) + }) + }) +} + +function sqliteFileExists() { + const xdg = process.env.XDG_DATA_HOME + const base = xdg && xdg.length > 0 ? xdg : join(homedir(), ".local", "share") + return existsSync(join(base, "opencode", "opencode.db")) +} + +function setupAutoUpdater() { + if (!UPDATER_ENABLED) return + autoUpdater.logger = logger + autoUpdater.channel = "latest" + autoUpdater.allowPrerelease = false + autoUpdater.allowDowngrade = true + autoUpdater.autoDownload = false + autoUpdater.autoInstallOnAppQuit = true + logger.log("auto updater configured", { + channel: autoUpdater.channel, + allowPrerelease: autoUpdater.allowPrerelease, + allowDowngrade: autoUpdater.allowDowngrade, + currentVersion: app.getVersion(), + }) +} + +let updateReady = false + +async function checkUpdate() { + if (!UPDATER_ENABLED) return { updateAvailable: false } + updateReady = false + logger.log("checking for updates", { + currentVersion: app.getVersion(), + channel: autoUpdater.channel, + allowPrerelease: autoUpdater.allowPrerelease, + allowDowngrade: autoUpdater.allowDowngrade, + }) + try { + const result = await autoUpdater.checkForUpdates() + const updateInfo = result?.updateInfo + logger.log("update metadata fetched", { + releaseVersion: updateInfo?.version ?? null, + releaseDate: updateInfo?.releaseDate ?? null, + releaseName: updateInfo?.releaseName ?? null, + files: updateInfo?.files?.map((file) => file.url) ?? [], + }) + const version = result?.updateInfo?.version + if (result?.isUpdateAvailable === false || !version) { + logger.log("no update available", { + reason: "provider returned no newer version", + }) + return { updateAvailable: false } + } + logger.log("update available", { version }) + await autoUpdater.downloadUpdate() + logger.log("update download completed", { version }) + updateReady = true + return { updateAvailable: true, version } + } catch (error) { + logger.error("update check failed", error) + return { updateAvailable: false, failed: true } + } +} + +async function installUpdate() { + if (!updateReady) return + killSidecar() + autoUpdater.quitAndInstall() +} + +async function checkForUpdates(alertOnFail: boolean) { + if (!UPDATER_ENABLED) return + logger.log("checkForUpdates invoked", { alertOnFail }) + const result = await checkUpdate() + if (!result.updateAvailable) { + if (result.failed) { + logger.log("no update decision", { reason: "update check failed" }) + if (!alertOnFail) return + await dialog.showMessageBox({ + type: "error", + message: "Update check failed.", + title: "Update Error", + }) + return + } + + logger.log("no update decision", { reason: "already up to date" }) + if (!alertOnFail) return + await dialog.showMessageBox({ + type: "info", + message: "You're up to date.", + title: "No Updates", + }) + return + } + + const response = await dialog.showMessageBox({ + type: "info", + message: `Update ${result.version ?? ""} downloaded. Restart now?`, + title: "Update Ready", + buttons: ["Restart", "Later"], + defaultId: 0, + cancelId: 1, + }) + logger.log("update prompt response", { + version: result.version ?? null, + restartNow: response.response === 0, + }) + if (response.response === 0) { + await installUpdate() + } +} + +function delay(ms: number) { + return new Promise((resolve) => setTimeout(resolve, ms)) +} + +function defer() { + let resolve!: (value: T) => void + let reject!: (error: Error) => void + const promise = new Promise((res, rej) => { + resolve = res + reject = rej + }) + return { promise, resolve, reject } +} diff --git a/packages/desktop-electron/src/main/ipc.ts b/packages/desktop-electron/src/main/ipc.ts new file mode 100644 index 0000000000..bbb5379bb7 --- /dev/null +++ b/packages/desktop-electron/src/main/ipc.ts @@ -0,0 +1,176 @@ +import { execFile } from "node:child_process" +import { BrowserWindow, Notification, app, clipboard, dialog, ipcMain, shell } from "electron" +import type { IpcMainEvent, IpcMainInvokeEvent } from "electron" + +import type { InitStep, ServerReadyData, SqliteMigrationProgress, WslConfig } from "../preload/types" +import { getStore } from "./store" + +type Deps = { + killSidecar: () => void + installCli: () => Promise + awaitInitialization: (sendStep: (step: InitStep) => void) => Promise + getDefaultServerUrl: () => Promise | string | null + setDefaultServerUrl: (url: string | null) => Promise | void + getWslConfig: () => Promise + setWslConfig: (config: WslConfig) => Promise | void + getDisplayBackend: () => Promise + setDisplayBackend: (backend: string | null) => Promise | void + parseMarkdown: (markdown: string) => Promise | string + checkAppExists: (appName: string) => Promise | boolean + wslPath: (path: string, mode: "windows" | "linux" | null) => Promise + resolveAppPath: (appName: string) => Promise + loadingWindowComplete: () => void + runUpdater: (alertOnFail: boolean) => Promise | void + checkUpdate: () => Promise<{ updateAvailable: boolean; version?: string }> + installUpdate: () => Promise | void +} + +export function registerIpcHandlers(deps: Deps) { + ipcMain.handle("kill-sidecar", () => deps.killSidecar()) + ipcMain.handle("install-cli", () => deps.installCli()) + ipcMain.handle("await-initialization", (event: IpcMainInvokeEvent) => { + const send = (step: InitStep) => event.sender.send("init-step", step) + return deps.awaitInitialization(send) + }) + ipcMain.handle("get-default-server-url", () => deps.getDefaultServerUrl()) + ipcMain.handle("set-default-server-url", (_event: IpcMainInvokeEvent, url: string | null) => + deps.setDefaultServerUrl(url), + ) + ipcMain.handle("get-wsl-config", () => deps.getWslConfig()) + ipcMain.handle("set-wsl-config", (_event: IpcMainInvokeEvent, config: WslConfig) => deps.setWslConfig(config)) + ipcMain.handle("get-display-backend", () => deps.getDisplayBackend()) + ipcMain.handle("set-display-backend", (_event: IpcMainInvokeEvent, backend: string | null) => + deps.setDisplayBackend(backend), + ) + ipcMain.handle("parse-markdown", (_event: IpcMainInvokeEvent, markdown: string) => deps.parseMarkdown(markdown)) + ipcMain.handle("check-app-exists", (_event: IpcMainInvokeEvent, appName: string) => deps.checkAppExists(appName)) + ipcMain.handle("wsl-path", (_event: IpcMainInvokeEvent, path: string, mode: "windows" | "linux" | null) => + deps.wslPath(path, mode), + ) + ipcMain.handle("resolve-app-path", (_event: IpcMainInvokeEvent, appName: string) => deps.resolveAppPath(appName)) + ipcMain.on("loading-window-complete", () => deps.loadingWindowComplete()) + ipcMain.handle("run-updater", (_event: IpcMainInvokeEvent, alertOnFail: boolean) => deps.runUpdater(alertOnFail)) + ipcMain.handle("check-update", () => deps.checkUpdate()) + ipcMain.handle("install-update", () => deps.installUpdate()) + ipcMain.handle("store-get", (_event: IpcMainInvokeEvent, name: string, key: string) => { + const store = getStore(name) + const value = store.get(key) + if (value === undefined || value === null) return null + return typeof value === "string" ? value : JSON.stringify(value) + }) + ipcMain.handle("store-set", (_event: IpcMainInvokeEvent, name: string, key: string, value: string) => { + getStore(name).set(key, value) + }) + ipcMain.handle("store-delete", (_event: IpcMainInvokeEvent, name: string, key: string) => { + getStore(name).delete(key) + }) + ipcMain.handle("store-clear", (_event: IpcMainInvokeEvent, name: string) => { + getStore(name).clear() + }) + ipcMain.handle("store-keys", (_event: IpcMainInvokeEvent, name: string) => { + const store = getStore(name) + return Object.keys(store.store) + }) + ipcMain.handle("store-length", (_event: IpcMainInvokeEvent, name: string) => { + const store = getStore(name) + return Object.keys(store.store).length + }) + + ipcMain.handle( + "open-directory-picker", + async (_event: IpcMainInvokeEvent, opts?: { multiple?: boolean; title?: string; defaultPath?: string }) => { + const result = await dialog.showOpenDialog({ + properties: ["openDirectory", ...(opts?.multiple ? ["multiSelections" as const] : [])], + title: opts?.title ?? "Choose a folder", + defaultPath: opts?.defaultPath, + }) + if (result.canceled) return null + return opts?.multiple ? result.filePaths : result.filePaths[0] + }, + ) + + ipcMain.handle( + "open-file-picker", + async (_event: IpcMainInvokeEvent, opts?: { multiple?: boolean; title?: string; defaultPath?: string }) => { + const result = await dialog.showOpenDialog({ + properties: ["openFile", ...(opts?.multiple ? ["multiSelections" as const] : [])], + title: opts?.title ?? "Choose a file", + defaultPath: opts?.defaultPath, + }) + if (result.canceled) return null + return opts?.multiple ? result.filePaths : result.filePaths[0] + }, + ) + + ipcMain.handle( + "save-file-picker", + async (_event: IpcMainInvokeEvent, opts?: { title?: string; defaultPath?: string }) => { + const result = await dialog.showSaveDialog({ + title: opts?.title ?? "Save file", + defaultPath: opts?.defaultPath, + }) + if (result.canceled) return null + return result.filePath ?? null + }, + ) + + ipcMain.on("open-link", (_event: IpcMainEvent, url: string) => { + void shell.openExternal(url) + }) + + ipcMain.handle("open-path", async (_event: IpcMainInvokeEvent, path: string, app?: string) => { + if (!app) return shell.openPath(path) + await new Promise((resolve, reject) => { + const [cmd, args] = + process.platform === "darwin" ? (["open", ["-a", app, path]] as const) : ([app, [path]] as const) + execFile(cmd, args, (err) => (err ? reject(err) : resolve())) + }) + }) + + ipcMain.handle("read-clipboard-image", () => { + const image = clipboard.readImage() + if (image.isEmpty()) return null + const buffer = image.toPNG().buffer + const size = image.getSize() + return { buffer, width: size.width, height: size.height } + }) + + ipcMain.on("show-notification", (_event: IpcMainEvent, title: string, body?: string) => { + new Notification({ title, body }).show() + }) + + ipcMain.handle("get-window-focused", (event: IpcMainInvokeEvent) => { + const win = BrowserWindow.fromWebContents(event.sender) + return win?.isFocused() ?? false + }) + + ipcMain.handle("set-window-focus", (event: IpcMainInvokeEvent) => { + const win = BrowserWindow.fromWebContents(event.sender) + win?.focus() + }) + + ipcMain.handle("show-window", (event: IpcMainInvokeEvent) => { + const win = BrowserWindow.fromWebContents(event.sender) + win?.show() + }) + + ipcMain.on("relaunch", () => { + app.relaunch() + app.exit(0) + }) + + ipcMain.handle("get-zoom-factor", (event: IpcMainInvokeEvent) => event.sender.getZoomFactor()) + ipcMain.handle("set-zoom-factor", (event: IpcMainInvokeEvent, factor: number) => event.sender.setZoomFactor(factor)) +} + +export function sendSqliteMigrationProgress(win: BrowserWindow, progress: SqliteMigrationProgress) { + win.webContents.send("sqlite-migration-progress", progress) +} + +export function sendMenuCommand(win: BrowserWindow, id: string) { + win.webContents.send("menu-command", id) +} + +export function sendDeepLinks(win: BrowserWindow, urls: string[]) { + win.webContents.send("deep-link", urls) +} diff --git a/packages/desktop-electron/src/main/logging.ts b/packages/desktop-electron/src/main/logging.ts new file mode 100644 index 0000000000..d315b2d344 --- /dev/null +++ b/packages/desktop-electron/src/main/logging.ts @@ -0,0 +1,40 @@ +import log from "electron-log/main.js" +import { readFileSync, readdirSync, statSync, unlinkSync } from "node:fs" +import { dirname, join } from "node:path" + +const MAX_LOG_AGE_DAYS = 7 +const TAIL_LINES = 1000 + +export function initLogging() { + log.transports.file.maxSize = 5 * 1024 * 1024 + cleanup() + return log +} + +export function tail(): string { + try { + const path = log.transports.file.getFile().path + const contents = readFileSync(path, "utf8") + const lines = contents.split("\n") + return lines.slice(Math.max(0, lines.length - TAIL_LINES)).join("\n") + } catch { + return "" + } +} + +function cleanup() { + const path = log.transports.file.getFile().path + const dir = dirname(path) + const cutoff = Date.now() - MAX_LOG_AGE_DAYS * 24 * 60 * 60 * 1000 + + for (const entry of readdirSync(dir)) { + const file = join(dir, entry) + try { + const info = statSync(file) + if (!info.isFile()) continue + if (info.mtimeMs < cutoff) unlinkSync(file) + } catch { + continue + } + } +} diff --git a/packages/desktop-electron/src/main/markdown.ts b/packages/desktop-electron/src/main/markdown.ts new file mode 100644 index 0000000000..b956f48760 --- /dev/null +++ b/packages/desktop-electron/src/main/markdown.ts @@ -0,0 +1,16 @@ +import { marked, type Tokens } from "marked" + +const renderer = new marked.Renderer() + +renderer.link = ({ href, title, text }: Tokens.Link) => { + const titleAttr = title ? ` title="${title}"` : "" + return `${text}` +} + +export function parseMarkdown(input: string) { + return marked(input, { + renderer, + breaks: false, + gfm: true, + }) +} diff --git a/packages/desktop-electron/src/main/menu.ts b/packages/desktop-electron/src/main/menu.ts new file mode 100644 index 0000000000..53707ba7f2 --- /dev/null +++ b/packages/desktop-electron/src/main/menu.ts @@ -0,0 +1,116 @@ +import { BrowserWindow, Menu, shell } from "electron" + +import { UPDATER_ENABLED } from "./constants" + +type Deps = { + trigger: (id: string) => void + installCli: () => void + checkForUpdates: () => void + reload: () => void + relaunch: () => void +} + +export function createMenu(deps: Deps) { + if (process.platform !== "darwin") return + + const template: Electron.MenuItemConstructorOptions[] = [ + { + label: "OpenCode", + submenu: [ + { role: "about" }, + { + label: "Check for Updates...", + enabled: UPDATER_ENABLED, + click: () => deps.checkForUpdates(), + }, + { + label: "Install CLI...", + click: () => deps.installCli(), + }, + { + label: "Reload Webview", + click: () => deps.reload(), + }, + { + label: "Restart", + click: () => deps.relaunch(), + }, + { type: "separator" }, + { role: "hide" }, + { role: "hideOthers" }, + { role: "unhide" }, + { type: "separator" }, + { role: "quit" }, + ], + }, + { + label: "File", + submenu: [ + { label: "New Session", accelerator: "Shift+Cmd+S", click: () => deps.trigger("session.new") }, + { label: "Open Project...", accelerator: "Cmd+O", click: () => deps.trigger("project.open") }, + { type: "separator" }, + { role: "close" }, + ], + }, + { + label: "Edit", + submenu: [ + { role: "undo" }, + { role: "redo" }, + { type: "separator" }, + { role: "cut" }, + { role: "copy" }, + { role: "paste" }, + { role: "selectAll" }, + ], + }, + { + label: "View", + submenu: [ + { label: "Toggle Sidebar", accelerator: "Cmd+B", click: () => deps.trigger("sidebar.toggle") }, + { label: "Toggle Terminal", accelerator: "Ctrl+`", click: () => deps.trigger("terminal.toggle") }, + { label: "Toggle File Tree", click: () => deps.trigger("fileTree.toggle") }, + { type: "separator" }, + { label: "Back", click: () => deps.trigger("common.goBack") }, + { label: "Forward", click: () => deps.trigger("common.goForward") }, + { type: "separator" }, + { + label: "Previous Session", + accelerator: "Option+ArrowUp", + click: () => deps.trigger("session.previous"), + }, + { + label: "Next Session", + accelerator: "Option+ArrowDown", + click: () => deps.trigger("session.next"), + }, + { type: "separator" }, + { + label: "Toggle Developer Tools", + accelerator: "Alt+Cmd+I", + click: () => BrowserWindow.getFocusedWindow()?.webContents.toggleDevTools(), + }, + ], + }, + { + label: "Help", + submenu: [ + { label: "OpenCode Documentation", click: () => shell.openExternal("https://opencode.ai/docs") }, + { label: "Support Forum", click: () => shell.openExternal("https://discord.com/invite/opencode") }, + { type: "separator" }, + { type: "separator" }, + { + label: "Share Feedback", + click: () => + shell.openExternal("https://github.com/anomalyco/opencode/issues/new?template=feature_request.yml"), + }, + { + label: "Report a Bug", + click: () => shell.openExternal("https://github.com/anomalyco/opencode/issues/new?template=bug_report.yml"), + }, + ], + }, + ] + + Menu.setApplicationMenu(Menu.buildFromTemplate(template)) +} diff --git a/packages/desktop-electron/src/main/migrate.ts b/packages/desktop-electron/src/main/migrate.ts new file mode 100644 index 0000000000..bad1349eeb --- /dev/null +++ b/packages/desktop-electron/src/main/migrate.ts @@ -0,0 +1,91 @@ +import { app } from "electron" +import log from "electron-log/main.js" +import { existsSync, readdirSync, readFileSync } from "node:fs" +import { homedir } from "node:os" +import { join } from "node:path" +import { CHANNEL } from "./constants" +import { getStore, store } from "./store" + +const TAURI_MIGRATED_KEY = "tauriMigrated" + +// Resolve the directory where Tauri stored its .dat files for the given app identifier. +// Mirrors Tauri's AppLocalData / AppData resolution per OS. +function tauriDir(id: string) { + switch (process.platform) { + case "darwin": + return join(homedir(), "Library", "Application Support", id) + case "win32": + return join(process.env.APPDATA ?? join(homedir(), "AppData", "Roaming"), id) + default: + return join(process.env.XDG_DATA_HOME ?? join(homedir(), ".local", "share"), id) + } +} + +// The Tauri app identifier changes between dev/beta/prod builds. +const TAURI_APP_IDS: Record = { + dev: "ai.opencode.desktop.dev", + beta: "ai.opencode.desktop.beta", + prod: "ai.opencode.desktop", +} +function tauriAppId() { + return app.isPackaged ? TAURI_APP_IDS[CHANNEL] : "ai.opencode.desktop.dev" +} + +// Migrate a single Tauri .dat file into the corresponding electron-store. +// `opencode.settings.dat` is special: it maps to the `opencode.settings` store +// (the electron-store name without the `.dat` extension). All other .dat files +// keep their full filename as the electron-store name so they match what the +// renderer already passes via IPC (e.g. `"default.dat"`, `"opencode.global.dat"`). +function migrateFile(datPath: string, filename: string) { + let data: Record + try { + data = JSON.parse(readFileSync(datPath, "utf-8")) + } catch (err) { + log.warn("tauri migration: failed to parse", filename, err) + return + } + + // opencode.settings.dat → the electron settings store ("opencode.settings"). + // All other .dat files keep their full filename as the store name so they match + // what the renderer passes via IPC (e.g. "default.dat", "opencode.global.dat"). + const storeName = filename === "opencode.settings.dat" ? "opencode.settings" : filename + const target = getStore(storeName) + const migrated: string[] = [] + const skipped: string[] = [] + + for (const [key, value] of Object.entries(data)) { + // Don't overwrite values the user has already set in the Electron app. + if (target.has(key)) { + skipped.push(key) + continue + } + target.set(key, value) + migrated.push(key) + } + + log.log("tauri migration: migrated", filename, "→", storeName, { migrated, skipped }) +} + +export function migrate() { + if (store.get(TAURI_MIGRATED_KEY)) { + log.log("tauri migration: already done, skipping") + return + } + + const dir = tauriDir(tauriAppId()) + log.log("tauri migration: starting", { dir }) + + if (!existsSync(dir)) { + log.log("tauri migration: no tauri data directory found, nothing to migrate") + store.set(TAURI_MIGRATED_KEY, true) + return + } + + for (const filename of readdirSync(dir)) { + if (!filename.endsWith(".dat")) continue + migrateFile(join(dir, filename), filename) + } + + log.log("tauri migration: complete") + store.set(TAURI_MIGRATED_KEY, true) +} diff --git a/packages/desktop-electron/src/main/server.ts b/packages/desktop-electron/src/main/server.ts new file mode 100644 index 0000000000..92018e72e7 --- /dev/null +++ b/packages/desktop-electron/src/main/server.ts @@ -0,0 +1,129 @@ +import { dialog } from "electron" + +import { getConfig, serve, type CommandChild, type Config } from "./cli" +import { DEFAULT_SERVER_URL_KEY, WSL_ENABLED_KEY } from "./constants" +import { store } from "./store" + +export type WslConfig = { enabled: boolean } + +export type HealthCheck = { wait: Promise } + +export function getDefaultServerUrl(): string | null { + const value = store.get(DEFAULT_SERVER_URL_KEY) + return typeof value === "string" ? value : null +} + +export function setDefaultServerUrl(url: string | null) { + if (url) { + store.set(DEFAULT_SERVER_URL_KEY, url) + return + } + + store.delete(DEFAULT_SERVER_URL_KEY) +} + +export function getWslConfig(): WslConfig { + const value = store.get(WSL_ENABLED_KEY) + return { enabled: typeof value === "boolean" ? value : false } +} + +export function setWslConfig(config: WslConfig) { + store.set(WSL_ENABLED_KEY, config.enabled) +} + +export async function getSavedServerUrl(): Promise { + const direct = getDefaultServerUrl() + if (direct) return direct + + const config = await getConfig().catch(() => null) + if (!config) return null + return getServerUrlFromConfig(config) +} + +export function spawnLocalServer(hostname: string, port: number, password: string) { + const { child, exit, events } = serve(hostname, port, password) + + const wait = (async () => { + const url = `http://${hostname}:${port}` + + const ready = async () => { + while (true) { + await new Promise((resolve) => setTimeout(resolve, 100)) + if (await checkHealth(url, password)) return + } + } + + const terminated = async () => { + const payload = await exit + throw new Error( + `Sidecar terminated before becoming healthy (code=${payload.code ?? "unknown"} signal=${ + payload.signal ?? "unknown" + })`, + ) + } + + await Promise.race([ready(), terminated()]) + })() + + return { child, health: { wait }, events } +} + +export async function checkHealth(url: string, password?: string | null): Promise { + let healthUrl: URL + try { + healthUrl = new URL("/global/health", url) + } catch { + return false + } + + const headers = new Headers() + if (password) { + const auth = Buffer.from(`opencode:${password}`).toString("base64") + headers.set("authorization", `Basic ${auth}`) + } + + try { + const res = await fetch(healthUrl, { + method: "GET", + headers, + signal: AbortSignal.timeout(3000), + }) + return res.ok + } catch { + return false + } +} + +export async function checkHealthOrAskRetry(url: string): Promise { + while (true) { + if (await checkHealth(url)) return true + + const result = await dialog.showMessageBox({ + type: "warning", + message: `Could not connect to configured server:\n${url}\n\nWould you like to retry or start a local server instead?`, + title: "Connection Failed", + buttons: ["Retry", "Start Local"], + defaultId: 0, + cancelId: 1, + }) + + if (result.response === 0) continue + return false + } +} + +export function normalizeHostnameForUrl(hostname: string) { + if (hostname === "0.0.0.0") return "127.0.0.1" + if (hostname === "::") return "[::1]" + if (hostname.includes(":") && !hostname.startsWith("[")) return `[${hostname}]` + return hostname +} + +export function getServerUrlFromConfig(config: Config) { + const server = config.server + if (!server?.port) return null + const host = server.hostname ? normalizeHostnameForUrl(server.hostname) : "127.0.0.1" + return `http://${host}:${server.port}` +} + +export type { CommandChild } diff --git a/packages/desktop-electron/src/main/store.ts b/packages/desktop-electron/src/main/store.ts new file mode 100644 index 0000000000..fa1c5682e2 --- /dev/null +++ b/packages/desktop-electron/src/main/store.ts @@ -0,0 +1,15 @@ +import Store from "electron-store" + +import { SETTINGS_STORE } from "./constants" + +const cache = new Map() + +export function getStore(name = SETTINGS_STORE) { + const cached = cache.get(name) + if (cached) return cached + const next = new Store({ name }) + cache.set(name, next) + return next +} + +export const store = getStore(SETTINGS_STORE) diff --git a/packages/desktop-electron/src/main/windows.ts b/packages/desktop-electron/src/main/windows.ts new file mode 100644 index 0000000000..9178457f8d --- /dev/null +++ b/packages/desktop-electron/src/main/windows.ts @@ -0,0 +1,135 @@ +import windowState from "electron-window-state" +import { app, BrowserWindow, nativeImage } from "electron" +import { dirname, join } from "node:path" +import { fileURLToPath } from "node:url" + +type Globals = { + updaterEnabled: boolean + wsl: boolean + deepLinks?: string[] +} + +const root = dirname(fileURLToPath(import.meta.url)) + +function iconsDir() { + return app.isPackaged ? join(process.resourcesPath, "icons") : join(root, "../../resources/icons") +} + +function iconPath() { + const ext = process.platform === "win32" ? "ico" : "png" + return join(iconsDir(), `icon.${ext}`) +} + +export function setDockIcon() { + if (process.platform !== "darwin") return + app.dock?.setIcon(nativeImage.createFromPath(join(iconsDir(), "128x128@2x.png"))) +} + +export function createMainWindow(globals: Globals) { + const state = windowState({ + defaultWidth: 1280, + defaultHeight: 800, + }) + + const win = new BrowserWindow({ + x: state.x, + y: state.y, + width: state.width, + height: state.height, + show: true, + title: "OpenCode", + icon: iconPath(), + ...(process.platform === "darwin" + ? { + titleBarStyle: "hidden" as const, + trafficLightPosition: { x: 12, y: 14 }, + } + : {}), + ...(process.platform === "win32" + ? { + frame: false, + titleBarStyle: "hidden" as const, + titleBarOverlay: { + color: "transparent", + symbolColor: "#999", + height: 40, + }, + } + : {}), + webPreferences: { + preload: join(root, "../preload/index.mjs"), + sandbox: false, + }, + }) + + state.manage(win) + loadWindow(win, "index.html") + wireZoom(win) + injectGlobals(win, globals) + + return win +} + +export function createLoadingWindow(globals: Globals) { + const win = new BrowserWindow({ + width: 640, + height: 480, + resizable: false, + center: true, + show: true, + icon: iconPath(), + ...(process.platform === "darwin" ? { titleBarStyle: "hidden" as const } : {}), + ...(process.platform === "win32" + ? { + frame: false, + titleBarStyle: "hidden" as const, + titleBarOverlay: { + color: "transparent", + symbolColor: "#999", + height: 40, + }, + } + : {}), + webPreferences: { + preload: join(root, "../preload/index.mjs"), + sandbox: false, + }, + }) + + loadWindow(win, "loading.html") + injectGlobals(win, globals) + + return win +} + +function loadWindow(win: BrowserWindow, html: string) { + const devUrl = process.env.ELECTRON_RENDERER_URL + if (devUrl) { + const url = new URL(html, devUrl) + void win.loadURL(url.toString()) + return + } + + void win.loadFile(join(root, `../renderer/${html}`)) +} + +function injectGlobals(win: BrowserWindow, globals: Globals) { + win.webContents.on("dom-ready", () => { + const deepLinks = globals.deepLinks ?? [] + const data = { + updaterEnabled: globals.updaterEnabled, + wsl: globals.wsl, + deepLinks: Array.isArray(deepLinks) ? deepLinks.splice(0) : deepLinks, + } + void win.webContents.executeJavaScript( + `window.__OPENCODE__ = Object.assign(window.__OPENCODE__ ?? {}, ${JSON.stringify(data)})`, + ) + }) +} + +function wireZoom(win: BrowserWindow) { + win.webContents.setZoomFactor(1) + win.webContents.on("zoom-changed", () => { + win.webContents.setZoomFactor(1) + }) +} diff --git a/packages/desktop-electron/src/preload/index.ts b/packages/desktop-electron/src/preload/index.ts new file mode 100644 index 0000000000..a6520ab424 --- /dev/null +++ b/packages/desktop-electron/src/preload/index.ts @@ -0,0 +1,66 @@ +import { contextBridge, ipcRenderer } from "electron" +import type { ElectronAPI, InitStep, SqliteMigrationProgress } from "./types" + +const api: ElectronAPI = { + killSidecar: () => ipcRenderer.invoke("kill-sidecar"), + installCli: () => ipcRenderer.invoke("install-cli"), + awaitInitialization: (onStep) => { + const handler = (_: unknown, step: InitStep) => onStep(step) + ipcRenderer.on("init-step", handler) + return ipcRenderer.invoke("await-initialization").finally(() => { + ipcRenderer.removeListener("init-step", handler) + }) + }, + getDefaultServerUrl: () => ipcRenderer.invoke("get-default-server-url"), + setDefaultServerUrl: (url) => ipcRenderer.invoke("set-default-server-url", url), + getWslConfig: () => ipcRenderer.invoke("get-wsl-config"), + setWslConfig: (config) => ipcRenderer.invoke("set-wsl-config", config), + getDisplayBackend: () => ipcRenderer.invoke("get-display-backend"), + setDisplayBackend: (backend) => ipcRenderer.invoke("set-display-backend", backend), + parseMarkdownCommand: (markdown) => ipcRenderer.invoke("parse-markdown", markdown), + checkAppExists: (appName) => ipcRenderer.invoke("check-app-exists", appName), + wslPath: (path, mode) => ipcRenderer.invoke("wsl-path", path, mode), + resolveAppPath: (appName) => ipcRenderer.invoke("resolve-app-path", appName), + storeGet: (name, key) => ipcRenderer.invoke("store-get", name, key), + storeSet: (name, key, value) => ipcRenderer.invoke("store-set", name, key, value), + storeDelete: (name, key) => ipcRenderer.invoke("store-delete", name, key), + storeClear: (name) => ipcRenderer.invoke("store-clear", name), + storeKeys: (name) => ipcRenderer.invoke("store-keys", name), + storeLength: (name) => ipcRenderer.invoke("store-length", name), + + onSqliteMigrationProgress: (cb) => { + const handler = (_: unknown, progress: SqliteMigrationProgress) => cb(progress) + ipcRenderer.on("sqlite-migration-progress", handler) + return () => ipcRenderer.removeListener("sqlite-migration-progress", handler) + }, + onMenuCommand: (cb) => { + const handler = (_: unknown, id: string) => cb(id) + ipcRenderer.on("menu-command", handler) + return () => ipcRenderer.removeListener("menu-command", handler) + }, + onDeepLink: (cb) => { + const handler = (_: unknown, urls: string[]) => cb(urls) + ipcRenderer.on("deep-link", handler) + return () => ipcRenderer.removeListener("deep-link", handler) + }, + + openDirectoryPicker: (opts) => ipcRenderer.invoke("open-directory-picker", opts), + openFilePicker: (opts) => ipcRenderer.invoke("open-file-picker", opts), + saveFilePicker: (opts) => ipcRenderer.invoke("save-file-picker", opts), + openLink: (url) => ipcRenderer.send("open-link", url), + openPath: (path, app) => ipcRenderer.invoke("open-path", path, app), + readClipboardImage: () => ipcRenderer.invoke("read-clipboard-image"), + showNotification: (title, body) => ipcRenderer.send("show-notification", title, body), + getWindowFocused: () => ipcRenderer.invoke("get-window-focused"), + setWindowFocus: () => ipcRenderer.invoke("set-window-focus"), + showWindow: () => ipcRenderer.invoke("show-window"), + relaunch: () => ipcRenderer.send("relaunch"), + getZoomFactor: () => ipcRenderer.invoke("get-zoom-factor"), + setZoomFactor: (factor) => ipcRenderer.invoke("set-zoom-factor", factor), + loadingWindowComplete: () => ipcRenderer.send("loading-window-complete"), + runUpdater: (alertOnFail) => ipcRenderer.invoke("run-updater", alertOnFail), + checkUpdate: () => ipcRenderer.invoke("check-update"), + installUpdate: () => ipcRenderer.invoke("install-update"), +} + +contextBridge.exposeInMainWorld("api", api) diff --git a/packages/desktop-electron/src/preload/types.ts b/packages/desktop-electron/src/preload/types.ts new file mode 100644 index 0000000000..af5410f5f5 --- /dev/null +++ b/packages/desktop-electron/src/preload/types.ts @@ -0,0 +1,64 @@ +export type InitStep = { phase: "server_waiting" } | { phase: "sqlite_waiting" } | { phase: "done" } + +export type ServerReadyData = { + url: string + password: string | null +} + +export type SqliteMigrationProgress = { type: "InProgress"; value: number } | { type: "Done" } + +export type WslConfig = { enabled: boolean } + +export type LinuxDisplayBackend = "wayland" | "auto" + +export type ElectronAPI = { + killSidecar: () => Promise + installCli: () => Promise + awaitInitialization: (onStep: (step: InitStep) => void) => Promise + getDefaultServerUrl: () => Promise + setDefaultServerUrl: (url: string | null) => Promise + getWslConfig: () => Promise + setWslConfig: (config: WslConfig) => Promise + getDisplayBackend: () => Promise + setDisplayBackend: (backend: LinuxDisplayBackend | null) => Promise + parseMarkdownCommand: (markdown: string) => Promise + checkAppExists: (appName: string) => Promise + wslPath: (path: string, mode: "windows" | "linux" | null) => Promise + resolveAppPath: (appName: string) => Promise + storeGet: (name: string, key: string) => Promise + storeSet: (name: string, key: string, value: string) => Promise + storeDelete: (name: string, key: string) => Promise + storeClear: (name: string) => Promise + storeKeys: (name: string) => Promise + storeLength: (name: string) => Promise + + onSqliteMigrationProgress: (cb: (progress: SqliteMigrationProgress) => void) => () => void + onMenuCommand: (cb: (id: string) => void) => () => void + onDeepLink: (cb: (urls: string[]) => void) => () => void + + openDirectoryPicker: (opts?: { + multiple?: boolean + title?: string + defaultPath?: string + }) => Promise + openFilePicker: (opts?: { + multiple?: boolean + title?: string + defaultPath?: string + }) => Promise + saveFilePicker: (opts?: { title?: string; defaultPath?: string }) => Promise + openLink: (url: string) => void + openPath: (path: string, app?: string) => Promise + readClipboardImage: () => Promise<{ buffer: ArrayBuffer; width: number; height: number } | null> + showNotification: (title: string, body?: string) => void + getWindowFocused: () => Promise + setWindowFocus: () => Promise + showWindow: () => Promise + relaunch: () => void + getZoomFactor: () => Promise + setZoomFactor: (factor: number) => Promise + loadingWindowComplete: () => void + runUpdater: (alertOnFail: boolean) => Promise + checkUpdate: () => Promise<{ updateAvailable: boolean; version?: string }> + installUpdate: () => Promise +} diff --git a/packages/desktop-electron/src/renderer/cli.ts b/packages/desktop-electron/src/renderer/cli.ts new file mode 100644 index 0000000000..11d3c1f1b0 --- /dev/null +++ b/packages/desktop-electron/src/renderer/cli.ts @@ -0,0 +1,12 @@ +import { initI18n, t } from "./i18n" + +export async function installCli(): Promise { + await initI18n() + + try { + const path = await window.api.installCli() + window.alert(t("desktop.cli.installed.message", { path })) + } catch (e) { + window.alert(t("desktop.cli.failed.message", { error: String(e) })) + } +} diff --git a/packages/desktop-electron/src/renderer/env.d.ts b/packages/desktop-electron/src/renderer/env.d.ts new file mode 100644 index 0000000000..d1590ff048 --- /dev/null +++ b/packages/desktop-electron/src/renderer/env.d.ts @@ -0,0 +1,12 @@ +import type { ElectronAPI } from "../preload/types" + +declare global { + interface Window { + api: ElectronAPI + __OPENCODE__?: { + updaterEnabled?: boolean + wsl?: boolean + deepLinks?: string[] + } + } +} diff --git a/packages/desktop-electron/src/renderer/i18n/ar.ts b/packages/desktop-electron/src/renderer/i18n/ar.ts new file mode 100644 index 0000000000..fdbf0a8047 --- /dev/null +++ b/packages/desktop-electron/src/renderer/i18n/ar.ts @@ -0,0 +1,26 @@ +export const dict = { + "desktop.menu.checkForUpdates": "التحقق من وجود تحديثات...", + "desktop.menu.installCli": "تثبيت CLI...", + "desktop.menu.reloadWebview": "إعادة تحميل Webview", + "desktop.menu.restart": "إعادة تشغيل", + + "desktop.dialog.chooseFolder": "اختر مجلدًا", + "desktop.dialog.chooseFile": "اختر ملفًا", + "desktop.dialog.saveFile": "حفظ ملف", + + "desktop.updater.checkFailed.title": "فشل التحقق من التحديثات", + "desktop.updater.checkFailed.message": "فشل التحقق من وجود تحديثات", + "desktop.updater.none.title": "لا توجد تحديثات متاحة", + "desktop.updater.none.message": "أنت تستخدم بالفعل أحدث إصدار من OpenCode", + "desktop.updater.downloadFailed.title": "فشل التحديث", + "desktop.updater.downloadFailed.message": "فشل تنزيل التحديث", + "desktop.updater.downloaded.title": "تم تنزيل التحديث", + "desktop.updater.downloaded.prompt": "تم تنزيل إصدار {{version}} من OpenCode، هل ترغب في تثبيته وإعادة تشغيله؟", + "desktop.updater.installFailed.title": "فشل التحديث", + "desktop.updater.installFailed.message": "فشل تثبيت التحديث", + + "desktop.cli.installed.title": "تم تثبيت CLI", + "desktop.cli.installed.message": "تم تثبيت CLI في {{path}}\n\nأعد تشغيل الطرفية لاستخدام الأمر 'opencode'.", + "desktop.cli.failed.title": "فشل التثبيت", + "desktop.cli.failed.message": "فشل تثبيت CLI: {{error}}", +} diff --git a/packages/desktop-electron/src/renderer/i18n/br.ts b/packages/desktop-electron/src/renderer/i18n/br.ts new file mode 100644 index 0000000000..75fe2dc32b --- /dev/null +++ b/packages/desktop-electron/src/renderer/i18n/br.ts @@ -0,0 +1,27 @@ +export const dict = { + "desktop.menu.checkForUpdates": "Verificar atualizações...", + "desktop.menu.installCli": "Instalar CLI...", + "desktop.menu.reloadWebview": "Recarregar Webview", + "desktop.menu.restart": "Reiniciar", + + "desktop.dialog.chooseFolder": "Escolher uma pasta", + "desktop.dialog.chooseFile": "Escolher um arquivo", + "desktop.dialog.saveFile": "Salvar arquivo", + + "desktop.updater.checkFailed.title": "Falha ao verificar atualizações", + "desktop.updater.checkFailed.message": "Falha ao verificar atualizações", + "desktop.updater.none.title": "Nenhuma atualização disponível", + "desktop.updater.none.message": "Você já está usando a versão mais recente do OpenCode", + "desktop.updater.downloadFailed.title": "Falha na atualização", + "desktop.updater.downloadFailed.message": "Falha ao baixar a atualização", + "desktop.updater.downloaded.title": "Atualização baixada", + "desktop.updater.downloaded.prompt": + "A versão {{version}} do OpenCode foi baixada. Você gostaria de instalá-la e reiniciar?", + "desktop.updater.installFailed.title": "Falha na atualização", + "desktop.updater.installFailed.message": "Falha ao instalar a atualização", + + "desktop.cli.installed.title": "CLI instalada", + "desktop.cli.installed.message": "CLI instalada em {{path}}\n\nReinicie seu terminal para usar o comando 'opencode'.", + "desktop.cli.failed.title": "Falha na instalação", + "desktop.cli.failed.message": "Falha ao instalar a CLI: {{error}}", +} diff --git a/packages/desktop-electron/src/renderer/i18n/bs.ts b/packages/desktop-electron/src/renderer/i18n/bs.ts new file mode 100644 index 0000000000..58c266f530 --- /dev/null +++ b/packages/desktop-electron/src/renderer/i18n/bs.ts @@ -0,0 +1,28 @@ +export const dict = { + "desktop.menu.checkForUpdates": "Provjeri ažuriranja...", + "desktop.menu.installCli": "Instaliraj CLI...", + "desktop.menu.reloadWebview": "Ponovo učitavanje webview-a", + "desktop.menu.restart": "Restartuj", + + "desktop.dialog.chooseFolder": "Odaberi folder", + "desktop.dialog.chooseFile": "Odaberi datoteku", + "desktop.dialog.saveFile": "Sačuvaj datoteku", + + "desktop.updater.checkFailed.title": "Provjera ažuriranja nije uspjela", + "desktop.updater.checkFailed.message": "Nije moguće provjeriti ažuriranja", + "desktop.updater.none.title": "Nema dostupnog ažuriranja", + "desktop.updater.none.message": "Već koristiš najnoviju verziju OpenCode-a", + "desktop.updater.downloadFailed.title": "Ažuriranje nije uspjelo", + "desktop.updater.downloadFailed.message": "Neuspjelo preuzimanje ažuriranja", + "desktop.updater.downloaded.title": "Ažuriranje preuzeto", + "desktop.updater.downloaded.prompt": + "Verzija {{version}} OpenCode-a je preuzeta. Želiš li da je instaliraš i ponovo pokreneš aplikaciju?", + "desktop.updater.installFailed.title": "Ažuriranje nije uspjelo", + "desktop.updater.installFailed.message": "Neuspjela instalacija ažuriranja", + + "desktop.cli.installed.title": "CLI instaliran", + "desktop.cli.installed.message": + "CLI je instaliran u {{path}}\n\nRestartuj terminal da bi koristio komandu 'opencode'.", + "desktop.cli.failed.title": "Instalacija nije uspjela", + "desktop.cli.failed.message": "Neuspjela instalacija CLI-a: {{error}}", +} diff --git a/packages/desktop-electron/src/renderer/i18n/da.ts b/packages/desktop-electron/src/renderer/i18n/da.ts new file mode 100644 index 0000000000..2109495f76 --- /dev/null +++ b/packages/desktop-electron/src/renderer/i18n/da.ts @@ -0,0 +1,28 @@ +export const dict = { + "desktop.menu.checkForUpdates": "Tjek for opdateringer...", + "desktop.menu.installCli": "Installer CLI...", + "desktop.menu.reloadWebview": "Genindlæs Webview", + "desktop.menu.restart": "Genstart", + + "desktop.dialog.chooseFolder": "Vælg en mappe", + "desktop.dialog.chooseFile": "Vælg en fil", + "desktop.dialog.saveFile": "Gem fil", + + "desktop.updater.checkFailed.title": "Opdateringstjek mislykkedes", + "desktop.updater.checkFailed.message": "Kunne ikke tjekke for opdateringer", + "desktop.updater.none.title": "Ingen opdatering tilgængelig", + "desktop.updater.none.message": "Du bruger allerede den nyeste version af OpenCode", + "desktop.updater.downloadFailed.title": "Opdatering mislykkedes", + "desktop.updater.downloadFailed.message": "Kunne ikke downloade opdateringen", + "desktop.updater.downloaded.title": "Opdatering downloadet", + "desktop.updater.downloaded.prompt": + "Version {{version}} af OpenCode er blevet downloadet. Vil du installere den og genstarte?", + "desktop.updater.installFailed.title": "Opdatering mislykkedes", + "desktop.updater.installFailed.message": "Kunne ikke installere opdateringen", + + "desktop.cli.installed.title": "CLI installeret", + "desktop.cli.installed.message": + "CLI installeret i {{path}}\n\nGenstart din terminal for at bruge 'opencode'-kommandoen.", + "desktop.cli.failed.title": "Installation mislykkedes", + "desktop.cli.failed.message": "Kunne ikke installere CLI: {{error}}", +} diff --git a/packages/desktop-electron/src/renderer/i18n/de.ts b/packages/desktop-electron/src/renderer/i18n/de.ts new file mode 100644 index 0000000000..38ad8096e3 --- /dev/null +++ b/packages/desktop-electron/src/renderer/i18n/de.ts @@ -0,0 +1,28 @@ +export const dict = { + "desktop.menu.checkForUpdates": "Nach Updates suchen...", + "desktop.menu.installCli": "CLI installieren...", + "desktop.menu.reloadWebview": "Webview neu laden", + "desktop.menu.restart": "Neustart", + + "desktop.dialog.chooseFolder": "Ordner auswählen", + "desktop.dialog.chooseFile": "Datei auswählen", + "desktop.dialog.saveFile": "Datei speichern", + + "desktop.updater.checkFailed.title": "Updateprüfung fehlgeschlagen", + "desktop.updater.checkFailed.message": "Updates konnten nicht geprüft werden", + "desktop.updater.none.title": "Kein Update verfügbar", + "desktop.updater.none.message": "Sie verwenden bereits die neueste Version von OpenCode", + "desktop.updater.downloadFailed.title": "Update fehlgeschlagen", + "desktop.updater.downloadFailed.message": "Update konnte nicht heruntergeladen werden", + "desktop.updater.downloaded.title": "Update heruntergeladen", + "desktop.updater.downloaded.prompt": + "Version {{version}} von OpenCode wurde heruntergeladen. Möchten Sie sie installieren und neu starten?", + "desktop.updater.installFailed.title": "Update fehlgeschlagen", + "desktop.updater.installFailed.message": "Update konnte nicht installiert werden", + + "desktop.cli.installed.title": "CLI installiert", + "desktop.cli.installed.message": + "CLI wurde in {{path}} installiert\n\nStarten Sie Ihr Terminal neu, um den Befehl 'opencode' zu verwenden.", + "desktop.cli.failed.title": "Installation fehlgeschlagen", + "desktop.cli.failed.message": "CLI konnte nicht installiert werden: {{error}}", +} diff --git a/packages/desktop-electron/src/renderer/i18n/en.ts b/packages/desktop-electron/src/renderer/i18n/en.ts new file mode 100644 index 0000000000..4c30380d56 --- /dev/null +++ b/packages/desktop-electron/src/renderer/i18n/en.ts @@ -0,0 +1,27 @@ +export const dict = { + "desktop.menu.checkForUpdates": "Check for Updates...", + "desktop.menu.installCli": "Install CLI...", + "desktop.menu.reloadWebview": "Reload Webview", + "desktop.menu.restart": "Restart", + + "desktop.dialog.chooseFolder": "Choose a folder", + "desktop.dialog.chooseFile": "Choose a file", + "desktop.dialog.saveFile": "Save file", + + "desktop.updater.checkFailed.title": "Update Check Failed", + "desktop.updater.checkFailed.message": "Failed to check for updates", + "desktop.updater.none.title": "No Update Available", + "desktop.updater.none.message": "You are already using the latest version of OpenCode", + "desktop.updater.downloadFailed.title": "Update Failed", + "desktop.updater.downloadFailed.message": "Failed to download update", + "desktop.updater.downloaded.title": "Update Downloaded", + "desktop.updater.downloaded.prompt": + "Version {{version}} of OpenCode has been downloaded, would you like to install it and relaunch?", + "desktop.updater.installFailed.title": "Update Failed", + "desktop.updater.installFailed.message": "Failed to install update", + + "desktop.cli.installed.title": "CLI Installed", + "desktop.cli.installed.message": "CLI installed to {{path}}\n\nRestart your terminal to use the 'opencode' command.", + "desktop.cli.failed.title": "Installation Failed", + "desktop.cli.failed.message": "Failed to install CLI: {{error}}", +} diff --git a/packages/desktop-electron/src/renderer/i18n/es.ts b/packages/desktop-electron/src/renderer/i18n/es.ts new file mode 100644 index 0000000000..80504a8f24 --- /dev/null +++ b/packages/desktop-electron/src/renderer/i18n/es.ts @@ -0,0 +1,27 @@ +export const dict = { + "desktop.menu.checkForUpdates": "Buscar actualizaciones...", + "desktop.menu.installCli": "Instalar CLI...", + "desktop.menu.reloadWebview": "Recargar Webview", + "desktop.menu.restart": "Reiniciar", + + "desktop.dialog.chooseFolder": "Elegir una carpeta", + "desktop.dialog.chooseFile": "Elegir un archivo", + "desktop.dialog.saveFile": "Guardar archivo", + + "desktop.updater.checkFailed.title": "Comprobación de actualizaciones fallida", + "desktop.updater.checkFailed.message": "No se pudieron buscar actualizaciones", + "desktop.updater.none.title": "No hay actualizaciones disponibles", + "desktop.updater.none.message": "Ya estás usando la versión más reciente de OpenCode", + "desktop.updater.downloadFailed.title": "Actualización fallida", + "desktop.updater.downloadFailed.message": "No se pudo descargar la actualización", + "desktop.updater.downloaded.title": "Actualización descargada", + "desktop.updater.downloaded.prompt": + "Se ha descargado la versión {{version}} de OpenCode. ¿Quieres instalarla y reiniciar?", + "desktop.updater.installFailed.title": "Actualización fallida", + "desktop.updater.installFailed.message": "No se pudo instalar la actualización", + + "desktop.cli.installed.title": "CLI instalada", + "desktop.cli.installed.message": "CLI instalada en {{path}}\n\nReinicia tu terminal para usar el comando 'opencode'.", + "desktop.cli.failed.title": "Instalación fallida", + "desktop.cli.failed.message": "No se pudo instalar la CLI: {{error}}", +} diff --git a/packages/desktop-electron/src/renderer/i18n/fr.ts b/packages/desktop-electron/src/renderer/i18n/fr.ts new file mode 100644 index 0000000000..4f0bb2b16c --- /dev/null +++ b/packages/desktop-electron/src/renderer/i18n/fr.ts @@ -0,0 +1,28 @@ +export const dict = { + "desktop.menu.checkForUpdates": "Vérifier les mises à jour...", + "desktop.menu.installCli": "Installer la CLI...", + "desktop.menu.reloadWebview": "Recharger la Webview", + "desktop.menu.restart": "Redémarrer", + + "desktop.dialog.chooseFolder": "Choisir un dossier", + "desktop.dialog.chooseFile": "Choisir un fichier", + "desktop.dialog.saveFile": "Enregistrer le fichier", + + "desktop.updater.checkFailed.title": "Échec de la vérification des mises à jour", + "desktop.updater.checkFailed.message": "Impossible de vérifier les mises à jour", + "desktop.updater.none.title": "Aucune mise à jour disponible", + "desktop.updater.none.message": "Vous utilisez déjà la dernière version d'OpenCode", + "desktop.updater.downloadFailed.title": "Échec de la mise à jour", + "desktop.updater.downloadFailed.message": "Impossible de télécharger la mise à jour", + "desktop.updater.downloaded.title": "Mise à jour téléchargée", + "desktop.updater.downloaded.prompt": + "La version {{version}} d'OpenCode a été téléchargée. Voulez-vous l'installer et redémarrer ?", + "desktop.updater.installFailed.title": "Échec de la mise à jour", + "desktop.updater.installFailed.message": "Impossible d'installer la mise à jour", + + "desktop.cli.installed.title": "CLI installée", + "desktop.cli.installed.message": + "CLI installée dans {{path}}\n\nRedémarrez votre terminal pour utiliser la commande 'opencode'.", + "desktop.cli.failed.title": "Échec de l'installation", + "desktop.cli.failed.message": "Impossible d'installer la CLI : {{error}}", +} diff --git a/packages/desktop-electron/src/renderer/i18n/index.ts b/packages/desktop-electron/src/renderer/i18n/index.ts new file mode 100644 index 0000000000..be87f94f91 --- /dev/null +++ b/packages/desktop-electron/src/renderer/i18n/index.ts @@ -0,0 +1,188 @@ +import * as i18n from "@solid-primitives/i18n" + +import { dict as desktopEn } from "./en" +import { dict as desktopZh } from "./zh" +import { dict as desktopZht } from "./zht" +import { dict as desktopKo } from "./ko" +import { dict as desktopDe } from "./de" +import { dict as desktopEs } from "./es" +import { dict as desktopFr } from "./fr" +import { dict as desktopDa } from "./da" +import { dict as desktopJa } from "./ja" +import { dict as desktopPl } from "./pl" +import { dict as desktopRu } from "./ru" +import { dict as desktopAr } from "./ar" +import { dict as desktopNo } from "./no" +import { dict as desktopBr } from "./br" +import { dict as desktopBs } from "./bs" + +import { dict as appEn } from "../../../../app/src/i18n/en" +import { dict as appZh } from "../../../../app/src/i18n/zh" +import { dict as appZht } from "../../../../app/src/i18n/zht" +import { dict as appKo } from "../../../../app/src/i18n/ko" +import { dict as appDe } from "../../../../app/src/i18n/de" +import { dict as appEs } from "../../../../app/src/i18n/es" +import { dict as appFr } from "../../../../app/src/i18n/fr" +import { dict as appDa } from "../../../../app/src/i18n/da" +import { dict as appJa } from "../../../../app/src/i18n/ja" +import { dict as appPl } from "../../../../app/src/i18n/pl" +import { dict as appRu } from "../../../../app/src/i18n/ru" +import { dict as appAr } from "../../../../app/src/i18n/ar" +import { dict as appNo } from "../../../../app/src/i18n/no" +import { dict as appBr } from "../../../../app/src/i18n/br" +import { dict as appBs } from "../../../../app/src/i18n/bs" + +export type Locale = + | "en" + | "zh" + | "zht" + | "ko" + | "de" + | "es" + | "fr" + | "da" + | "ja" + | "pl" + | "ru" + | "ar" + | "no" + | "br" + | "bs" + +type RawDictionary = typeof appEn & typeof desktopEn +type Dictionary = i18n.Flatten + +const LOCALES: readonly Locale[] = [ + "en", + "zh", + "zht", + "ko", + "de", + "es", + "fr", + "da", + "ja", + "pl", + "ru", + "bs", + "ar", + "no", + "br", +] + +function detectLocale(): Locale { + if (typeof navigator !== "object") return "en" + + const languages = navigator.languages?.length ? navigator.languages : [navigator.language] + for (const language of languages) { + if (!language) continue + if (language.toLowerCase().startsWith("en")) return "en" + if (language.toLowerCase().startsWith("zh")) { + if (language.toLowerCase().includes("hant")) return "zht" + return "zh" + } + if (language.toLowerCase().startsWith("ko")) return "ko" + if (language.toLowerCase().startsWith("de")) return "de" + if (language.toLowerCase().startsWith("es")) return "es" + if (language.toLowerCase().startsWith("fr")) return "fr" + if (language.toLowerCase().startsWith("da")) return "da" + if (language.toLowerCase().startsWith("ja")) return "ja" + if (language.toLowerCase().startsWith("pl")) return "pl" + if (language.toLowerCase().startsWith("ru")) return "ru" + if (language.toLowerCase().startsWith("ar")) return "ar" + if ( + language.toLowerCase().startsWith("no") || + language.toLowerCase().startsWith("nb") || + language.toLowerCase().startsWith("nn") + ) + return "no" + if (language.toLowerCase().startsWith("pt")) return "br" + if (language.toLowerCase().startsWith("bs")) return "bs" + } + + return "en" +} + +function parseLocale(value: unknown): Locale | null { + if (!value) return null + if (typeof value !== "string") return null + if ((LOCALES as readonly string[]).includes(value)) return value as Locale + return null +} + +function parseRecord(value: unknown) { + if (!value || typeof value !== "object") return null + if (Array.isArray(value)) return null + return value as Record +} + +function parseStored(value: unknown) { + if (typeof value !== "string") return value + try { + return JSON.parse(value) as unknown + } catch { + return value + } +} + +function pickLocale(value: unknown): Locale | null { + const direct = parseLocale(value) + if (direct) return direct + + const record = parseRecord(value) + if (!record) return null + + return parseLocale(record.locale) +} + +const base = i18n.flatten({ ...appEn, ...desktopEn }) + +function build(locale: Locale): Dictionary { + if (locale === "en") return base + if (locale === "zh") return { ...base, ...i18n.flatten(appZh), ...i18n.flatten(desktopZh) } + if (locale === "zht") return { ...base, ...i18n.flatten(appZht), ...i18n.flatten(desktopZht) } + if (locale === "de") return { ...base, ...i18n.flatten(appDe), ...i18n.flatten(desktopDe) } + if (locale === "es") return { ...base, ...i18n.flatten(appEs), ...i18n.flatten(desktopEs) } + if (locale === "fr") return { ...base, ...i18n.flatten(appFr), ...i18n.flatten(desktopFr) } + if (locale === "da") return { ...base, ...i18n.flatten(appDa), ...i18n.flatten(desktopDa) } + if (locale === "ja") return { ...base, ...i18n.flatten(appJa), ...i18n.flatten(desktopJa) } + if (locale === "pl") return { ...base, ...i18n.flatten(appPl), ...i18n.flatten(desktopPl) } + if (locale === "ru") return { ...base, ...i18n.flatten(appRu), ...i18n.flatten(desktopRu) } + if (locale === "ar") return { ...base, ...i18n.flatten(appAr), ...i18n.flatten(desktopAr) } + if (locale === "no") return { ...base, ...i18n.flatten(appNo), ...i18n.flatten(desktopNo) } + if (locale === "br") return { ...base, ...i18n.flatten(appBr), ...i18n.flatten(desktopBr) } + if (locale === "bs") return { ...base, ...i18n.flatten(appBs), ...i18n.flatten(desktopBs) } + return { ...base, ...i18n.flatten(appKo), ...i18n.flatten(desktopKo) } +} + +const state = { + locale: detectLocale(), + dict: base as Dictionary, + init: undefined as Promise | undefined, +} + +state.dict = build(state.locale) + +const translate = i18n.translator(() => state.dict, i18n.resolveTemplate) + +export function t(key: keyof Dictionary, params?: Record) { + return translate(key, params) +} + +export function initI18n(): Promise { + const cached = state.init + if (cached) return cached + + const promise = (async () => { + const raw = await window.api.storeGet("opencode.global.dat", "language").catch(() => null) + const value = parseStored(raw) + const next = pickLocale(value) ?? state.locale + + state.locale = next + state.dict = build(next) + return next + })().catch(() => state.locale) + + state.init = promise + return promise +} diff --git a/packages/desktop-electron/src/renderer/i18n/ja.ts b/packages/desktop-electron/src/renderer/i18n/ja.ts new file mode 100644 index 0000000000..fc485c6f40 --- /dev/null +++ b/packages/desktop-electron/src/renderer/i18n/ja.ts @@ -0,0 +1,28 @@ +export const dict = { + "desktop.menu.checkForUpdates": "アップデートを確認...", + "desktop.menu.installCli": "CLI をインストール...", + "desktop.menu.reloadWebview": "Webview を再読み込み", + "desktop.menu.restart": "再起動", + + "desktop.dialog.chooseFolder": "フォルダーを選択", + "desktop.dialog.chooseFile": "ファイルを選択", + "desktop.dialog.saveFile": "ファイルを保存", + + "desktop.updater.checkFailed.title": "アップデートの確認に失敗しました", + "desktop.updater.checkFailed.message": "アップデートを確認できませんでした", + "desktop.updater.none.title": "利用可能なアップデートはありません", + "desktop.updater.none.message": "すでに最新バージョンの OpenCode を使用しています", + "desktop.updater.downloadFailed.title": "アップデートに失敗しました", + "desktop.updater.downloadFailed.message": "アップデートをダウンロードできませんでした", + "desktop.updater.downloaded.title": "アップデートをダウンロードしました", + "desktop.updater.downloaded.prompt": + "OpenCode のバージョン {{version}} がダウンロードされました。インストールして再起動しますか?", + "desktop.updater.installFailed.title": "アップデートに失敗しました", + "desktop.updater.installFailed.message": "アップデートをインストールできませんでした", + + "desktop.cli.installed.title": "CLI をインストールしました", + "desktop.cli.installed.message": + "CLI を {{path}} にインストールしました\n\nターミナルを再起動して 'opencode' コマンドを使用してください。", + "desktop.cli.failed.title": "インストールに失敗しました", + "desktop.cli.failed.message": "CLI のインストールに失敗しました: {{error}}", +} diff --git a/packages/desktop-electron/src/renderer/i18n/ko.ts b/packages/desktop-electron/src/renderer/i18n/ko.ts new file mode 100644 index 0000000000..be27cec86a --- /dev/null +++ b/packages/desktop-electron/src/renderer/i18n/ko.ts @@ -0,0 +1,27 @@ +export const dict = { + "desktop.menu.checkForUpdates": "업데이트 확인...", + "desktop.menu.installCli": "CLI 설치...", + "desktop.menu.reloadWebview": "Webview 새로고침", + "desktop.menu.restart": "다시 시작", + + "desktop.dialog.chooseFolder": "폴더 선택", + "desktop.dialog.chooseFile": "파일 선택", + "desktop.dialog.saveFile": "파일 저장", + + "desktop.updater.checkFailed.title": "업데이트 확인 실패", + "desktop.updater.checkFailed.message": "업데이트를 확인하지 못했습니다", + "desktop.updater.none.title": "사용 가능한 업데이트 없음", + "desktop.updater.none.message": "이미 최신 버전의 OpenCode를 사용하고 있습니다", + "desktop.updater.downloadFailed.title": "업데이트 실패", + "desktop.updater.downloadFailed.message": "업데이트를 다운로드하지 못했습니다", + "desktop.updater.downloaded.title": "업데이트 다운로드 완료", + "desktop.updater.downloaded.prompt": "OpenCode {{version}} 버전을 다운로드했습니다. 설치하고 다시 실행할까요?", + "desktop.updater.installFailed.title": "업데이트 실패", + "desktop.updater.installFailed.message": "업데이트를 설치하지 못했습니다", + + "desktop.cli.installed.title": "CLI 설치됨", + "desktop.cli.installed.message": + "CLI가 {{path}}에 설치되었습니다\n\n터미널을 다시 시작하여 'opencode' 명령을 사용하세요.", + "desktop.cli.failed.title": "설치 실패", + "desktop.cli.failed.message": "CLI 설치 실패: {{error}}", +} diff --git a/packages/desktop-electron/src/renderer/i18n/no.ts b/packages/desktop-electron/src/renderer/i18n/no.ts new file mode 100644 index 0000000000..e39bd7f3b4 --- /dev/null +++ b/packages/desktop-electron/src/renderer/i18n/no.ts @@ -0,0 +1,28 @@ +export const dict = { + "desktop.menu.checkForUpdates": "Se etter oppdateringer...", + "desktop.menu.installCli": "Installer CLI...", + "desktop.menu.reloadWebview": "Last inn Webview på nytt", + "desktop.menu.restart": "Start på nytt", + + "desktop.dialog.chooseFolder": "Velg en mappe", + "desktop.dialog.chooseFile": "Velg en fil", + "desktop.dialog.saveFile": "Lagre fil", + + "desktop.updater.checkFailed.title": "Oppdateringssjekk mislyktes", + "desktop.updater.checkFailed.message": "Kunne ikke se etter oppdateringer", + "desktop.updater.none.title": "Ingen oppdatering tilgjengelig", + "desktop.updater.none.message": "Du bruker allerede den nyeste versjonen av OpenCode", + "desktop.updater.downloadFailed.title": "Oppdatering mislyktes", + "desktop.updater.downloadFailed.message": "Kunne ikke laste ned oppdateringen", + "desktop.updater.downloaded.title": "Oppdatering lastet ned", + "desktop.updater.downloaded.prompt": + "Versjon {{version}} av OpenCode er lastet ned. Vil du installere den og starte på nytt?", + "desktop.updater.installFailed.title": "Oppdatering mislyktes", + "desktop.updater.installFailed.message": "Kunne ikke installere oppdateringen", + + "desktop.cli.installed.title": "CLI installert", + "desktop.cli.installed.message": + "CLI installert til {{path}}\n\nStart terminalen på nytt for å bruke 'opencode'-kommandoen.", + "desktop.cli.failed.title": "Installasjon mislyktes", + "desktop.cli.failed.message": "Kunne ikke installere CLI: {{error}}", +} diff --git a/packages/desktop-electron/src/renderer/i18n/pl.ts b/packages/desktop-electron/src/renderer/i18n/pl.ts new file mode 100644 index 0000000000..d3ad7ce64f --- /dev/null +++ b/packages/desktop-electron/src/renderer/i18n/pl.ts @@ -0,0 +1,28 @@ +export const dict = { + "desktop.menu.checkForUpdates": "Sprawdź aktualizacje...", + "desktop.menu.installCli": "Zainstaluj CLI...", + "desktop.menu.reloadWebview": "Przeładuj Webview", + "desktop.menu.restart": "Restartuj", + + "desktop.dialog.chooseFolder": "Wybierz folder", + "desktop.dialog.chooseFile": "Wybierz plik", + "desktop.dialog.saveFile": "Zapisz plik", + + "desktop.updater.checkFailed.title": "Nie udało się sprawdzić aktualizacji", + "desktop.updater.checkFailed.message": "Nie udało się sprawdzić aktualizacji", + "desktop.updater.none.title": "Brak dostępnych aktualizacji", + "desktop.updater.none.message": "Korzystasz już z najnowszej wersji OpenCode", + "desktop.updater.downloadFailed.title": "Aktualizacja nie powiodła się", + "desktop.updater.downloadFailed.message": "Nie udało się pobrać aktualizacji", + "desktop.updater.downloaded.title": "Aktualizacja pobrana", + "desktop.updater.downloaded.prompt": + "Pobrano wersję {{version}} OpenCode. Czy chcesz ją zainstalować i uruchomić ponownie?", + "desktop.updater.installFailed.title": "Aktualizacja nie powiodła się", + "desktop.updater.installFailed.message": "Nie udało się zainstalować aktualizacji", + + "desktop.cli.installed.title": "CLI zainstalowane", + "desktop.cli.installed.message": + "CLI zainstalowane w {{path}}\n\nUruchom ponownie terminal, aby użyć polecenia 'opencode'.", + "desktop.cli.failed.title": "Instalacja nie powiodła się", + "desktop.cli.failed.message": "Nie udało się zainstalować CLI: {{error}}", +} diff --git a/packages/desktop-electron/src/renderer/i18n/ru.ts b/packages/desktop-electron/src/renderer/i18n/ru.ts new file mode 100644 index 0000000000..8e09cc45b4 --- /dev/null +++ b/packages/desktop-electron/src/renderer/i18n/ru.ts @@ -0,0 +1,27 @@ +export const dict = { + "desktop.menu.checkForUpdates": "Проверить обновления...", + "desktop.menu.installCli": "Установить CLI...", + "desktop.menu.reloadWebview": "Перезагрузить Webview", + "desktop.menu.restart": "Перезапустить", + + "desktop.dialog.chooseFolder": "Выберите папку", + "desktop.dialog.chooseFile": "Выберите файл", + "desktop.dialog.saveFile": "Сохранить файл", + + "desktop.updater.checkFailed.title": "Не удалось проверить обновления", + "desktop.updater.checkFailed.message": "Не удалось проверить обновления", + "desktop.updater.none.title": "Обновлений нет", + "desktop.updater.none.message": "Вы уже используете последнюю версию OpenCode", + "desktop.updater.downloadFailed.title": "Обновление не удалось", + "desktop.updater.downloadFailed.message": "Не удалось скачать обновление", + "desktop.updater.downloaded.title": "Обновление загружено", + "desktop.updater.downloaded.prompt": "Версия OpenCode {{version}} загружена. Хотите установить и перезапустить?", + "desktop.updater.installFailed.title": "Обновление не удалось", + "desktop.updater.installFailed.message": "Не удалось установить обновление", + + "desktop.cli.installed.title": "CLI установлен", + "desktop.cli.installed.message": + "CLI установлен в {{path}}\n\nПерезапустите терминал, чтобы использовать команду 'opencode'.", + "desktop.cli.failed.title": "Ошибка установки", + "desktop.cli.failed.message": "Не удалось установить CLI: {{error}}", +} diff --git a/packages/desktop-electron/src/renderer/i18n/zh.ts b/packages/desktop-electron/src/renderer/i18n/zh.ts new file mode 100644 index 0000000000..aeb3a54e03 --- /dev/null +++ b/packages/desktop-electron/src/renderer/i18n/zh.ts @@ -0,0 +1,26 @@ +export const dict = { + "desktop.menu.checkForUpdates": "检查更新...", + "desktop.menu.installCli": "安装 CLI...", + "desktop.menu.reloadWebview": "重新加载 Webview", + "desktop.menu.restart": "重启", + + "desktop.dialog.chooseFolder": "选择文件夹", + "desktop.dialog.chooseFile": "选择文件", + "desktop.dialog.saveFile": "保存文件", + + "desktop.updater.checkFailed.title": "检查更新失败", + "desktop.updater.checkFailed.message": "无法检查更新", + "desktop.updater.none.title": "没有可用更新", + "desktop.updater.none.message": "你已经在使用最新版本的 OpenCode", + "desktop.updater.downloadFailed.title": "更新失败", + "desktop.updater.downloadFailed.message": "无法下载更新", + "desktop.updater.downloaded.title": "更新已下载", + "desktop.updater.downloaded.prompt": "已下载 OpenCode {{version}} 版本,是否安装并重启?", + "desktop.updater.installFailed.title": "更新失败", + "desktop.updater.installFailed.message": "无法安装更新", + + "desktop.cli.installed.title": "CLI 已安装", + "desktop.cli.installed.message": "CLI 已安装到 {{path}}\n\n重启终端以使用 'opencode' 命令。", + "desktop.cli.failed.title": "安装失败", + "desktop.cli.failed.message": "无法安装 CLI: {{error}}", +} diff --git a/packages/desktop-electron/src/renderer/i18n/zht.ts b/packages/desktop-electron/src/renderer/i18n/zht.ts new file mode 100644 index 0000000000..7fd677aca4 --- /dev/null +++ b/packages/desktop-electron/src/renderer/i18n/zht.ts @@ -0,0 +1,26 @@ +export const dict = { + "desktop.menu.checkForUpdates": "檢查更新...", + "desktop.menu.installCli": "安裝 CLI...", + "desktop.menu.reloadWebview": "重新載入 Webview", + "desktop.menu.restart": "重新啟動", + + "desktop.dialog.chooseFolder": "選擇資料夾", + "desktop.dialog.chooseFile": "選擇檔案", + "desktop.dialog.saveFile": "儲存檔案", + + "desktop.updater.checkFailed.title": "檢查更新失敗", + "desktop.updater.checkFailed.message": "無法檢查更新", + "desktop.updater.none.title": "沒有可用更新", + "desktop.updater.none.message": "你已在使用最新版的 OpenCode", + "desktop.updater.downloadFailed.title": "更新失敗", + "desktop.updater.downloadFailed.message": "無法下載更新", + "desktop.updater.downloaded.title": "更新已下載", + "desktop.updater.downloaded.prompt": "已下載 OpenCode {{version}} 版本,是否安裝並重新啟動?", + "desktop.updater.installFailed.title": "更新失敗", + "desktop.updater.installFailed.message": "無法安裝更新", + + "desktop.cli.installed.title": "CLI 已安裝", + "desktop.cli.installed.message": "CLI 已安裝到 {{path}}\n\n重新啟動終端機以使用 'opencode' 命令。", + "desktop.cli.failed.title": "安裝失敗", + "desktop.cli.failed.message": "無法安裝 CLI: {{error}}", +} diff --git a/packages/desktop-electron/src/renderer/index.html b/packages/desktop-electron/src/renderer/index.html new file mode 100644 index 0000000000..1756408196 --- /dev/null +++ b/packages/desktop-electron/src/renderer/index.html @@ -0,0 +1,23 @@ + + + + + + OpenCode + + + + + + + + + + + + + +
    + + + diff --git a/packages/desktop-electron/src/renderer/index.tsx b/packages/desktop-electron/src/renderer/index.tsx new file mode 100644 index 0000000000..b5193d626b --- /dev/null +++ b/packages/desktop-electron/src/renderer/index.tsx @@ -0,0 +1,312 @@ +// @refresh reload + +import { + AppBaseProviders, + AppInterface, + handleNotificationClick, + type Platform, + PlatformProvider, + ServerConnection, + useCommand, +} from "@opencode-ai/app" +import { Splash } from "@opencode-ai/ui/logo" +import type { AsyncStorage } from "@solid-primitives/storage" +import { type Accessor, createResource, type JSX, onCleanup, onMount, Show } from "solid-js" +import { render } from "solid-js/web" +import { MemoryRouter } from "@solidjs/router" +import pkg from "../../package.json" +import { initI18n, t } from "./i18n" +import { UPDATER_ENABLED } from "./updater" +import { webviewZoom } from "./webview-zoom" +import "./styles.css" +import type { ServerReadyData } from "../preload/types" + +const root = document.getElementById("root") +if (import.meta.env.DEV && !(root instanceof HTMLElement)) { + throw new Error(t("error.dev.rootNotFound")) +} + +void initI18n() + +const deepLinkEvent = "opencode:deep-link" + +const emitDeepLinks = (urls: string[]) => { + if (urls.length === 0) return + window.__OPENCODE__ ??= {} + const pending = window.__OPENCODE__.deepLinks ?? [] + window.__OPENCODE__.deepLinks = [...pending, ...urls] + window.dispatchEvent(new CustomEvent(deepLinkEvent, { detail: { urls } })) +} + +const listenForDeepLinks = () => { + const startUrls = window.__OPENCODE__?.deepLinks ?? [] + if (startUrls.length) emitDeepLinks(startUrls) + return window.api.onDeepLink((urls) => emitDeepLinks(urls)) +} + +const createPlatform = (): Platform => { + const os = (() => { + const ua = navigator.userAgent + if (ua.includes("Mac")) return "macos" + if (ua.includes("Windows")) return "windows" + if (ua.includes("Linux")) return "linux" + return undefined + })() + + const wslHome = async () => { + if (os !== "windows" || !window.__OPENCODE__?.wsl) return undefined + return window.api.wslPath("~", "windows").catch(() => undefined) + } + + const handleWslPicker = async (result: T | null): Promise => { + if (!result || !window.__OPENCODE__?.wsl) return result + if (Array.isArray(result)) { + return Promise.all(result.map((path) => window.api.wslPath(path, "linux").catch(() => path))) as any + } + return window.api.wslPath(result, "linux").catch(() => result) as any + } + + const storage = (() => { + const cache = new Map() + + const createStorage = (name: string) => { + const api: AsyncStorage = { + getItem: (key: string) => window.api.storeGet(name, key), + setItem: (key: string, value: string) => window.api.storeSet(name, key, value), + removeItem: (key: string) => window.api.storeDelete(name, key), + clear: () => window.api.storeClear(name), + key: async (index: number) => (await window.api.storeKeys(name))[index], + getLength: () => window.api.storeLength(name), + get length() { + return api.getLength() + }, + } + return api + } + + return (name = "default.dat") => { + const cached = cache.get(name) + if (cached) return cached + const api = createStorage(name) + cache.set(name, api) + return api + } + })() + + return { + platform: "desktop", + os, + version: pkg.version, + + async openDirectoryPickerDialog(opts) { + const defaultPath = await wslHome() + const result = await window.api.openDirectoryPicker({ + multiple: opts?.multiple ?? false, + title: opts?.title ?? t("desktop.dialog.chooseFolder"), + defaultPath, + }) + return await handleWslPicker(result) + }, + + async openFilePickerDialog(opts) { + const result = await window.api.openFilePicker({ + multiple: opts?.multiple ?? false, + title: opts?.title ?? t("desktop.dialog.chooseFile"), + }) + return handleWslPicker(result) + }, + + async saveFilePickerDialog(opts) { + const result = await window.api.saveFilePicker({ + title: opts?.title ?? t("desktop.dialog.saveFile"), + defaultPath: opts?.defaultPath, + }) + return handleWslPicker(result) + }, + + openLink(url: string) { + window.api.openLink(url) + }, + async openPath(path: string, app?: string) { + if (os === "windows") { + const resolvedApp = app ? await window.api.resolveAppPath(app).catch(() => null) : null + const resolvedPath = await (async () => { + if (window.__OPENCODE__?.wsl) { + const converted = await window.api.wslPath(path, "windows").catch(() => null) + if (converted) return converted + } + return path + })() + return window.api.openPath(resolvedPath, resolvedApp ?? undefined) + } + return window.api.openPath(path, app) + }, + + back() { + window.history.back() + }, + + forward() { + window.history.forward() + }, + + storage, + + checkUpdate: async () => { + if (!UPDATER_ENABLED) return { updateAvailable: false } + return window.api.checkUpdate() + }, + + update: async () => { + if (!UPDATER_ENABLED) return + await window.api.installUpdate() + }, + + restart: async () => { + await window.api.killSidecar().catch(() => undefined) + window.api.relaunch() + }, + + notify: async (title, description, href) => { + const focused = await window.api.getWindowFocused().catch(() => document.hasFocus()) + if (focused) return + + const notification = new Notification(title, { + body: description ?? "", + icon: "https://opencode.ai/favicon-96x96-v3.png", + }) + notification.onclick = () => { + void window.api.showWindow() + void window.api.setWindowFocus() + handleNotificationClick(href) + notification.close() + } + }, + + fetch: (input, init) => { + if (input instanceof Request) return fetch(input) + return fetch(input, init) + }, + + getWslEnabled: async () => { + const next = await window.api.getWslConfig().catch(() => null) + if (next) return next.enabled + return window.__OPENCODE__!.wsl ?? false + }, + + setWslEnabled: async (enabled) => { + await window.api.setWslConfig({ enabled }) + }, + + getDefaultServerUrl: async () => { + return window.api.getDefaultServerUrl().catch(() => null) + }, + + setDefaultServerUrl: async (url: string | null) => { + await window.api.setDefaultServerUrl(url) + }, + + getDisplayBackend: async () => { + return window.api.getDisplayBackend().catch(() => null) + }, + + setDisplayBackend: async (backend) => { + await window.api.setDisplayBackend(backend) + }, + + parseMarkdown: (markdown: string) => window.api.parseMarkdownCommand(markdown), + + webviewZoom, + + checkAppExists: async (appName: string) => { + return window.api.checkAppExists(appName) + }, + + async readClipboardImage() { + const image = await window.api.readClipboardImage().catch(() => null) + if (!image) return null + const blob = new Blob([image.buffer], { type: "image/png" }) + return new File([blob], `pasted-image-${Date.now()}.png`, { type: "image/png" }) + }, + } +} + +let menuTrigger = null as null | ((id: string) => void) +window.api.onMenuCommand((id) => { + menuTrigger?.(id) +}) +listenForDeepLinks() + +render(() => { + const platform = createPlatform() + + function handleClick(e: MouseEvent) { + const link = (e.target as HTMLElement).closest("a.external-link") as HTMLAnchorElement | null + if (link?.href) { + e.preventDefault() + platform.openLink(link.href) + } + } + + onMount(() => { + document.addEventListener("click", handleClick) + onCleanup(() => { + document.removeEventListener("click", handleClick) + }) + }) + + return ( + + + + {(data) => { + const server: ServerConnection.Sidecar = { + displayName: "Local Server", + type: "sidecar", + variant: "base", + http: { + url: data().url, + username: "opencode", + password: data().password ?? undefined, + }, + } + + function Inner() { + const cmd = useCommand() + + menuTrigger = (id) => cmd.trigger(id) + + return null + } + + return ( + + + + ) + }} + + + + ) +}, root!) + +// Gate component that waits for the server to be ready +function ServerGate(props: { children: (data: Accessor) => JSX.Element }) { + const [serverData] = createResource(() => window.api.awaitInitialization(() => undefined)) + console.log({ serverData }) + if (serverData.state === "errored") throw serverData.error + + return ( + + +
    + } + > + {(data) => props.children(data)} + + ) +} diff --git a/packages/desktop-electron/src/renderer/loading.html b/packages/desktop-electron/src/renderer/loading.html new file mode 100644 index 0000000000..8def243b49 --- /dev/null +++ b/packages/desktop-electron/src/renderer/loading.html @@ -0,0 +1,23 @@ + + + + + + OpenCode + + + + + + + + + + + + + +
    + + + diff --git a/packages/desktop-electron/src/renderer/loading.tsx b/packages/desktop-electron/src/renderer/loading.tsx new file mode 100644 index 0000000000..1659503529 --- /dev/null +++ b/packages/desktop-electron/src/renderer/loading.tsx @@ -0,0 +1,80 @@ +import { render } from "solid-js/web" +import { MetaProvider } from "@solidjs/meta" +import "@opencode-ai/app/index.css" +import { Font } from "@opencode-ai/ui/font" +import { Splash } from "@opencode-ai/ui/logo" +import { Progress } from "@opencode-ai/ui/progress" +import "./styles.css" +import { createEffect, createMemo, createSignal, onCleanup, onMount } from "solid-js" +import type { InitStep, SqliteMigrationProgress } from "../preload/types" + +const root = document.getElementById("root")! +const lines = ["Just a moment...", "Migrating your database", "This may take a couple of minutes"] +const delays = [3000, 9000] + +render(() => { + const [step, setStep] = createSignal(null) + const [line, setLine] = createSignal(0) + const [percent, setPercent] = createSignal(0) + + const phase = createMemo(() => step()?.phase) + + const value = createMemo(() => { + if (phase() === "done") return 100 + return Math.max(25, Math.min(100, percent())) + }) + + window.api.awaitInitialization((next) => setStep(next as InitStep)).catch(() => undefined) + + onMount(() => { + setLine(0) + setPercent(0) + + const timers = delays.map((ms, i) => setTimeout(() => setLine(i + 1), ms)) + + const listener = window.api.onSqliteMigrationProgress((progress: SqliteMigrationProgress) => { + if (progress.type === "InProgress") setPercent(Math.max(0, Math.min(100, progress.value))) + if (progress.type === "Done") setPercent(100) + }) + + onCleanup(() => { + listener() + timers.forEach(clearTimeout) + }) + }) + + createEffect(() => { + if (phase() !== "done") return + + const timer = setTimeout(() => window.api.loadingWindowComplete(), 1000) + onCleanup(() => clearTimeout(timer)) + }) + + const status = createMemo(() => { + if (phase() === "done") return "All done" + if (phase() === "sqlite_waiting") return lines[line()] + return "Just a moment..." + }) + + return ( + +
    + +
    + +
    + + {status()} + + `${Math.round(value)}%`} + /> +
    +
    +
    +
    + ) +}, root) diff --git a/packages/desktop-electron/src/renderer/styles.css b/packages/desktop-electron/src/renderer/styles.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/desktop-electron/src/renderer/updater.ts b/packages/desktop-electron/src/renderer/updater.ts new file mode 100644 index 0000000000..fe9e601db8 --- /dev/null +++ b/packages/desktop-electron/src/renderer/updater.ts @@ -0,0 +1,14 @@ +import { initI18n, t } from "./i18n" + +export const UPDATER_ENABLED = window.__OPENCODE__?.updaterEnabled ?? false + +export async function runUpdater({ alertOnFail }: { alertOnFail: boolean }) { + await initI18n() + try { + await window.api.runUpdater(alertOnFail) + } catch { + if (alertOnFail) { + window.alert(t("desktop.updater.checkFailed.message")) + } + } +} diff --git a/packages/desktop-electron/src/renderer/webview-zoom.ts b/packages/desktop-electron/src/renderer/webview-zoom.ts new file mode 100644 index 0000000000..9c0a3a3a35 --- /dev/null +++ b/packages/desktop-electron/src/renderer/webview-zoom.ts @@ -0,0 +1,38 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +import { createSignal } from "solid-js" + +const OS_NAME = (() => { + if (navigator.userAgent.includes("Mac")) return "macos" + if (navigator.userAgent.includes("Windows")) return "windows" + if (navigator.userAgent.includes("Linux")) return "linux" + return "unknown" +})() + +const [webviewZoom, setWebviewZoom] = createSignal(1) + +const MAX_ZOOM_LEVEL = 10 +const MIN_ZOOM_LEVEL = 0.2 + +const clamp = (value: number) => Math.min(Math.max(value, MIN_ZOOM_LEVEL), MAX_ZOOM_LEVEL) + +const applyZoom = (next: number) => { + setWebviewZoom(next) + void window.api.setZoomFactor(next) +} + +window.addEventListener("keydown", (event) => { + if (!(OS_NAME === "macos" ? event.metaKey : event.ctrlKey)) return + + let newZoom = webviewZoom() + + if (event.key === "-") newZoom -= 0.2 + if (event.key === "=" || event.key === "+") newZoom += 0.2 + if (event.key === "0") newZoom = 1 + + applyZoom(clamp(newZoom)) +}) + +export { webviewZoom } diff --git a/packages/desktop-electron/sst-env.d.ts b/packages/desktop-electron/sst-env.d.ts new file mode 100644 index 0000000000..64441936d7 --- /dev/null +++ b/packages/desktop-electron/sst-env.d.ts @@ -0,0 +1,10 @@ +/* This file is auto-generated by SST. Do not edit. */ +/* tslint:disable */ +/* eslint-disable */ +/* deno-fmt-ignore-file */ +/* biome-ignore-all lint: auto-generated */ + +/// + +import "sst" +export {} \ No newline at end of file diff --git a/packages/desktop-electron/tsconfig.json b/packages/desktop-electron/tsconfig.json new file mode 100644 index 0000000000..160f6c3fd2 --- /dev/null +++ b/packages/desktop-electron/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "target": "ESNext", + "module": "ESNext", + "skipLibCheck": true, + "moduleResolution": "bundler", + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + "allowJs": true, + "resolveJsonModule": true, + "strict": true, + "isolatedModules": true, + "noEmit": true, + "emitDeclarationOnly": false, + "outDir": "node_modules/.ts-dist", + "types": ["vite/client", "node", "electron"] + }, + "references": [{ "path": "../app" }], + "include": ["src", "package.json"] +} diff --git a/packages/desktop/README.md b/packages/desktop/README.md index ebaf488223..358b7d24d5 100644 --- a/packages/desktop/README.md +++ b/packages/desktop/README.md @@ -2,6 +2,10 @@ Native OpenCode desktop app, built with Tauri v2. +## Prerequisites + +Building the desktop app requires additional Tauri dependencies (Rust toolchain, platform-specific libraries). See the [Tauri prerequisites](https://v2.tauri.app/start/prerequisites/) for setup instructions. + ## Development From the repo root: @@ -11,22 +15,18 @@ bun install bun run --cwd packages/desktop tauri dev ``` -This starts the Vite dev server on http://localhost:1420 and opens the native window. - -If you only want the web dev server (no native shell): - -```bash -bun run --cwd packages/desktop dev -``` - ## Build -To create a production `dist/` and build the native app bundle: - ```bash bun run --cwd packages/desktop tauri build ``` -## Prerequisites +## Troubleshooting -Running the desktop app requires additional Tauri dependencies (Rust toolchain, platform-specific libraries). See the [Tauri prerequisites](https://v2.tauri.app/start/prerequisites/) for setup instructions. +### Rust compiler not found + +If you see errors about Rust not being found, install it via [rustup](https://rustup.rs/): + +```bash +curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh +``` diff --git a/packages/desktop/package.json b/packages/desktop/package.json index dc25cb0203..b028c840ba 100644 --- a/packages/desktop/package.json +++ b/packages/desktop/package.json @@ -1,7 +1,7 @@ { "name": "@opencode-ai/desktop", "private": true, - "version": "1.2.10", + "version": "1.2.24", "type": "module", "license": "MIT", "scripts": { diff --git a/packages/desktop/scripts/finalize-latest-json.ts b/packages/desktop/scripts/finalize-latest-json.ts new file mode 100644 index 0000000000..5445e0640d --- /dev/null +++ b/packages/desktop/scripts/finalize-latest-json.ts @@ -0,0 +1,159 @@ +#!/usr/bin/env bun + +import { Buffer } from "node:buffer" +import { $ } from "bun" + +const { values } = parseArgs({ + args: Bun.argv.slice(2), + options: { + "dry-run": { type: "boolean", default: false }, + }, +}) + +const dryRun = values["dry-run"] + +import { parseArgs } from "node:util" + +const repo = process.env.GH_REPO +if (!repo) throw new Error("GH_REPO is required") + +const releaseId = process.env.OPENCODE_RELEASE +if (!releaseId) throw new Error("OPENCODE_RELEASE is required") + +const version = process.env.OPENCODE_VERSION +if (!releaseId) throw new Error("OPENCODE_VERSION is required") + +const token = process.env.GH_TOKEN ?? process.env.GITHUB_TOKEN +if (!token) throw new Error("GH_TOKEN or GITHUB_TOKEN is required") + +const apiHeaders = { + Authorization: `token ${token}`, + Accept: "application/vnd.github+json", +} + +const releaseRes = await fetch(`https://api.github.com/repos/${repo}/releases/${releaseId}`, { + headers: apiHeaders, +}) + +if (!releaseRes.ok) { + throw new Error(`Failed to fetch release: ${releaseRes.status} ${releaseRes.statusText}`) +} + +type Asset = { + name: string + url: string +} + +type Release = { + tag_name?: string + assets?: Asset[] +} + +const release = (await releaseRes.json()) as Release +const assets = release.assets ?? [] +const assetByName = new Map(assets.map((asset) => [asset.name, asset])) + +const latestAsset = assetByName.get("latest.json") +if (!latestAsset) throw new Error("latest.json asset not found") + +const latestRes = await fetch(latestAsset.url, { + headers: { + Authorization: `token ${token}`, + Accept: "application/octet-stream", + }, +}) + +if (!latestRes.ok) { + throw new Error(`Failed to fetch latest.json: ${latestRes.status} ${latestRes.statusText}`) +} + +const latestText = new TextDecoder().decode(await latestRes.arrayBuffer()) +const latest = JSON.parse(latestText) +const base = { ...latest } +delete base.platforms + +const fetchSignature = async (asset: Asset) => { + const res = await fetch(asset.url, { + headers: { + Authorization: `token ${token}`, + Accept: "application/octet-stream", + }, + }) + + if (!res.ok) { + throw new Error(`Failed to fetch signature: ${res.status} ${res.statusText}`) + } + + return Buffer.from(await res.arrayBuffer()).toString() +} + +const entries: Record = {} +const add = (key: string, asset: Asset, signature: string) => { + if (entries[key]) return + entries[key] = { + url: `https://github.com/${repo}/releases/download/v${version}/${asset.name}`, + signature, + } +} + +const targets = [ + { key: "linux-x86_64-deb", asset: "opencode-desktop-linux-amd64.deb" }, + { key: "linux-x86_64-rpm", asset: "opencode-desktop-linux-x86_64.rpm" }, + { key: "linux-aarch64-deb", asset: "opencode-desktop-linux-arm64.deb" }, + { key: "linux-aarch64-rpm", asset: "opencode-desktop-linux-aarch64.rpm" }, + { key: "windows-x86_64-nsis", asset: "opencode-desktop-windows-x64.exe" }, + { key: "darwin-x86_64-app", asset: "opencode-desktop-darwin-x64.app.tar.gz" }, + { + key: "darwin-aarch64-app", + asset: "opencode-desktop-darwin-aarch64.app.tar.gz", + }, +] + +for (const target of targets) { + const asset = assetByName.get(target.asset) + if (!asset) continue + + const sig = assetByName.get(`${target.asset}.sig`) + if (!sig) continue + + const signature = await fetchSignature(sig) + add(target.key, asset, signature) +} + +const alias = (key: string, source: string) => { + if (entries[key]) return + const entry = entries[source] + if (!entry) return + entries[key] = entry +} + +alias("linux-x86_64", "linux-x86_64-deb") +alias("linux-aarch64", "linux-aarch64-deb") +alias("windows-x86_64", "windows-x86_64-nsis") +alias("darwin-x86_64", "darwin-x86_64-app") +alias("darwin-aarch64", "darwin-aarch64-app") + +const platforms = Object.fromEntries( + Object.keys(entries) + .sort() + .map((key) => [key, entries[key]]), +) +const output = { + ...base, + platforms, +} + +const dir = process.env.RUNNER_TEMP ?? "/tmp" +const file = `${dir}/latest.json` +await Bun.write(file, JSON.stringify(output, null, 2)) + +const tag = release.tag_name +if (!tag) throw new Error("Release tag not found") + +if (dryRun) { + console.log(`dry-run: wrote latest.json for ${tag} to ${file}`) + process.exit(0) +} +await $`gh release upload ${tag} ${file} --clobber --repo ${repo}` + +console.log(`finalized latest.json for ${tag}`) diff --git a/packages/desktop/src-tauri/Cargo.lock b/packages/desktop/src-tauri/Cargo.lock index f9516350e1..55f0d5f360 100644 --- a/packages/desktop/src-tauri/Cargo.lock +++ b/packages/desktop/src-tauri/Cargo.lock @@ -1988,7 +1988,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core 0.62.2", + "windows-core 0.61.2", ] [[package]] @@ -3136,7 +3136,8 @@ dependencies = [ "tracing-subscriber", "uuid", "webkit2gtk", - "windows 0.62.2", + "windows-core 0.62.2", + "windows-sys 0.61.2", ] [[package]] diff --git a/packages/desktop/src-tauri/Cargo.toml b/packages/desktop/src-tauri/Cargo.toml index e98b8965c1..b228c7b616 100644 --- a/packages/desktop/src-tauri/Cargo.toml +++ b/packages/desktop/src-tauri/Cargo.toml @@ -55,7 +55,8 @@ tokio-stream = { version = "0.1.18", features = ["sync"] } process-wrap = { version = "9.0.3", features = ["tokio1"] } [target.'cfg(windows)'.dependencies] -windows = { version = "0.62", features = ["Win32_System_Threading"] } +windows-sys = { version = "0.61", features = ["Win32_System_Threading", "Win32_System_Registry"] } +windows-core = "0.62" [target.'cfg(target_os = "linux")'.dependencies] gtk = "0.18.2" diff --git a/packages/desktop/src-tauri/entitlements.plist b/packages/desktop/src-tauri/entitlements.plist index 61d6c38cef..b61dc02228 100644 --- a/packages/desktop/src-tauri/entitlements.plist +++ b/packages/desktop/src-tauri/entitlements.plist @@ -12,19 +12,7 @@ com.apple.security.cs.disable-library-validation - com.apple.security.automation.apple-events - com.apple.security.device.audio-input - com.apple.security.device.camera - - com.apple.security.personal-information.addressbook - - com.apple.security.personal-information.calendars - - com.apple.security.personal-information.location - - com.apple.security.personal-information.photos-library - diff --git a/packages/desktop/src-tauri/icons/README.md b/packages/desktop/src-tauri/icons/README.md index db86593cc3..fa219a77ef 100644 --- a/packages/desktop/src-tauri/icons/README.md +++ b/packages/desktop/src-tauri/icons/README.md @@ -3,8 +3,8 @@ Here's the process I've been using to create icons: - Save source image as `app-icon.png` in `packages/desktop` -- `cd` to `src-tauri` -- Run `bun tauri icons -o icons/{environment}` +- `cd` to `packages/desktop` +- Run `bun tauri icon -o src-tauri/icons/{environment}` - Use [Image2Icon](https://img2icnsapp.com/)'s 'Big Sur Icon' preset to generate an `icon.icns` file and place it in the appropriate icons folder The Image2Icon step is necessary as the `icon.icns` generated by `app-icon.png` does not apply the shadow/padding expected by macOS, diff --git a/packages/desktop/src-tauri/icons/beta/128x128.png b/packages/desktop/src-tauri/icons/beta/128x128.png new file mode 100644 index 0000000000..751e80f1fd Binary files /dev/null and b/packages/desktop/src-tauri/icons/beta/128x128.png differ diff --git a/packages/desktop/src-tauri/icons/beta/128x128@2x.png b/packages/desktop/src-tauri/icons/beta/128x128@2x.png new file mode 100644 index 0000000000..fe330df419 Binary files /dev/null and b/packages/desktop/src-tauri/icons/beta/128x128@2x.png differ diff --git a/packages/desktop/src-tauri/icons/beta/32x32.png b/packages/desktop/src-tauri/icons/beta/32x32.png new file mode 100644 index 0000000000..2703048eed Binary files /dev/null and b/packages/desktop/src-tauri/icons/beta/32x32.png differ diff --git a/packages/desktop/src-tauri/icons/beta/64x64.png b/packages/desktop/src-tauri/icons/beta/64x64.png new file mode 100644 index 0000000000..ecd7fe3142 Binary files /dev/null and b/packages/desktop/src-tauri/icons/beta/64x64.png differ diff --git a/packages/desktop/src-tauri/icons/beta/Square107x107Logo.png b/packages/desktop/src-tauri/icons/beta/Square107x107Logo.png new file mode 100644 index 0000000000..e6ea73f4da Binary files /dev/null and b/packages/desktop/src-tauri/icons/beta/Square107x107Logo.png differ diff --git a/packages/desktop/src-tauri/icons/beta/Square142x142Logo.png b/packages/desktop/src-tauri/icons/beta/Square142x142Logo.png new file mode 100644 index 0000000000..74ae729c42 Binary files /dev/null and b/packages/desktop/src-tauri/icons/beta/Square142x142Logo.png differ diff --git a/packages/desktop/src-tauri/icons/beta/Square150x150Logo.png b/packages/desktop/src-tauri/icons/beta/Square150x150Logo.png new file mode 100644 index 0000000000..0b109b8f4a Binary files /dev/null and b/packages/desktop/src-tauri/icons/beta/Square150x150Logo.png differ diff --git a/packages/desktop/src-tauri/icons/beta/Square284x284Logo.png b/packages/desktop/src-tauri/icons/beta/Square284x284Logo.png new file mode 100644 index 0000000000..0261ded42c Binary files /dev/null and b/packages/desktop/src-tauri/icons/beta/Square284x284Logo.png differ diff --git a/packages/desktop/src-tauri/icons/beta/Square30x30Logo.png b/packages/desktop/src-tauri/icons/beta/Square30x30Logo.png new file mode 100644 index 0000000000..34158f10a4 Binary files /dev/null and b/packages/desktop/src-tauri/icons/beta/Square30x30Logo.png differ diff --git a/packages/desktop/src-tauri/icons/beta/Square310x310Logo.png b/packages/desktop/src-tauri/icons/beta/Square310x310Logo.png new file mode 100644 index 0000000000..f18bfada4c Binary files /dev/null and b/packages/desktop/src-tauri/icons/beta/Square310x310Logo.png differ diff --git a/packages/desktop/src-tauri/icons/beta/Square44x44Logo.png b/packages/desktop/src-tauri/icons/beta/Square44x44Logo.png new file mode 100644 index 0000000000..6d1cc06c08 Binary files /dev/null and b/packages/desktop/src-tauri/icons/beta/Square44x44Logo.png differ diff --git a/packages/desktop/src-tauri/icons/beta/Square71x71Logo.png b/packages/desktop/src-tauri/icons/beta/Square71x71Logo.png new file mode 100644 index 0000000000..a26084dc2f Binary files /dev/null and b/packages/desktop/src-tauri/icons/beta/Square71x71Logo.png differ diff --git a/packages/desktop/src-tauri/icons/beta/Square89x89Logo.png b/packages/desktop/src-tauri/icons/beta/Square89x89Logo.png new file mode 100644 index 0000000000..58b0eb6053 Binary files /dev/null and b/packages/desktop/src-tauri/icons/beta/Square89x89Logo.png differ diff --git a/packages/desktop/src-tauri/icons/beta/StoreLogo.png b/packages/desktop/src-tauri/icons/beta/StoreLogo.png new file mode 100644 index 0000000000..648fd2114d Binary files /dev/null and b/packages/desktop/src-tauri/icons/beta/StoreLogo.png differ diff --git a/packages/desktop/src-tauri/icons/beta/android/mipmap-anydpi-v26/ic_launcher.xml b/packages/desktop/src-tauri/icons/beta/android/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000000..2ffbf24b68 --- /dev/null +++ b/packages/desktop/src-tauri/icons/beta/android/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/packages/desktop/src-tauri/icons/beta/android/mipmap-hdpi/ic_launcher.png b/packages/desktop/src-tauri/icons/beta/android/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000..39d1dd0d51 Binary files /dev/null and b/packages/desktop/src-tauri/icons/beta/android/mipmap-hdpi/ic_launcher.png differ diff --git a/packages/desktop/src-tauri/icons/beta/android/mipmap-hdpi/ic_launcher_foreground.png b/packages/desktop/src-tauri/icons/beta/android/mipmap-hdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000..84908e71c1 Binary files /dev/null and b/packages/desktop/src-tauri/icons/beta/android/mipmap-hdpi/ic_launcher_foreground.png differ diff --git a/packages/desktop/src-tauri/icons/beta/android/mipmap-hdpi/ic_launcher_round.png b/packages/desktop/src-tauri/icons/beta/android/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 0000000000..a6b8cb6162 Binary files /dev/null and b/packages/desktop/src-tauri/icons/beta/android/mipmap-hdpi/ic_launcher_round.png differ diff --git a/packages/desktop/src-tauri/icons/beta/android/mipmap-mdpi/ic_launcher.png b/packages/desktop/src-tauri/icons/beta/android/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000000..6522e0fba8 Binary files /dev/null and b/packages/desktop/src-tauri/icons/beta/android/mipmap-mdpi/ic_launcher.png differ diff --git a/packages/desktop/src-tauri/icons/beta/android/mipmap-mdpi/ic_launcher_foreground.png b/packages/desktop/src-tauri/icons/beta/android/mipmap-mdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000..b3449bd4f3 Binary files /dev/null and b/packages/desktop/src-tauri/icons/beta/android/mipmap-mdpi/ic_launcher_foreground.png differ diff --git a/packages/desktop/src-tauri/icons/beta/android/mipmap-mdpi/ic_launcher_round.png b/packages/desktop/src-tauri/icons/beta/android/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 0000000000..7aa97d8276 Binary files /dev/null and b/packages/desktop/src-tauri/icons/beta/android/mipmap-mdpi/ic_launcher_round.png differ diff --git a/packages/desktop/src-tauri/icons/beta/android/mipmap-xhdpi/ic_launcher.png b/packages/desktop/src-tauri/icons/beta/android/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000000..82bc9d22a6 Binary files /dev/null and b/packages/desktop/src-tauri/icons/beta/android/mipmap-xhdpi/ic_launcher.png differ diff --git a/packages/desktop/src-tauri/icons/beta/android/mipmap-xhdpi/ic_launcher_foreground.png b/packages/desktop/src-tauri/icons/beta/android/mipmap-xhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000..6b031ce851 Binary files /dev/null and b/packages/desktop/src-tauri/icons/beta/android/mipmap-xhdpi/ic_launcher_foreground.png differ diff --git a/packages/desktop/src-tauri/icons/beta/android/mipmap-xhdpi/ic_launcher_round.png b/packages/desktop/src-tauri/icons/beta/android/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 0000000000..34859de5ef Binary files /dev/null and b/packages/desktop/src-tauri/icons/beta/android/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/packages/desktop/src-tauri/icons/beta/android/mipmap-xxhdpi/ic_launcher.png b/packages/desktop/src-tauri/icons/beta/android/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000..4cdb71d62b Binary files /dev/null and b/packages/desktop/src-tauri/icons/beta/android/mipmap-xxhdpi/ic_launcher.png differ diff --git a/packages/desktop/src-tauri/icons/beta/android/mipmap-xxhdpi/ic_launcher_foreground.png b/packages/desktop/src-tauri/icons/beta/android/mipmap-xxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000..a64be6ada1 Binary files /dev/null and b/packages/desktop/src-tauri/icons/beta/android/mipmap-xxhdpi/ic_launcher_foreground.png differ diff --git a/packages/desktop/src-tauri/icons/beta/android/mipmap-xxhdpi/ic_launcher_round.png b/packages/desktop/src-tauri/icons/beta/android/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 0000000000..2de3c27342 Binary files /dev/null and b/packages/desktop/src-tauri/icons/beta/android/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/packages/desktop/src-tauri/icons/beta/android/mipmap-xxxhdpi/ic_launcher.png b/packages/desktop/src-tauri/icons/beta/android/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000000..0ead288664 Binary files /dev/null and b/packages/desktop/src-tauri/icons/beta/android/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/packages/desktop/src-tauri/icons/beta/android/mipmap-xxxhdpi/ic_launcher_foreground.png b/packages/desktop/src-tauri/icons/beta/android/mipmap-xxxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000..bdd1748258 Binary files /dev/null and b/packages/desktop/src-tauri/icons/beta/android/mipmap-xxxhdpi/ic_launcher_foreground.png differ diff --git a/packages/desktop/src-tauri/icons/beta/android/mipmap-xxxhdpi/ic_launcher_round.png b/packages/desktop/src-tauri/icons/beta/android/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 0000000000..69f74758ec Binary files /dev/null and b/packages/desktop/src-tauri/icons/beta/android/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/packages/desktop/src-tauri/icons/beta/android/values/ic_launcher_background.xml b/packages/desktop/src-tauri/icons/beta/android/values/ic_launcher_background.xml new file mode 100644 index 0000000000..ea9c223a6c --- /dev/null +++ b/packages/desktop/src-tauri/icons/beta/android/values/ic_launcher_background.xml @@ -0,0 +1,4 @@ + + + #fff + \ No newline at end of file diff --git a/packages/desktop/src-tauri/icons/beta/icon.icns b/packages/desktop/src-tauri/icons/beta/icon.icns new file mode 100644 index 0000000000..f98de5da88 Binary files /dev/null and b/packages/desktop/src-tauri/icons/beta/icon.icns differ diff --git a/packages/desktop/src-tauri/icons/beta/icon.ico b/packages/desktop/src-tauri/icons/beta/icon.ico new file mode 100644 index 0000000000..df8588c8e4 Binary files /dev/null and b/packages/desktop/src-tauri/icons/beta/icon.ico differ diff --git a/packages/desktop/src-tauri/icons/beta/icon.png b/packages/desktop/src-tauri/icons/beta/icon.png new file mode 100644 index 0000000000..5313049562 Binary files /dev/null and b/packages/desktop/src-tauri/icons/beta/icon.png differ diff --git a/packages/desktop/src-tauri/icons/beta/ios/AppIcon-20x20@1x.png b/packages/desktop/src-tauri/icons/beta/ios/AppIcon-20x20@1x.png new file mode 100644 index 0000000000..e8ebb28efe Binary files /dev/null and b/packages/desktop/src-tauri/icons/beta/ios/AppIcon-20x20@1x.png differ diff --git a/packages/desktop/src-tauri/icons/beta/ios/AppIcon-20x20@2x-1.png b/packages/desktop/src-tauri/icons/beta/ios/AppIcon-20x20@2x-1.png new file mode 100644 index 0000000000..50c8015dea Binary files /dev/null and b/packages/desktop/src-tauri/icons/beta/ios/AppIcon-20x20@2x-1.png differ diff --git a/packages/desktop/src-tauri/icons/beta/ios/AppIcon-20x20@2x.png b/packages/desktop/src-tauri/icons/beta/ios/AppIcon-20x20@2x.png new file mode 100644 index 0000000000..50c8015dea Binary files /dev/null and b/packages/desktop/src-tauri/icons/beta/ios/AppIcon-20x20@2x.png differ diff --git a/packages/desktop/src-tauri/icons/beta/ios/AppIcon-20x20@3x.png b/packages/desktop/src-tauri/icons/beta/ios/AppIcon-20x20@3x.png new file mode 100644 index 0000000000..6e290dbc68 Binary files /dev/null and b/packages/desktop/src-tauri/icons/beta/ios/AppIcon-20x20@3x.png differ diff --git a/packages/desktop/src-tauri/icons/beta/ios/AppIcon-29x29@1x.png b/packages/desktop/src-tauri/icons/beta/ios/AppIcon-29x29@1x.png new file mode 100644 index 0000000000..4ef554b4de Binary files /dev/null and b/packages/desktop/src-tauri/icons/beta/ios/AppIcon-29x29@1x.png differ diff --git a/packages/desktop/src-tauri/icons/beta/ios/AppIcon-29x29@2x-1.png b/packages/desktop/src-tauri/icons/beta/ios/AppIcon-29x29@2x-1.png new file mode 100644 index 0000000000..b9ddfd47c8 Binary files /dev/null and b/packages/desktop/src-tauri/icons/beta/ios/AppIcon-29x29@2x-1.png differ diff --git a/packages/desktop/src-tauri/icons/beta/ios/AppIcon-29x29@2x.png b/packages/desktop/src-tauri/icons/beta/ios/AppIcon-29x29@2x.png new file mode 100644 index 0000000000..b9ddfd47c8 Binary files /dev/null and b/packages/desktop/src-tauri/icons/beta/ios/AppIcon-29x29@2x.png differ diff --git a/packages/desktop/src-tauri/icons/beta/ios/AppIcon-29x29@3x.png b/packages/desktop/src-tauri/icons/beta/ios/AppIcon-29x29@3x.png new file mode 100644 index 0000000000..052322d682 Binary files /dev/null and b/packages/desktop/src-tauri/icons/beta/ios/AppIcon-29x29@3x.png differ diff --git a/packages/desktop/src-tauri/icons/beta/ios/AppIcon-40x40@1x.png b/packages/desktop/src-tauri/icons/beta/ios/AppIcon-40x40@1x.png new file mode 100644 index 0000000000..50c8015dea Binary files /dev/null and b/packages/desktop/src-tauri/icons/beta/ios/AppIcon-40x40@1x.png differ diff --git a/packages/desktop/src-tauri/icons/beta/ios/AppIcon-40x40@2x-1.png b/packages/desktop/src-tauri/icons/beta/ios/AppIcon-40x40@2x-1.png new file mode 100644 index 0000000000..9317b25001 Binary files /dev/null and b/packages/desktop/src-tauri/icons/beta/ios/AppIcon-40x40@2x-1.png differ diff --git a/packages/desktop/src-tauri/icons/beta/ios/AppIcon-40x40@2x.png b/packages/desktop/src-tauri/icons/beta/ios/AppIcon-40x40@2x.png new file mode 100644 index 0000000000..9317b25001 Binary files /dev/null and b/packages/desktop/src-tauri/icons/beta/ios/AppIcon-40x40@2x.png differ diff --git a/packages/desktop/src-tauri/icons/beta/ios/AppIcon-40x40@3x.png b/packages/desktop/src-tauri/icons/beta/ios/AppIcon-40x40@3x.png new file mode 100644 index 0000000000..6b921a17e3 Binary files /dev/null and b/packages/desktop/src-tauri/icons/beta/ios/AppIcon-40x40@3x.png differ diff --git a/packages/desktop/src-tauri/icons/beta/ios/AppIcon-512@2x.png b/packages/desktop/src-tauri/icons/beta/ios/AppIcon-512@2x.png new file mode 100644 index 0000000000..b83131d64b Binary files /dev/null and b/packages/desktop/src-tauri/icons/beta/ios/AppIcon-512@2x.png differ diff --git a/packages/desktop/src-tauri/icons/beta/ios/AppIcon-60x60@2x.png b/packages/desktop/src-tauri/icons/beta/ios/AppIcon-60x60@2x.png new file mode 100644 index 0000000000..6b921a17e3 Binary files /dev/null and b/packages/desktop/src-tauri/icons/beta/ios/AppIcon-60x60@2x.png differ diff --git a/packages/desktop/src-tauri/icons/beta/ios/AppIcon-60x60@3x.png b/packages/desktop/src-tauri/icons/beta/ios/AppIcon-60x60@3x.png new file mode 100644 index 0000000000..685004995c Binary files /dev/null and b/packages/desktop/src-tauri/icons/beta/ios/AppIcon-60x60@3x.png differ diff --git a/packages/desktop/src-tauri/icons/beta/ios/AppIcon-76x76@1x.png b/packages/desktop/src-tauri/icons/beta/ios/AppIcon-76x76@1x.png new file mode 100644 index 0000000000..1ffceb752a Binary files /dev/null and b/packages/desktop/src-tauri/icons/beta/ios/AppIcon-76x76@1x.png differ diff --git a/packages/desktop/src-tauri/icons/beta/ios/AppIcon-76x76@2x.png b/packages/desktop/src-tauri/icons/beta/ios/AppIcon-76x76@2x.png new file mode 100644 index 0000000000..81c4178c91 Binary files /dev/null and b/packages/desktop/src-tauri/icons/beta/ios/AppIcon-76x76@2x.png differ diff --git a/packages/desktop/src-tauri/icons/beta/ios/AppIcon-83.5x83.5@2x.png b/packages/desktop/src-tauri/icons/beta/ios/AppIcon-83.5x83.5@2x.png new file mode 100644 index 0000000000..d5453adffb Binary files /dev/null and b/packages/desktop/src-tauri/icons/beta/ios/AppIcon-83.5x83.5@2x.png differ diff --git a/packages/desktop/src-tauri/src/cli.rs b/packages/desktop/src-tauri/src/cli.rs index acab0fa703..97fdba144f 100644 --- a/packages/desktop/src-tauri/src/cli.rs +++ b/packages/desktop/src-tauri/src/cli.rs @@ -4,10 +4,13 @@ use process_wrap::tokio::CommandWrap; use process_wrap::tokio::ProcessGroup; #[cfg(windows)] use process_wrap::tokio::{CommandWrapper, JobObject, KillOnDrop}; +use std::collections::HashMap; #[cfg(unix)] use std::os::unix::process::ExitStatusExt; +use std::path::Path; +use std::process::Stdio; use std::sync::Arc; -use std::{process::Stdio, time::Duration}; +use std::time::{Duration, Instant}; use tauri::{AppHandle, Manager, path::BaseDirectory}; use tauri_specta::Event; use tokio::{ @@ -19,7 +22,7 @@ use tokio::{ use tokio_stream::wrappers::ReceiverStream; use tracing::Instrument; #[cfg(windows)] -use windows::Win32::System::Threading::{CREATE_NO_WINDOW, CREATE_SUSPENDED}; +use windows_sys::Win32::System::Threading::{CREATE_NO_WINDOW, CREATE_SUSPENDED}; use crate::server::get_wsl_config; @@ -32,13 +35,14 @@ struct WinCreationFlags; #[cfg(windows)] impl CommandWrapper for WinCreationFlags { fn pre_spawn(&mut self, command: &mut Command, _core: &CommandWrap) -> std::io::Result<()> { - command.creation_flags((CREATE_NO_WINDOW | CREATE_SUSPENDED).0); + command.creation_flags(CREATE_NO_WINDOW | CREATE_SUSPENDED); Ok(()) } } const CLI_INSTALL_DIR: &str = ".opencode/bin"; const CLI_BINARY_NAME: &str = "opencode"; +const SHELL_ENV_TIMEOUT: Duration = Duration::from_secs(5); #[derive(serde::Deserialize, Debug)] pub struct ServerConfig { @@ -232,6 +236,133 @@ fn shell_escape(input: &str) -> String { escaped } +fn parse_shell_env(stdout: &[u8]) -> HashMap { + String::from_utf8_lossy(stdout) + .split('\0') + .filter_map(|line| { + if line.is_empty() { + return None; + } + + let (key, value) = line.split_once('=')?; + if key.is_empty() { + return None; + } + + Some((key.to_string(), value.to_string())) + }) + .collect() +} + +fn command_output_with_timeout( + mut cmd: std::process::Command, + timeout: Duration, +) -> std::io::Result> { + let mut child = cmd.spawn()?; + let start = Instant::now(); + + loop { + if child.try_wait()?.is_some() { + return child.wait_with_output().map(Some); + } + + if start.elapsed() >= timeout { + let _ = child.kill(); + let _ = child.wait(); + return Ok(None); + } + + std::thread::sleep(Duration::from_millis(25)); + } +} + +enum ShellEnvProbe { + Loaded(HashMap), + Timeout, + Unavailable, +} + +fn probe_shell_env(shell: &str, mode: &str) -> ShellEnvProbe { + let mut cmd = std::process::Command::new(shell); + cmd.args([mode, "-c", "env -0"]); + cmd.stdin(Stdio::null()); + cmd.stdout(Stdio::piped()); + cmd.stderr(Stdio::null()); + let output = match command_output_with_timeout(cmd, SHELL_ENV_TIMEOUT) { + Ok(Some(output)) => output, + Ok(None) => return ShellEnvProbe::Timeout, + Err(error) => { + tracing::debug!(shell, mode, ?error, "Shell env probe failed"); + return ShellEnvProbe::Unavailable; + } + }; + if !output.status.success() { + tracing::debug!(shell, mode, "Shell env probe exited with non-zero status"); + return ShellEnvProbe::Unavailable; + } + let env = parse_shell_env(&output.stdout); + if env.is_empty() { + tracing::debug!(shell, mode, "Shell env probe returned empty env"); + return ShellEnvProbe::Unavailable; + } + + ShellEnvProbe::Loaded(env) +} + +fn is_nushell(shell: &str) -> bool { + let shell_name = Path::new(shell) + .file_name() + .and_then(|name| name.to_str()) + .unwrap_or(shell) + .to_ascii_lowercase(); + shell_name == "nu" || shell_name == "nu.exe" || shell.to_ascii_lowercase().ends_with("\\nu.exe") +} +fn load_shell_env(shell: &str) -> Option> { + if is_nushell(shell) { + tracing::debug!(shell, "Skipping shell env probe for nushell"); + return None; + } + + match probe_shell_env(shell, "-il") { + ShellEnvProbe::Loaded(env) => { + tracing::info!( + shell, + env_count = env.len(), + "Loaded shell environment with -il" + ); + return Some(env); + } + ShellEnvProbe::Timeout => { + tracing::warn!(shell, "Interactive shell env probe timed out"); + return None; + } + ShellEnvProbe::Unavailable => {} + } + + if let ShellEnvProbe::Loaded(env) = probe_shell_env(shell, "-l") { + tracing::info!( + shell, + env_count = env.len(), + "Loaded shell environment with -l" + ); + return Some(env); + } + tracing::warn!(shell, "Falling back to app environment"); + None +} + +fn merge_shell_env( + shell_env: Option>, + envs: Vec<(String, String)>, +) -> Vec<(String, String)> { + let mut merged = shell_env.unwrap_or_default(); + for (key, value) in envs { + merged.insert(key, value); + } + + merged.into_iter().collect() +} + pub fn spawn_command( app: &tauri::AppHandle, args: &str, @@ -312,6 +443,7 @@ pub fn spawn_command( } else { let sidecar = get_sidecar_path(app); let shell = get_user_shell(); + let envs = merge_shell_env(load_shell_env(&shell), envs); let line = if shell.ends_with("/nu") { format!("^\"{}\" {}", sidecar.display(), args) @@ -320,7 +452,7 @@ pub fn spawn_command( }; let mut cmd = Command::new(shell); - cmd.args(["-il", "-c", &line]); + cmd.args(["-l", "-c", &line]); for (key, value) in envs { cmd.env(key, value); @@ -556,3 +688,54 @@ async fn read_line CommandEvent + Send + Copy + 'static>( } } } + +#[cfg(test)] +mod tests { + use super::*; + use std::collections::HashMap; + + #[test] + fn parse_shell_env_supports_null_delimited_pairs() { + let env = parse_shell_env(b"PATH=/usr/bin:/bin\0FOO=bar=baz\0\0"); + + assert_eq!(env.get("PATH"), Some(&"/usr/bin:/bin".to_string())); + assert_eq!(env.get("FOO"), Some(&"bar=baz".to_string())); + } + + #[test] + fn parse_shell_env_ignores_invalid_entries() { + let env = parse_shell_env(b"INVALID\0=empty\0OK=1\0"); + + assert_eq!(env.len(), 1); + assert_eq!(env.get("OK"), Some(&"1".to_string())); + } + + #[test] + fn merge_shell_env_keeps_explicit_overrides() { + let mut shell_env = HashMap::new(); + shell_env.insert("PATH".to_string(), "/shell/path".to_string()); + shell_env.insert("HOME".to_string(), "/tmp/home".to_string()); + + let merged = merge_shell_env( + Some(shell_env), + vec![ + ("PATH".to_string(), "/desktop/path".to_string()), + ("OPENCODE_CLIENT".to_string(), "desktop".to_string()), + ], + ) + .into_iter() + .collect::>(); + + assert_eq!(merged.get("PATH"), Some(&"/desktop/path".to_string())); + assert_eq!(merged.get("HOME"), Some(&"/tmp/home".to_string())); + assert_eq!(merged.get("OPENCODE_CLIENT"), Some(&"desktop".to_string())); + } + + #[test] + fn is_nushell_handles_path_and_binary_name() { + assert!(is_nushell("nu")); + assert!(is_nushell("/opt/homebrew/bin/nu")); + assert!(is_nushell("C:\\Program Files\\nu.exe")); + assert!(!is_nushell("/bin/zsh")); + } +} diff --git a/packages/desktop/src-tauri/src/lib.rs b/packages/desktop/src-tauri/src/lib.rs index 7ea3aaa8a7..137692cdf7 100644 --- a/packages/desktop/src-tauri/src/lib.rs +++ b/packages/desktop/src-tauri/src/lib.rs @@ -6,6 +6,7 @@ pub mod linux_display; pub mod linux_windowing; mod logging; mod markdown; +mod os; mod server; mod window_customizer; mod windows; @@ -42,7 +43,7 @@ struct ServerReadyData { url: String, username: Option, password: Option, - is_sidecar: bool + is_sidecar: bool, } #[derive(Clone, Copy, serde::Serialize, specta::Type, Debug)] @@ -148,7 +149,7 @@ async fn await_initialization( fn check_app_exists(app_name: &str) -> bool { #[cfg(target_os = "windows")] { - check_windows_app(app_name) + os::windows::check_windows_app(app_name) } #[cfg(target_os = "macos")] @@ -162,156 +163,12 @@ fn check_app_exists(app_name: &str) -> bool { } } -#[cfg(target_os = "windows")] -fn check_windows_app(_app_name: &str) -> bool { - // Check if command exists in PATH, including .exe - return true; -} - -#[cfg(target_os = "windows")] -fn resolve_windows_app_path(app_name: &str) -> Option { - use std::path::{Path, PathBuf}; - - // Try to find the command using 'where' - let output = Command::new("where").arg(app_name).output().ok()?; - - if !output.status.success() { - return None; - } - - let paths = String::from_utf8_lossy(&output.stdout) - .lines() - .map(str::trim) - .filter(|line| !line.is_empty()) - .map(PathBuf::from) - .collect::>(); - - let has_ext = |path: &Path, ext: &str| { - path.extension() - .and_then(|v| v.to_str()) - .map(|v| v.eq_ignore_ascii_case(ext)) - .unwrap_or(false) - }; - - if let Some(path) = paths.iter().find(|path| has_ext(path, "exe")) { - return Some(path.to_string_lossy().to_string()); - } - - let resolve_cmd = |path: &Path| -> Option { - let content = std::fs::read_to_string(path).ok()?; - - for token in content.split('"') { - let lower = token.to_ascii_lowercase(); - if !lower.contains(".exe") { - continue; - } - - if let Some(index) = lower.find("%~dp0") { - let base = path.parent()?; - let suffix = &token[index + 5..]; - let mut resolved = PathBuf::from(base); - - for part in suffix.replace('/', "\\").split('\\') { - if part.is_empty() || part == "." { - continue; - } - if part == ".." { - let _ = resolved.pop(); - continue; - } - resolved.push(part); - } - - if resolved.exists() { - return Some(resolved.to_string_lossy().to_string()); - } - } - - let resolved = PathBuf::from(token); - if resolved.exists() { - return Some(resolved.to_string_lossy().to_string()); - } - } - - None - }; - - for path in &paths { - if has_ext(path, "cmd") || has_ext(path, "bat") { - if let Some(resolved) = resolve_cmd(path) { - return Some(resolved); - } - } - - if path.extension().is_none() { - let cmd = path.with_extension("cmd"); - if cmd.exists() { - if let Some(resolved) = resolve_cmd(&cmd) { - return Some(resolved); - } - } - - let bat = path.with_extension("bat"); - if bat.exists() { - if let Some(resolved) = resolve_cmd(&bat) { - return Some(resolved); - } - } - } - } - - let key = app_name - .chars() - .filter(|v| v.is_ascii_alphanumeric()) - .flat_map(|v| v.to_lowercase()) - .collect::(); - - if !key.is_empty() { - for path in &paths { - let dirs = [ - path.parent(), - path.parent().and_then(|dir| dir.parent()), - path.parent() - .and_then(|dir| dir.parent()) - .and_then(|dir| dir.parent()), - ]; - - for dir in dirs.into_iter().flatten() { - if let Ok(entries) = std::fs::read_dir(dir) { - for entry in entries.flatten() { - let candidate = entry.path(); - if !has_ext(&candidate, "exe") { - continue; - } - - let Some(stem) = candidate.file_stem().and_then(|v| v.to_str()) else { - continue; - }; - - let name = stem - .chars() - .filter(|v| v.is_ascii_alphanumeric()) - .flat_map(|v| v.to_lowercase()) - .collect::(); - - if name.contains(&key) || key.contains(&name) { - return Some(candidate.to_string_lossy().to_string()); - } - } - } - } - } - } - - paths.first().map(|path| path.to_string_lossy().to_string()) -} - #[tauri::command] #[specta::specta] fn resolve_app_path(app_name: &str) -> Option { #[cfg(target_os = "windows")] { - resolve_windows_app_path(app_name) + os::windows::resolve_windows_app_path(app_name) } #[cfg(not(target_os = "windows"))] @@ -322,6 +179,35 @@ fn resolve_app_path(app_name: &str) -> Option { } } +#[tauri::command] +#[specta::specta] +fn open_path(_app: AppHandle, path: String, app_name: Option) -> Result<(), String> { + #[cfg(target_os = "windows")] + { + let app_name = app_name.map(|v| os::windows::resolve_windows_app_path(&v).unwrap_or(v)); + let is_powershell = app_name.as_ref().is_some_and(|v| { + std::path::Path::new(v) + .file_name() + .and_then(|name| name.to_str()) + .is_some_and(|name| { + name.eq_ignore_ascii_case("powershell") + || name.eq_ignore_ascii_case("powershell.exe") + }) + }); + + if is_powershell { + return os::windows::open_in_powershell(path); + } + + return tauri_plugin_opener::open_path(path, app_name.as_deref()) + .map_err(|e| format!("Failed to open path: {e}")); + } + + #[cfg(not(target_os = "windows"))] + tauri_plugin_opener::open_path(path, app_name.as_deref()) + .map_err(|e| format!("Failed to open path: {e}")) +} + #[cfg(target_os = "macos")] fn check_macos_app(app_name: &str) -> bool { // Check common installation locations @@ -516,7 +402,8 @@ fn make_specta_builder() -> tauri_specta::Builder { markdown::parse_markdown_command, check_app_exists, wsl_path, - resolve_app_path + resolve_app_path, + open_path ]) .events(tauri_specta::collect_events![ LoadingWindowComplete, @@ -634,7 +521,12 @@ async fn initialize(app: AppHandle) { app.state::().set_child(Some(child)); - Ok(ServerReadyData { url, username,password, is_sidecar: true }) + Ok(ServerReadyData { + url, + username, + password, + is_sidecar: true, + }) } .map(move |res| { let _ = server_ready_tx.send(res); diff --git a/packages/desktop/src-tauri/src/os/mod.rs b/packages/desktop/src-tauri/src/os/mod.rs new file mode 100644 index 0000000000..8c36e53f77 --- /dev/null +++ b/packages/desktop/src-tauri/src/os/mod.rs @@ -0,0 +1,2 @@ +#[cfg(windows)] +pub mod windows; diff --git a/packages/desktop/src-tauri/src/os/windows.rs b/packages/desktop/src-tauri/src/os/windows.rs new file mode 100644 index 0000000000..a163c4aa7e --- /dev/null +++ b/packages/desktop/src-tauri/src/os/windows.rs @@ -0,0 +1,463 @@ +use std::{ + ffi::c_void, + os::windows::process::CommandExt, + path::{Path, PathBuf}, + process::Command, +}; +use windows_sys::Win32::{ + Foundation::ERROR_SUCCESS, + System::{ + Registry::{ + RegGetValueW, HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE, REG_EXPAND_SZ, REG_SZ, + RRF_RT_REG_EXPAND_SZ, RRF_RT_REG_SZ, + }, + Threading::{CREATE_NEW_CONSOLE, CREATE_NO_WINDOW}, + }, +}; + +pub fn check_windows_app(app_name: &str) -> bool { + resolve_windows_app_path(app_name).is_some() +} + +pub fn resolve_windows_app_path(app_name: &str) -> Option { + fn expand_env(value: &str) -> String { + let mut out = String::with_capacity(value.len()); + let mut index = 0; + + while let Some(start) = value[index..].find('%') { + let start = index + start; + out.push_str(&value[index..start]); + + let Some(end_rel) = value[start + 1..].find('%') else { + out.push_str(&value[start..]); + return out; + }; + + let end = start + 1 + end_rel; + let key = &value[start + 1..end]; + if key.is_empty() { + out.push('%'); + index = end + 1; + continue; + } + + if let Ok(v) = std::env::var(key) { + out.push_str(&v); + index = end + 1; + continue; + } + + out.push_str(&value[start..=end]); + index = end + 1; + } + + out.push_str(&value[index..]); + out + } + + fn extract_exe(value: &str) -> Option { + let value = value.trim(); + if value.is_empty() { + return None; + } + + if let Some(rest) = value.strip_prefix('"') { + if let Some(end) = rest.find('"') { + let inner = rest[..end].trim(); + if inner.to_ascii_lowercase().contains(".exe") { + return Some(inner.to_string()); + } + } + } + + let lower = value.to_ascii_lowercase(); + let end = lower.find(".exe")?; + Some(value[..end + 4].trim().trim_matches('"').to_string()) + } + + fn candidates(app_name: &str) -> Vec { + let app_name = app_name.trim().trim_matches('"'); + if app_name.is_empty() { + return vec![]; + } + + let mut out = Vec::::new(); + let mut push = |value: String| { + let value = value.trim().trim_matches('"').to_string(); + if value.is_empty() { + return; + } + if out.iter().any(|v| v.eq_ignore_ascii_case(&value)) { + return; + } + out.push(value); + }; + + push(app_name.to_string()); + + let lower = app_name.to_ascii_lowercase(); + if !lower.ends_with(".exe") { + push(format!("{app_name}.exe")); + } + + let snake = { + let mut s = String::new(); + let mut underscore = false; + for c in lower.chars() { + if c.is_ascii_alphanumeric() { + s.push(c); + underscore = false; + continue; + } + if underscore { + continue; + } + s.push('_'); + underscore = true; + } + s.trim_matches('_').to_string() + }; + + if !snake.is_empty() { + push(snake.clone()); + if !snake.ends_with(".exe") { + push(format!("{snake}.exe")); + } + } + + let alnum = lower + .chars() + .filter(|c| c.is_ascii_alphanumeric()) + .collect::(); + + if !alnum.is_empty() { + push(alnum.clone()); + push(format!("{alnum}.exe")); + } + + match lower.as_str() { + "sublime text" | "sublime-text" | "sublime_text" | "sublime text.exe" => { + push("subl".to_string()); + push("subl.exe".to_string()); + push("sublime_text".to_string()); + push("sublime_text.exe".to_string()); + } + _ => {} + } + + out + } + + fn reg_app_path(exe: &str) -> Option { + let exe = exe.trim().trim_matches('"'); + if exe.is_empty() { + return None; + } + + let query = |root: *mut c_void, subkey: &str| -> Option { + let flags = RRF_RT_REG_SZ | RRF_RT_REG_EXPAND_SZ; + let mut kind: u32 = 0; + let mut size = 0u32; + + let mut key = subkey.encode_utf16().collect::>(); + key.push(0); + + let status = unsafe { + RegGetValueW( + root, + key.as_ptr(), + std::ptr::null(), + flags, + &mut kind, + std::ptr::null_mut(), + &mut size, + ) + }; + + if status != ERROR_SUCCESS || size == 0 { + return None; + } + + if kind != REG_SZ && kind != REG_EXPAND_SZ { + return None; + } + + let mut data = vec![0u8; size as usize]; + let status = unsafe { + RegGetValueW( + root, + key.as_ptr(), + std::ptr::null(), + flags, + &mut kind, + data.as_mut_ptr() as *mut c_void, + &mut size, + ) + }; + + if status != ERROR_SUCCESS || size < 2 { + return None; + } + + let words = unsafe { + std::slice::from_raw_parts(data.as_ptr().cast::(), (size as usize) / 2) + }; + let len = words.iter().position(|v| *v == 0).unwrap_or(words.len()); + let value = String::from_utf16_lossy(&words[..len]).trim().to_string(); + + if value.is_empty() { + return None; + } + + Some(value) + }; + + let keys = [ + ( + HKEY_CURRENT_USER, + format!(r"Software\Microsoft\Windows\CurrentVersion\App Paths\{exe}"), + ), + ( + HKEY_LOCAL_MACHINE, + format!(r"Software\Microsoft\Windows\CurrentVersion\App Paths\{exe}"), + ), + ( + HKEY_LOCAL_MACHINE, + format!(r"Software\WOW6432Node\Microsoft\Windows\CurrentVersion\App Paths\{exe}"), + ), + ]; + + for (root, key) in keys { + let Some(value) = query(root, &key) else { + continue; + }; + + let Some(exe) = extract_exe(&value) else { + continue; + }; + + let exe = expand_env(&exe); + let path = Path::new(exe.trim().trim_matches('"')); + if path.exists() { + return Some(path.to_string_lossy().to_string()); + } + } + + None + } + + let app_name = app_name.trim().trim_matches('"'); + if app_name.is_empty() { + return None; + } + + let direct = Path::new(app_name); + if direct.is_absolute() && direct.exists() { + return Some(direct.to_string_lossy().to_string()); + } + + let key = app_name + .chars() + .filter(|v| v.is_ascii_alphanumeric()) + .flat_map(|v| v.to_lowercase()) + .collect::(); + + let has_ext = |path: &Path, ext: &str| { + path.extension() + .and_then(|v| v.to_str()) + .map(|v| v.eq_ignore_ascii_case(ext)) + .unwrap_or(false) + }; + + let resolve_cmd = |path: &Path| -> Option { + let bytes = std::fs::read(path).ok()?; + let content = String::from_utf8_lossy(&bytes); + + for token in content.split('"') { + let Some(exe) = extract_exe(token) else { + continue; + }; + + let lower = exe.to_ascii_lowercase(); + if let Some(index) = lower.find("%~dp0") { + let base = path.parent()?; + let suffix = &exe[index + 5..]; + let mut resolved = PathBuf::from(base); + + for part in suffix.replace('/', "\\").split('\\') { + if part.is_empty() || part == "." { + continue; + } + if part == ".." { + let _ = resolved.pop(); + continue; + } + resolved.push(part); + } + + if resolved.exists() { + return Some(resolved.to_string_lossy().to_string()); + } + + continue; + } + + let resolved = PathBuf::from(expand_env(&exe)); + if resolved.exists() { + return Some(resolved.to_string_lossy().to_string()); + } + } + + None + }; + + let resolve_where = |query: &str| -> Option { + let output = Command::new("where") + .creation_flags(CREATE_NO_WINDOW) + .arg(query) + .output() + .ok()?; + if !output.status.success() { + return None; + } + + let paths = String::from_utf8_lossy(&output.stdout) + .lines() + .map(str::trim) + .filter(|line| !line.is_empty()) + .map(PathBuf::from) + .collect::>(); + + if paths.is_empty() { + return None; + } + + if let Some(path) = paths.iter().find(|path| has_ext(path, "exe")) { + return Some(path.to_string_lossy().to_string()); + } + + for path in &paths { + if has_ext(path, "cmd") || has_ext(path, "bat") { + if let Some(resolved) = resolve_cmd(path) { + return Some(resolved); + } + } + + if path.extension().is_none() { + let cmd = path.with_extension("cmd"); + if cmd.exists() { + if let Some(resolved) = resolve_cmd(&cmd) { + return Some(resolved); + } + } + + let bat = path.with_extension("bat"); + if bat.exists() { + if let Some(resolved) = resolve_cmd(&bat) { + return Some(resolved); + } + } + } + } + + if !key.is_empty() { + for path in &paths { + let dirs = [ + path.parent(), + path.parent().and_then(|dir| dir.parent()), + path.parent() + .and_then(|dir| dir.parent()) + .and_then(|dir| dir.parent()), + ]; + + for dir in dirs.into_iter().flatten() { + if let Ok(entries) = std::fs::read_dir(dir) { + for entry in entries.flatten() { + let candidate = entry.path(); + if !has_ext(&candidate, "exe") { + continue; + } + + let Some(stem) = candidate.file_stem().and_then(|v| v.to_str()) else { + continue; + }; + + let name = stem + .chars() + .filter(|v| v.is_ascii_alphanumeric()) + .flat_map(|v| v.to_lowercase()) + .collect::(); + + if name.contains(&key) || key.contains(&name) { + return Some(candidate.to_string_lossy().to_string()); + } + } + } + } + } + } + + paths.first().map(|path| path.to_string_lossy().to_string()) + }; + + let list = candidates(app_name); + for query in &list { + if let Some(path) = resolve_where(query) { + return Some(path); + } + } + + let mut exes = Vec::::new(); + for query in &list { + let query = query.trim().trim_matches('"'); + if query.is_empty() { + continue; + } + + let name = Path::new(query) + .file_name() + .and_then(|v| v.to_str()) + .unwrap_or(query); + + let exe = if name.to_ascii_lowercase().ends_with(".exe") { + name.to_string() + } else { + format!("{name}.exe") + }; + + if exes.iter().any(|v| v.eq_ignore_ascii_case(&exe)) { + continue; + } + + exes.push(exe); + } + + for exe in exes { + if let Some(path) = reg_app_path(&exe) { + return Some(path); + } + } + + None +} + +pub fn open_in_powershell(path: String) -> Result<(), String> { + let path = PathBuf::from(path); + let dir = if path.is_dir() { + path + } else if let Some(parent) = path.parent() { + parent.to_path_buf() + } else { + std::env::current_dir() + .map_err(|e| format!("Failed to determine current directory: {e}"))? + }; + + Command::new("powershell.exe") + .creation_flags(CREATE_NEW_CONSOLE) + .current_dir(dir) + .args(["-NoExit"]) + .spawn() + .map_err(|e| format!("Failed to start PowerShell: {e}"))?; + + Ok(()) +} diff --git a/packages/desktop/src-tauri/tauri.beta.conf.json b/packages/desktop/src-tauri/tauri.beta.conf.json index 5207c73fc1..4dd7879933 100644 --- a/packages/desktop/src-tauri/tauri.beta.conf.json +++ b/packages/desktop/src-tauri/tauri.beta.conf.json @@ -4,6 +4,18 @@ "identifier": "ai.opencode.desktop.beta", "bundle": { "createUpdaterArtifacts": true, + "icon": [ + "icons/beta/32x32.png", + "icons/beta/128x128.png", + "icons/beta/128x128@2x.png", + "icons/beta/icon.icns", + "icons/beta/icon.ico" + ], + "windows": { + "nsis": { + "installerIcon": "icons/beta/icon.ico" + } + }, "linux": { "rpm": { "compression": { diff --git a/packages/desktop/src/bindings.ts b/packages/desktop/src/bindings.ts index 6d05bfc56e..80548173e9 100644 --- a/packages/desktop/src/bindings.ts +++ b/packages/desktop/src/bindings.ts @@ -18,6 +18,7 @@ export const commands = { checkAppExists: (appName: string) => __TAURI_INVOKE("check_app_exists", { appName }), wslPath: (path: string, mode: "windows" | "linux" | null) => __TAURI_INVOKE("wsl_path", { path, mode }), resolveAppPath: (appName: string) => __TAURI_INVOKE("resolve_app_path", { appName }), + openPath: (path: string, appName: string | null) => __TAURI_INVOKE("open_path", { path, appName }), }; /** Events */ diff --git a/packages/desktop/src/cli.ts b/packages/desktop/src/cli.ts index 28623bdf78..49e47534f9 100644 --- a/packages/desktop/src/cli.ts +++ b/packages/desktop/src/cli.ts @@ -3,6 +3,32 @@ import { message } from "@tauri-apps/plugin-dialog" import { initI18n, t } from "./i18n" import { commands } from "./bindings" +function installError(error: unknown) { + const text = String(error) + if (text.includes("CLI installation is only supported on macOS & Linux")) { + return t("desktop.cli.error.unsupportedPlatform") + } + if (text.includes("Sidecar binary not found")) { + return t("desktop.cli.error.sidecarMissing") + } + if (text.includes("Failed to write install script")) { + return t("desktop.cli.error.scriptWriteFailed") + } + if (text.includes("Failed to set script permissions")) { + return t("desktop.cli.error.scriptPermissionFailed") + } + if (text.includes("Failed to run install script")) { + return t("desktop.cli.error.scriptRunFailed") + } + if (text.includes("Install script failed")) { + return t("desktop.cli.error.scriptFailed") + } + if (text.includes("Could not determine install path")) { + return t("desktop.cli.error.installPathUnknown") + } + return text || t("desktop.cli.error.unknown") +} + export async function installCli(): Promise { await initI18n() @@ -10,6 +36,8 @@ export async function installCli(): Promise { const path = await commands.installCli() await message(t("desktop.cli.installed.message", { path }), { title: t("desktop.cli.installed.title") }) } catch (e) { - await message(t("desktop.cli.failed.message", { error: String(e) }), { title: t("desktop.cli.failed.title") }) + await message(t("desktop.cli.failed.message", { error: installError(e) }), { + title: t("desktop.cli.failed.title"), + }) } } diff --git a/packages/desktop/src/i18n/ar.ts b/packages/desktop/src/i18n/ar.ts index fdbf0a8047..21ab1c39bb 100644 --- a/packages/desktop/src/i18n/ar.ts +++ b/packages/desktop/src/i18n/ar.ts @@ -23,4 +23,37 @@ export const dict = { "desktop.cli.installed.message": "تم تثبيت CLI في {{path}}\n\nأعد تشغيل الطرفية لاستخدام الأمر 'opencode'.", "desktop.cli.failed.title": "فشل التثبيت", "desktop.cli.failed.message": "فشل تثبيت CLI: {{error}}", + + "desktop.menu.app": "OpenCode", + "desktop.menu.file": "ملف", + "desktop.menu.edit": "تعديل", + "desktop.menu.view": "عرض", + "desktop.menu.help": "مساعدة", + "desktop.menu.file.newSession": "جلسة جديدة", + "desktop.menu.file.openProject": "فتح مشروع...", + "desktop.menu.view.toggleSidebar": "تبديل الشريط الجانبي", + "desktop.menu.view.toggleTerminal": "تبديل الطرفية", + "desktop.menu.view.toggleFileTree": "تبديل شجرة الملفات", + "desktop.menu.view.back": "رجوع", + "desktop.menu.view.forward": "تقدم", + "desktop.menu.view.previousSession": "الجلسة السابقة", + "desktop.menu.view.nextSession": "الجلسة التالية", + "desktop.menu.help.documentation": "وثائق OpenCode", + "desktop.menu.help.supportForum": "منتدى الدعم", + "desktop.menu.help.shareFeedback": "مشاركة التعليقات", + "desktop.menu.help.reportBug": "الإبلاغ عن خطأ", + "desktop.cli.error.unsupportedPlatform": "تثبيت CLI مدعوم فقط على macOS و Linux.", + "desktop.cli.error.sidecarMissing": "ملف OpenCode CLI الثنائي مفقود. حاول إعادة تثبيت تطبيق سطح المكتب.", + "desktop.cli.error.scriptWriteFailed": "فشل تحضير برنامج تثبيت CLI.", + "desktop.cli.error.scriptPermissionFailed": "فشل جعل برنامج تثبيت CLI قابلاً للتنفيذ.", + "desktop.cli.error.scriptRunFailed": "فشل تشغيل برنامج تثبيت CLI.", + "desktop.cli.error.scriptFailed": "فشل برنامج تثبيت CLI.", + "desktop.cli.error.installPathUnknown": "تعذر تحديد مكان تثبيت CLI.", + "desktop.cli.error.unknown": "خطأ تثبيت غير معروف", + "desktop.loading.status.initial": "لحظة من فضلك...", + "desktop.loading.status.done": "تم الانتهاء", + "desktop.loading.status.migrating": "جارٍ ترحيل قاعدة البيانات الخاصة بك", + "desktop.loading.status.waiting": "قد يستغرق هذا بضع دقائق", + "desktop.loading.progressAria": "تقدم ترحيل قاعدة البيانات", + "desktop.server.local": "خادم محلي", } diff --git a/packages/desktop/src/i18n/br.ts b/packages/desktop/src/i18n/br.ts index 75fe2dc32b..82c84c2c90 100644 --- a/packages/desktop/src/i18n/br.ts +++ b/packages/desktop/src/i18n/br.ts @@ -24,4 +24,38 @@ export const dict = { "desktop.cli.installed.message": "CLI instalada em {{path}}\n\nReinicie seu terminal para usar o comando 'opencode'.", "desktop.cli.failed.title": "Falha na instalação", "desktop.cli.failed.message": "Falha ao instalar a CLI: {{error}}", + + "desktop.menu.app": "OpenCode", + "desktop.menu.file": "Arquivo", + "desktop.menu.edit": "Editar", + "desktop.menu.view": "Visualizar", + "desktop.menu.help": "Ajuda", + "desktop.menu.file.newSession": "Nova Sessão", + "desktop.menu.file.openProject": "Abrir Projeto...", + "desktop.menu.view.toggleSidebar": "Alternar Barra Lateral", + "desktop.menu.view.toggleTerminal": "Alternar Terminal", + "desktop.menu.view.toggleFileTree": "Alternar Árvore de Arquivos", + "desktop.menu.view.back": "Voltar", + "desktop.menu.view.forward": "Avançar", + "desktop.menu.view.previousSession": "Sessão Anterior", + "desktop.menu.view.nextSession": "Próxima Sessão", + "desktop.menu.help.documentation": "Documentação do OpenCode", + "desktop.menu.help.supportForum": "Fórum de Suporte", + "desktop.menu.help.shareFeedback": "Compartilhar Feedback", + "desktop.menu.help.reportBug": "Relatar um Bug", + "desktop.cli.error.unsupportedPlatform": "A instalação da CLI é suportada apenas no macOS e Linux.", + "desktop.cli.error.sidecarMissing": + "O binário da CLI do OpenCode está ausente. Tente reinstalar o aplicativo de desktop.", + "desktop.cli.error.scriptWriteFailed": "Falha ao preparar o script de instalação da CLI.", + "desktop.cli.error.scriptPermissionFailed": "Falha ao tornar o script de instalação da CLI executável.", + "desktop.cli.error.scriptRunFailed": "Falha ao executar o script de instalação da CLI.", + "desktop.cli.error.scriptFailed": "O instalador da CLI falhou.", + "desktop.cli.error.installPathUnknown": "Não foi possível determinar onde a CLI foi instalada.", + "desktop.cli.error.unknown": "Erro de instalação desconhecido", + "desktop.loading.status.initial": "Só um momento...", + "desktop.loading.status.done": "Tudo pronto", + "desktop.loading.status.migrating": "Migrando seu banco de dados", + "desktop.loading.status.waiting": "Isso pode levar alguns minutos", + "desktop.loading.progressAria": "Progresso da migração do banco de dados", + "desktop.server.local": "Servidor Local", } diff --git a/packages/desktop/src/i18n/bs.ts b/packages/desktop/src/i18n/bs.ts index 58c266f530..bf16065d12 100644 --- a/packages/desktop/src/i18n/bs.ts +++ b/packages/desktop/src/i18n/bs.ts @@ -25,4 +25,38 @@ export const dict = { "CLI je instaliran u {{path}}\n\nRestartuj terminal da bi koristio komandu 'opencode'.", "desktop.cli.failed.title": "Instalacija nije uspjela", "desktop.cli.failed.message": "Neuspjela instalacija CLI-a: {{error}}", + + "desktop.menu.app": "OpenCode", + "desktop.menu.file": "Datoteka", + "desktop.menu.edit": "Uredi", + "desktop.menu.view": "Prikaz", + "desktop.menu.help": "Pomoć", + "desktop.menu.file.newSession": "Nova sesija", + "desktop.menu.file.openProject": "Otvori projekat...", + "desktop.menu.view.toggleSidebar": "Prebaci bočnu traku", + "desktop.menu.view.toggleTerminal": "Prebaci terminal", + "desktop.menu.view.toggleFileTree": "Prebaci stablo datoteka", + "desktop.menu.view.back": "Nazad", + "desktop.menu.view.forward": "Naprijed", + "desktop.menu.view.previousSession": "Prethodna sesija", + "desktop.menu.view.nextSession": "Sljedeća sesija", + "desktop.menu.help.documentation": "OpenCode Dokumentacija", + "desktop.menu.help.supportForum": "Forum za podršku", + "desktop.menu.help.shareFeedback": "Podijeli povratne informacije", + "desktop.menu.help.reportBug": "Prijavi grešku", + "desktop.cli.error.unsupportedPlatform": "Instalacija CLI-a je podržana samo na macOS-u i Linux-u.", + "desktop.cli.error.sidecarMissing": + "Nedostaje binarna datoteka OpenCode CLI-a. Pokušaj ponovo instalirati desktop aplikaciju.", + "desktop.cli.error.scriptWriteFailed": "Nije uspjela priprema skripte za instalaciju CLI-a.", + "desktop.cli.error.scriptPermissionFailed": "Nije uspjelo postavljanje izvršnih dozvola za instalaciju CLI-a.", + "desktop.cli.error.scriptRunFailed": "Nije uspjelo pokretanje skripte za instalaciju CLI-a.", + "desktop.cli.error.scriptFailed": "Instalacija CLI-a nije uspjela.", + "desktop.cli.error.installPathUnknown": "Nije bilo moguće utvrditi gdje je instaliran CLI.", + "desktop.cli.error.unknown": "Nepoznata greška pri instalaciji", + "desktop.loading.status.initial": "Samo trenutak...", + "desktop.loading.status.done": "Sve je gotovo", + "desktop.loading.status.migrating": "Migracija baze podataka u toku", + "desktop.loading.status.waiting": "Ovo može potrajati nekoliko minuta", + "desktop.loading.progressAria": "Napredak migracije baze podataka", + "desktop.server.local": "Lokalni server", } diff --git a/packages/desktop/src/i18n/da.ts b/packages/desktop/src/i18n/da.ts index 2109495f76..463ffa3298 100644 --- a/packages/desktop/src/i18n/da.ts +++ b/packages/desktop/src/i18n/da.ts @@ -25,4 +25,37 @@ export const dict = { "CLI installeret i {{path}}\n\nGenstart din terminal for at bruge 'opencode'-kommandoen.", "desktop.cli.failed.title": "Installation mislykkedes", "desktop.cli.failed.message": "Kunne ikke installere CLI: {{error}}", + + "desktop.menu.app": "OpenCode", + "desktop.menu.file": "Filer", + "desktop.menu.edit": "Rediger", + "desktop.menu.view": "Vis", + "desktop.menu.help": "Hjælp", + "desktop.menu.file.newSession": "Ny session", + "desktop.menu.file.openProject": "Åbn projekt...", + "desktop.menu.view.toggleSidebar": "Slå sidepanel til/fra", + "desktop.menu.view.toggleTerminal": "Slå terminal til/fra", + "desktop.menu.view.toggleFileTree": "Slå filoversigt til/fra", + "desktop.menu.view.back": "Tilbage", + "desktop.menu.view.forward": "Fremad", + "desktop.menu.view.previousSession": "Forrige session", + "desktop.menu.view.nextSession": "Næste session", + "desktop.menu.help.documentation": "OpenCode Dokumentation", + "desktop.menu.help.supportForum": "Supportforum", + "desktop.menu.help.shareFeedback": "Del feedback", + "desktop.menu.help.reportBug": "Rapporter en fejl", + "desktop.cli.error.unsupportedPlatform": "CLI-installation understøttes kun på macOS og Linux.", + "desktop.cli.error.sidecarMissing": "OpenCode CLI-binærfil mangler. Prøv at geninstallere desktop-appen.", + "desktop.cli.error.scriptWriteFailed": "Kunne ikke forberede CLI-installationsscriptet.", + "desktop.cli.error.scriptPermissionFailed": "Kunne ikke gøre CLI-installationsscriptet eksekverbart.", + "desktop.cli.error.scriptRunFailed": "Kunne ikke køre CLI-installationsscriptet.", + "desktop.cli.error.scriptFailed": "CLI-installationsprogrammet mislykkedes.", + "desktop.cli.error.installPathUnknown": "Kunne ikke fastslå, hvor CLI'en blev installeret.", + "desktop.cli.error.unknown": "Ukendt installationsfejl", + "desktop.loading.status.initial": "Lige et øjeblik...", + "desktop.loading.status.done": "Helt færdig", + "desktop.loading.status.migrating": "Migrerer din database", + "desktop.loading.status.waiting": "Dette kan tage et par minutter", + "desktop.loading.progressAria": "Status for databasemigrering", + "desktop.server.local": "Lokal server", } diff --git a/packages/desktop/src/i18n/de.ts b/packages/desktop/src/i18n/de.ts index 38ad8096e3..26026d1ff2 100644 --- a/packages/desktop/src/i18n/de.ts +++ b/packages/desktop/src/i18n/de.ts @@ -25,4 +25,38 @@ export const dict = { "CLI wurde in {{path}} installiert\n\nStarten Sie Ihr Terminal neu, um den Befehl 'opencode' zu verwenden.", "desktop.cli.failed.title": "Installation fehlgeschlagen", "desktop.cli.failed.message": "CLI konnte nicht installiert werden: {{error}}", + + "desktop.menu.app": "OpenCode", + "desktop.menu.file": "Datei", + "desktop.menu.edit": "Bearbeiten", + "desktop.menu.view": "Ansicht", + "desktop.menu.help": "Hilfe", + "desktop.menu.file.newSession": "Neue Sitzung", + "desktop.menu.file.openProject": "Projekt öffnen...", + "desktop.menu.view.toggleSidebar": "Seitenleiste umschalten", + "desktop.menu.view.toggleTerminal": "Terminal umschalten", + "desktop.menu.view.toggleFileTree": "Dateibaum umschalten", + "desktop.menu.view.back": "Zurück", + "desktop.menu.view.forward": "Vorwärts", + "desktop.menu.view.previousSession": "Vorherige Sitzung", + "desktop.menu.view.nextSession": "Nächste Sitzung", + "desktop.menu.help.documentation": "OpenCode-Dokumentation", + "desktop.menu.help.supportForum": "Support-Forum", + "desktop.menu.help.shareFeedback": "Feedback teilen", + "desktop.menu.help.reportBug": "Einen Fehler melden", + "desktop.cli.error.unsupportedPlatform": "Die CLI-Installation wird nur unter macOS und Linux unterstützt.", + "desktop.cli.error.sidecarMissing": + "Das OpenCode CLI-Binary fehlt. Versuchen Sie, die Desktop-App neu zu installieren.", + "desktop.cli.error.scriptWriteFailed": "Das CLI-Installationsskript konnte nicht vorbereitet werden.", + "desktop.cli.error.scriptPermissionFailed": "Das CLI-Installationsskript konnte nicht ausführbar gemacht werden.", + "desktop.cli.error.scriptRunFailed": "Das CLI-Installationsskript konnte nicht ausgeführt werden.", + "desktop.cli.error.scriptFailed": "Das CLI-Installationsprogramm ist fehlgeschlagen.", + "desktop.cli.error.installPathUnknown": "Es konnte nicht ermittelt werden, wo die CLI installiert wurde.", + "desktop.cli.error.unknown": "Unbekannter Installationsfehler", + "desktop.loading.status.initial": "Einen Moment bitte...", + "desktop.loading.status.done": "Alles erledigt", + "desktop.loading.status.migrating": "Ihre Datenbank wird migriert", + "desktop.loading.status.waiting": "Dies kann einige Minuten dauern", + "desktop.loading.progressAria": "Fortschritt der Datenbankmigration", + "desktop.server.local": "Lokaler Server", } diff --git a/packages/desktop/src/i18n/en.ts b/packages/desktop/src/i18n/en.ts index 4c30380d56..f93fe58f77 100644 --- a/packages/desktop/src/i18n/en.ts +++ b/packages/desktop/src/i18n/en.ts @@ -3,6 +3,24 @@ export const dict = { "desktop.menu.installCli": "Install CLI...", "desktop.menu.reloadWebview": "Reload Webview", "desktop.menu.restart": "Restart", + "desktop.menu.app": "OpenCode", + "desktop.menu.file": "File", + "desktop.menu.edit": "Edit", + "desktop.menu.view": "View", + "desktop.menu.help": "Help", + "desktop.menu.file.newSession": "New Session", + "desktop.menu.file.openProject": "Open Project...", + "desktop.menu.view.toggleSidebar": "Toggle Sidebar", + "desktop.menu.view.toggleTerminal": "Toggle Terminal", + "desktop.menu.view.toggleFileTree": "Toggle File Tree", + "desktop.menu.view.back": "Back", + "desktop.menu.view.forward": "Forward", + "desktop.menu.view.previousSession": "Previous Session", + "desktop.menu.view.nextSession": "Next Session", + "desktop.menu.help.documentation": "OpenCode Documentation", + "desktop.menu.help.supportForum": "Support Forum", + "desktop.menu.help.shareFeedback": "Share Feedback", + "desktop.menu.help.reportBug": "Report a Bug", "desktop.dialog.chooseFolder": "Choose a folder", "desktop.dialog.chooseFile": "Choose a file", @@ -24,4 +42,20 @@ export const dict = { "desktop.cli.installed.message": "CLI installed to {{path}}\n\nRestart your terminal to use the 'opencode' command.", "desktop.cli.failed.title": "Installation Failed", "desktop.cli.failed.message": "Failed to install CLI: {{error}}", + "desktop.cli.error.unsupportedPlatform": "CLI installation is only supported on macOS and Linux.", + "desktop.cli.error.sidecarMissing": "OpenCode CLI binary is missing. Try reinstalling the desktop app.", + "desktop.cli.error.scriptWriteFailed": "Failed to prepare CLI installer script.", + "desktop.cli.error.scriptPermissionFailed": "Failed to make CLI installer executable.", + "desktop.cli.error.scriptRunFailed": "Failed to run CLI installer script.", + "desktop.cli.error.scriptFailed": "CLI installer failed.", + "desktop.cli.error.installPathUnknown": "Could not determine where the CLI was installed.", + "desktop.cli.error.unknown": "Unknown installation error", + + "desktop.loading.status.initial": "Just a moment...", + "desktop.loading.status.done": "All done", + "desktop.loading.status.migrating": "Migrating your database", + "desktop.loading.status.waiting": "This may take a couple of minutes", + "desktop.loading.progressAria": "Database migration progress", + + "desktop.server.local": "Local Server", } diff --git a/packages/desktop/src/i18n/es.ts b/packages/desktop/src/i18n/es.ts index 80504a8f24..6b0d0dee27 100644 --- a/packages/desktop/src/i18n/es.ts +++ b/packages/desktop/src/i18n/es.ts @@ -24,4 +24,38 @@ export const dict = { "desktop.cli.installed.message": "CLI instalada en {{path}}\n\nReinicia tu terminal para usar el comando 'opencode'.", "desktop.cli.failed.title": "Instalación fallida", "desktop.cli.failed.message": "No se pudo instalar la CLI: {{error}}", + + "desktop.menu.app": "OpenCode", + "desktop.menu.file": "Archivo", + "desktop.menu.edit": "Editar", + "desktop.menu.view": "Ver", + "desktop.menu.help": "Ayuda", + "desktop.menu.file.newSession": "Nueva sesión", + "desktop.menu.file.openProject": "Abrir proyecto...", + "desktop.menu.view.toggleSidebar": "Alternar barra lateral", + "desktop.menu.view.toggleTerminal": "Alternar terminal", + "desktop.menu.view.toggleFileTree": "Alternar árbol de archivos", + "desktop.menu.view.back": "Atrás", + "desktop.menu.view.forward": "Adelante", + "desktop.menu.view.previousSession": "Sesión anterior", + "desktop.menu.view.nextSession": "Siguiente sesión", + "desktop.menu.help.documentation": "Documentación de OpenCode", + "desktop.menu.help.supportForum": "Foro de soporte", + "desktop.menu.help.shareFeedback": "Compartir comentarios", + "desktop.menu.help.reportBug": "Informar de un error", + "desktop.cli.error.unsupportedPlatform": "La instalación de la CLI solo es compatible con macOS y Linux.", + "desktop.cli.error.sidecarMissing": + "Falta el binario de la CLI de OpenCode. Intenta reinstalar la aplicación de escritorio.", + "desktop.cli.error.scriptWriteFailed": "No se pudo preparar el script del instalador de la CLI.", + "desktop.cli.error.scriptPermissionFailed": "No se pudo hacer ejecutable el script del instalador de la CLI.", + "desktop.cli.error.scriptRunFailed": "No se pudo ejecutar el script del instalador de la CLI.", + "desktop.cli.error.scriptFailed": "El instalador de la CLI falló.", + "desktop.cli.error.installPathUnknown": "No se pudo determinar dónde se instaló la CLI.", + "desktop.cli.error.unknown": "Error de instalación desconocido", + "desktop.loading.status.initial": "Un momento...", + "desktop.loading.status.done": "Todo listo", + "desktop.loading.status.migrating": "Migrando tu base de datos", + "desktop.loading.status.waiting": "Esto puede tardar unos minutos", + "desktop.loading.progressAria": "Progreso de migración de la base de datos", + "desktop.server.local": "Servidor local", } diff --git a/packages/desktop/src/i18n/fr.ts b/packages/desktop/src/i18n/fr.ts index 4f0bb2b16c..cd9c854b37 100644 --- a/packages/desktop/src/i18n/fr.ts +++ b/packages/desktop/src/i18n/fr.ts @@ -25,4 +25,38 @@ export const dict = { "CLI installée dans {{path}}\n\nRedémarrez votre terminal pour utiliser la commande 'opencode'.", "desktop.cli.failed.title": "Échec de l'installation", "desktop.cli.failed.message": "Impossible d'installer la CLI : {{error}}", + + "desktop.menu.app": "OpenCode", + "desktop.menu.file": "Fichier", + "desktop.menu.edit": "Édition", + "desktop.menu.view": "Affichage", + "desktop.menu.help": "Aide", + "desktop.menu.file.newSession": "Nouvelle session", + "desktop.menu.file.openProject": "Ouvrir un projet...", + "desktop.menu.view.toggleSidebar": "Basculer la barre latérale", + "desktop.menu.view.toggleTerminal": "Basculer le terminal", + "desktop.menu.view.toggleFileTree": "Basculer l'arborescence des fichiers", + "desktop.menu.view.back": "Retour", + "desktop.menu.view.forward": "Suivant", + "desktop.menu.view.previousSession": "Session précédente", + "desktop.menu.view.nextSession": "Session suivante", + "desktop.menu.help.documentation": "Documentation d'OpenCode", + "desktop.menu.help.supportForum": "Forum d'assistance", + "desktop.menu.help.shareFeedback": "Partager des commentaires", + "desktop.menu.help.reportBug": "Signaler un bug", + "desktop.cli.error.unsupportedPlatform": "L'installation de la CLI n'est prise en charge que sur macOS et Linux.", + "desktop.cli.error.sidecarMissing": + "Le binaire de la CLI OpenCode est manquant. Essayez de réinstaller l'application de bureau.", + "desktop.cli.error.scriptWriteFailed": "Impossible de préparer le script d'installation de la CLI.", + "desktop.cli.error.scriptPermissionFailed": "Impossible de rendre le script d'installation de la CLI exécutable.", + "desktop.cli.error.scriptRunFailed": "Impossible d'exécuter le script d'installation de la CLI.", + "desktop.cli.error.scriptFailed": "L'installateur de la CLI a échoué.", + "desktop.cli.error.installPathUnknown": "Impossible de déterminer où la CLI a été installée.", + "desktop.cli.error.unknown": "Erreur d'installation inconnue", + "desktop.loading.status.initial": "Un instant...", + "desktop.loading.status.done": "Terminé", + "desktop.loading.status.migrating": "Migration de votre base de données", + "desktop.loading.status.waiting": "Cela peut prendre quelques minutes", + "desktop.loading.progressAria": "Progression de la migration de la base de données", + "desktop.server.local": "Serveur local", } diff --git a/packages/desktop/src/i18n/index.ts b/packages/desktop/src/i18n/index.ts index 7b1ebfe696..e1c1e63d97 100644 --- a/packages/desktop/src/i18n/index.ts +++ b/packages/desktop/src/i18n/index.ts @@ -77,6 +77,7 @@ function detectLocale(): Locale { const languages = navigator.languages?.length ? navigator.languages : [navigator.language] for (const language of languages) { if (!language) continue + if (language.toLowerCase().startsWith("en")) return "en" if (language.toLowerCase().startsWith("zh")) { if (language.toLowerCase().includes("hant")) return "zht" return "zh" diff --git a/packages/desktop/src/i18n/ja.ts b/packages/desktop/src/i18n/ja.ts index fc485c6f40..ff768c0676 100644 --- a/packages/desktop/src/i18n/ja.ts +++ b/packages/desktop/src/i18n/ja.ts @@ -25,4 +25,38 @@ export const dict = { "CLI を {{path}} にインストールしました\n\nターミナルを再起動して 'opencode' コマンドを使用してください。", "desktop.cli.failed.title": "インストールに失敗しました", "desktop.cli.failed.message": "CLI のインストールに失敗しました: {{error}}", + + "desktop.menu.app": "OpenCode", + "desktop.menu.file": "ファイル", + "desktop.menu.edit": "編集", + "desktop.menu.view": "表示", + "desktop.menu.help": "ヘルプ", + "desktop.menu.file.newSession": "新しいセッション", + "desktop.menu.file.openProject": "プロジェクトを開く...", + "desktop.menu.view.toggleSidebar": "サイドバーの切り替え", + "desktop.menu.view.toggleTerminal": "ターミナルの切り替え", + "desktop.menu.view.toggleFileTree": "ファイルツリーの切り替え", + "desktop.menu.view.back": "戻る", + "desktop.menu.view.forward": "進む", + "desktop.menu.view.previousSession": "前のセッション", + "desktop.menu.view.nextSession": "次のセッション", + "desktop.menu.help.documentation": "OpenCode ドキュメント", + "desktop.menu.help.supportForum": "サポートフォーラム", + "desktop.menu.help.shareFeedback": "フィードバックを共有", + "desktop.menu.help.reportBug": "バグを報告", + "desktop.cli.error.unsupportedPlatform": "CLI のインストールは macOS と Linux のみでサポートされています。", + "desktop.cli.error.sidecarMissing": + "OpenCode CLI のバイナリが見つかりません。デスクトップアプリを再インストールしてみてください。", + "desktop.cli.error.scriptWriteFailed": "CLI インストーラースクリプトの準備に失敗しました。", + "desktop.cli.error.scriptPermissionFailed": "CLI インストーラースクリプトに実行権限を付与できませんでした。", + "desktop.cli.error.scriptRunFailed": "CLI インストーラースクリプトの実行に失敗しました。", + "desktop.cli.error.scriptFailed": "CLI インストーラーが失敗しました。", + "desktop.cli.error.installPathUnknown": "CLI がどこにインストールされたか特定できませんでした。", + "desktop.cli.error.unknown": "不明なインストールエラー", + "desktop.loading.status.initial": "少々お待ちください...", + "desktop.loading.status.done": "完了しました", + "desktop.loading.status.migrating": "データベースを移行しています", + "desktop.loading.status.waiting": "これには数分かかる場合があります", + "desktop.loading.progressAria": "データベース移行の進行状況", + "desktop.server.local": "ローカルサーバー", } diff --git a/packages/desktop/src/i18n/ko.ts b/packages/desktop/src/i18n/ko.ts index be27cec86a..c50b7fdefd 100644 --- a/packages/desktop/src/i18n/ko.ts +++ b/packages/desktop/src/i18n/ko.ts @@ -24,4 +24,37 @@ export const dict = { "CLI가 {{path}}에 설치되었습니다\n\n터미널을 다시 시작하여 'opencode' 명령을 사용하세요.", "desktop.cli.failed.title": "설치 실패", "desktop.cli.failed.message": "CLI 설치 실패: {{error}}", + + "desktop.menu.app": "OpenCode", + "desktop.menu.file": "파일", + "desktop.menu.edit": "편집", + "desktop.menu.view": "보기", + "desktop.menu.help": "도움말", + "desktop.menu.file.newSession": "새 세션", + "desktop.menu.file.openProject": "프로젝트 열기...", + "desktop.menu.view.toggleSidebar": "사이드바 전환", + "desktop.menu.view.toggleTerminal": "터미널 전환", + "desktop.menu.view.toggleFileTree": "파일 트리 전환", + "desktop.menu.view.back": "뒤로", + "desktop.menu.view.forward": "앞으로", + "desktop.menu.view.previousSession": "이전 세션", + "desktop.menu.view.nextSession": "다음 세션", + "desktop.menu.help.documentation": "OpenCode 문서", + "desktop.menu.help.supportForum": "지원 포럼", + "desktop.menu.help.shareFeedback": "피드백 공유", + "desktop.menu.help.reportBug": "버그 신고", + "desktop.cli.error.unsupportedPlatform": "CLI 설치는 macOS 및 Linux에서만 지원됩니다.", + "desktop.cli.error.sidecarMissing": "OpenCode CLI 바이너리가 누락되었습니다. 데스크톱 앱을 다시 설치해 보세요.", + "desktop.cli.error.scriptWriteFailed": "CLI 설치 스크립트를 준비하지 못했습니다.", + "desktop.cli.error.scriptPermissionFailed": "CLI 설치 스크립트를 실행 가능하게 만들지 못했습니다.", + "desktop.cli.error.scriptRunFailed": "CLI 설치 스크립트를 실행하지 못했습니다.", + "desktop.cli.error.scriptFailed": "CLI 설치 프로그램이 실패했습니다.", + "desktop.cli.error.installPathUnknown": "CLI가 어디에 설치되었는지 확인할 수 없습니다.", + "desktop.cli.error.unknown": "알 수 없는 설치 오류", + "desktop.loading.status.initial": "잠시만 기다려 주세요...", + "desktop.loading.status.done": "모두 완료되었습니다", + "desktop.loading.status.migrating": "데이터베이스 마이그레이션 중", + "desktop.loading.status.waiting": "이 작업은 몇 분 정도 걸릴 수 있습니다", + "desktop.loading.progressAria": "데이터베이스 마이그레이션 진행률", + "desktop.server.local": "로컬 서버", } diff --git a/packages/desktop/src/i18n/no.ts b/packages/desktop/src/i18n/no.ts index e39bd7f3b4..ced60e8352 100644 --- a/packages/desktop/src/i18n/no.ts +++ b/packages/desktop/src/i18n/no.ts @@ -25,4 +25,37 @@ export const dict = { "CLI installert til {{path}}\n\nStart terminalen på nytt for å bruke 'opencode'-kommandoen.", "desktop.cli.failed.title": "Installasjon mislyktes", "desktop.cli.failed.message": "Kunne ikke installere CLI: {{error}}", + + "desktop.menu.app": "OpenCode", + "desktop.menu.file": "Fil", + "desktop.menu.edit": "Rediger", + "desktop.menu.view": "Vis", + "desktop.menu.help": "Hjelp", + "desktop.menu.file.newSession": "Ny sesjon", + "desktop.menu.file.openProject": "Åpne prosjekt...", + "desktop.menu.view.toggleSidebar": "Vis/skjul sidefelt", + "desktop.menu.view.toggleTerminal": "Vis/skjul terminal", + "desktop.menu.view.toggleFileTree": "Vis/skjul filtre", + "desktop.menu.view.back": "Tilbake", + "desktop.menu.view.forward": "Frem", + "desktop.menu.view.previousSession": "Forrige sesjon", + "desktop.menu.view.nextSession": "Neste sesjon", + "desktop.menu.help.documentation": "OpenCode Dokumentasjon", + "desktop.menu.help.supportForum": "Støtteforum", + "desktop.menu.help.shareFeedback": "Del tilbakemelding", + "desktop.menu.help.reportBug": "Rapporter en feil", + "desktop.cli.error.unsupportedPlatform": "CLI-installasjon støttes kun på macOS og Linux.", + "desktop.cli.error.sidecarMissing": "OpenCode CLI-binærfil mangler. Prøv å installere skrivebordsappen på nytt.", + "desktop.cli.error.scriptWriteFailed": "Kunne ikke klargjøre CLI-installasjonsskriptet.", + "desktop.cli.error.scriptPermissionFailed": "Kunne ikke gjøre CLI-installasjonsskriptet kjørbart.", + "desktop.cli.error.scriptRunFailed": "Kunne ikke kjøre CLI-installasjonsskriptet.", + "desktop.cli.error.scriptFailed": "CLI-installasjonsprogrammet mislyktes.", + "desktop.cli.error.installPathUnknown": "Kunne ikke avgjøre hvor CLI ble installert.", + "desktop.cli.error.unknown": "Ukjent installasjonsfeil", + "desktop.loading.status.initial": "Et øyeblikk...", + "desktop.loading.status.done": "Alt ferdig", + "desktop.loading.status.migrating": "Migrerer databasen din", + "desktop.loading.status.waiting": "Dette kan ta et par minutter", + "desktop.loading.progressAria": "Fremdrift for databasemigrering", + "desktop.server.local": "Lokal server", } diff --git a/packages/desktop/src/i18n/pl.ts b/packages/desktop/src/i18n/pl.ts index d3ad7ce64f..0452ab5da5 100644 --- a/packages/desktop/src/i18n/pl.ts +++ b/packages/desktop/src/i18n/pl.ts @@ -25,4 +25,38 @@ export const dict = { "CLI zainstalowane w {{path}}\n\nUruchom ponownie terminal, aby użyć polecenia 'opencode'.", "desktop.cli.failed.title": "Instalacja nie powiodła się", "desktop.cli.failed.message": "Nie udało się zainstalować CLI: {{error}}", + + "desktop.menu.app": "OpenCode", + "desktop.menu.file": "Plik", + "desktop.menu.edit": "Edycja", + "desktop.menu.view": "Widok", + "desktop.menu.help": "Pomoc", + "desktop.menu.file.newSession": "Nowa sesja", + "desktop.menu.file.openProject": "Otwórz projekt...", + "desktop.menu.view.toggleSidebar": "Przełącz pasek boczny", + "desktop.menu.view.toggleTerminal": "Przełącz terminal", + "desktop.menu.view.toggleFileTree": "Przełącz drzewo plików", + "desktop.menu.view.back": "Wstecz", + "desktop.menu.view.forward": "Dalej", + "desktop.menu.view.previousSession": "Poprzednia sesja", + "desktop.menu.view.nextSession": "Następna sesja", + "desktop.menu.help.documentation": "Dokumentacja OpenCode", + "desktop.menu.help.supportForum": "Forum wsparcia", + "desktop.menu.help.shareFeedback": "Prześlij opinię", + "desktop.menu.help.reportBug": "Zgłoś błąd", + "desktop.cli.error.unsupportedPlatform": "Instalacja CLI jest obsługiwana tylko na macOS i Linux.", + "desktop.cli.error.sidecarMissing": + "Brakuje pliku binarnego OpenCode CLI. Spróbuj ponownie zainstalować aplikację na komputer.", + "desktop.cli.error.scriptWriteFailed": "Nie udało się przygotować skryptu instalatora CLI.", + "desktop.cli.error.scriptPermissionFailed": "Nie udało się nadać uprawnień do wykonania skryptu instalatora CLI.", + "desktop.cli.error.scriptRunFailed": "Nie udało się uruchomić skryptu instalatora CLI.", + "desktop.cli.error.scriptFailed": "Instalator CLI nie powiódł się.", + "desktop.cli.error.installPathUnknown": "Nie udało się ustalić, gdzie zostało zainstalowane CLI.", + "desktop.cli.error.unknown": "Nieznany błąd instalacji", + "desktop.loading.status.initial": "Chwileczkę...", + "desktop.loading.status.done": "Gotowe", + "desktop.loading.status.migrating": "Migrowanie bazy danych", + "desktop.loading.status.waiting": "Może to potrwać kilka minut", + "desktop.loading.progressAria": "Postęp migracji bazy danych", + "desktop.server.local": "Serwer lokalny", } diff --git a/packages/desktop/src/i18n/ru.ts b/packages/desktop/src/i18n/ru.ts index 8e09cc45b4..d0d6c8aff3 100644 --- a/packages/desktop/src/i18n/ru.ts +++ b/packages/desktop/src/i18n/ru.ts @@ -24,4 +24,38 @@ export const dict = { "CLI установлен в {{path}}\n\nПерезапустите терминал, чтобы использовать команду 'opencode'.", "desktop.cli.failed.title": "Ошибка установки", "desktop.cli.failed.message": "Не удалось установить CLI: {{error}}", + + "desktop.menu.app": "OpenCode", + "desktop.menu.file": "Файл", + "desktop.menu.edit": "Правка", + "desktop.menu.view": "Вид", + "desktop.menu.help": "Справка", + "desktop.menu.file.newSession": "Новая сессия", + "desktop.menu.file.openProject": "Открыть проект...", + "desktop.menu.view.toggleSidebar": "Переключить боковую панель", + "desktop.menu.view.toggleTerminal": "Переключить терминал", + "desktop.menu.view.toggleFileTree": "Переключить дерево файлов", + "desktop.menu.view.back": "Назад", + "desktop.menu.view.forward": "Вперед", + "desktop.menu.view.previousSession": "Предыдущая сессия", + "desktop.menu.view.nextSession": "Следующая сессия", + "desktop.menu.help.documentation": "Документация OpenCode", + "desktop.menu.help.supportForum": "Форум поддержки", + "desktop.menu.help.shareFeedback": "Поделиться отзывом", + "desktop.menu.help.reportBug": "Сообщить об ошибке", + "desktop.cli.error.unsupportedPlatform": "Установка CLI поддерживается только в macOS и Linux.", + "desktop.cli.error.sidecarMissing": + "Отсутствует бинарный файл OpenCode CLI. Попробуйте переустановить настольное приложение.", + "desktop.cli.error.scriptWriteFailed": "Не удалось подготовить скрипт установщика CLI.", + "desktop.cli.error.scriptPermissionFailed": "Не удалось сделать скрипт установщика CLI исполняемым.", + "desktop.cli.error.scriptRunFailed": "Не удалось запустить скрипт установщика CLI.", + "desktop.cli.error.scriptFailed": "Ошибка установщика CLI.", + "desktop.cli.error.installPathUnknown": "Не удалось определить, куда был установлен CLI.", + "desktop.cli.error.unknown": "Неизвестная ошибка установки", + "desktop.loading.status.initial": "Минуточку...", + "desktop.loading.status.done": "Всё готово", + "desktop.loading.status.migrating": "Миграция вашей базы данных", + "desktop.loading.status.waiting": "Это может занять пару минут", + "desktop.loading.progressAria": "Прогресс миграции базы данных", + "desktop.server.local": "Локальный сервер", } diff --git a/packages/desktop/src/i18n/zh.ts b/packages/desktop/src/i18n/zh.ts index aeb3a54e03..a173e2b558 100644 --- a/packages/desktop/src/i18n/zh.ts +++ b/packages/desktop/src/i18n/zh.ts @@ -23,4 +23,37 @@ export const dict = { "desktop.cli.installed.message": "CLI 已安装到 {{path}}\n\n重启终端以使用 'opencode' 命令。", "desktop.cli.failed.title": "安装失败", "desktop.cli.failed.message": "无法安装 CLI: {{error}}", + + "desktop.menu.app": "OpenCode", + "desktop.menu.file": "文件", + "desktop.menu.edit": "编辑", + "desktop.menu.view": "查看", + "desktop.menu.help": "帮助", + "desktop.menu.file.newSession": "新会话", + "desktop.menu.file.openProject": "打开项目...", + "desktop.menu.view.toggleSidebar": "切换侧边栏", + "desktop.menu.view.toggleTerminal": "切换终端", + "desktop.menu.view.toggleFileTree": "切换文件树", + "desktop.menu.view.back": "后退", + "desktop.menu.view.forward": "前进", + "desktop.menu.view.previousSession": "上一个会话", + "desktop.menu.view.nextSession": "下一个会话", + "desktop.menu.help.documentation": "OpenCode 文档", + "desktop.menu.help.supportForum": "支持论坛", + "desktop.menu.help.shareFeedback": "分享反馈", + "desktop.menu.help.reportBug": "报告错误", + "desktop.cli.error.unsupportedPlatform": "CLI 安装仅在 macOS 和 Linux 上受支持。", + "desktop.cli.error.sidecarMissing": "OpenCode CLI 二进制文件缺失。请尝试重新安装桌面应用程序。", + "desktop.cli.error.scriptWriteFailed": "无法准备 CLI 安装脚本。", + "desktop.cli.error.scriptPermissionFailed": "无法使 CLI 安装脚本可执行。", + "desktop.cli.error.scriptRunFailed": "无法运行 CLI 安装脚本。", + "desktop.cli.error.scriptFailed": "CLI 安装程序失败。", + "desktop.cli.error.installPathUnknown": "无法确定 CLI 的安装位置。", + "desktop.cli.error.unknown": "未知的安装错误", + "desktop.loading.status.initial": "稍等片刻...", + "desktop.loading.status.done": "全部完成", + "desktop.loading.status.migrating": "正在迁移您的数据库", + "desktop.loading.status.waiting": "这可能需要几分钟", + "desktop.loading.progressAria": "数据库迁移进度", + "desktop.server.local": "本地服务器", } diff --git a/packages/desktop/src/i18n/zht.ts b/packages/desktop/src/i18n/zht.ts index 7fd677aca4..fca239ba64 100644 --- a/packages/desktop/src/i18n/zht.ts +++ b/packages/desktop/src/i18n/zht.ts @@ -23,4 +23,37 @@ export const dict = { "desktop.cli.installed.message": "CLI 已安裝到 {{path}}\n\n重新啟動終端機以使用 'opencode' 命令。", "desktop.cli.failed.title": "安裝失敗", "desktop.cli.failed.message": "無法安裝 CLI: {{error}}", + + "desktop.menu.app": "OpenCode", + "desktop.menu.file": "檔案", + "desktop.menu.edit": "編輯", + "desktop.menu.view": "檢視", + "desktop.menu.help": "說明", + "desktop.menu.file.newSession": "新工作階段", + "desktop.menu.file.openProject": "開啟專案...", + "desktop.menu.view.toggleSidebar": "切換側邊欄", + "desktop.menu.view.toggleTerminal": "切換終端機", + "desktop.menu.view.toggleFileTree": "切換檔案樹", + "desktop.menu.view.back": "上一步", + "desktop.menu.view.forward": "下一步", + "desktop.menu.view.previousSession": "上一個工作階段", + "desktop.menu.view.nextSession": "下一個工作階段", + "desktop.menu.help.documentation": "OpenCode 文件", + "desktop.menu.help.supportForum": "支援論壇", + "desktop.menu.help.shareFeedback": "分享意見回饋", + "desktop.menu.help.reportBug": "回報錯誤", + "desktop.cli.error.unsupportedPlatform": "CLI 安裝僅支援 macOS 與 Linux。", + "desktop.cli.error.sidecarMissing": "OpenCode CLI 執行檔遺失。請嘗試重新安裝桌面應用程式。", + "desktop.cli.error.scriptWriteFailed": "無法準備 CLI 安裝指令碼。", + "desktop.cli.error.scriptPermissionFailed": "無法將 CLI 安裝指令碼設為可執行。", + "desktop.cli.error.scriptRunFailed": "無法執行 CLI 安裝指令碼。", + "desktop.cli.error.scriptFailed": "CLI 安裝程式失敗。", + "desktop.cli.error.installPathUnknown": "無法確定 CLI 的安裝位置。", + "desktop.cli.error.unknown": "未知的安裝錯誤", + "desktop.loading.status.initial": "稍等片刻...", + "desktop.loading.status.done": "全部完成", + "desktop.loading.status.migrating": "正在移轉您的資料庫", + "desktop.loading.status.waiting": "這可能需要幾分鐘", + "desktop.loading.progressAria": "資料庫移轉進度", + "desktop.server.local": "本機伺服器", } diff --git a/packages/desktop/src/index.tsx b/packages/desktop/src/index.tsx index 983fe39456..9afabe918b 100644 --- a/packages/desktop/src/index.tsx +++ b/packages/desktop/src/index.tsx @@ -17,7 +17,6 @@ import { getCurrent, onOpenUrl } from "@tauri-apps/plugin-deep-link" import { open, save } from "@tauri-apps/plugin-dialog" import { fetch as tauriFetch } from "@tauri-apps/plugin-http" import { isPermissionGranted, requestPermission } from "@tauri-apps/plugin-notification" -import { openPath as openerOpenPath } from "@tauri-apps/plugin-opener" import { type as ostype } from "@tauri-apps/plugin-os" import { relaunch } from "@tauri-apps/plugin-process" import { open as shellOpen } from "@tauri-apps/plugin-shell" @@ -116,20 +115,7 @@ const createPlatform = (): Platform => { void shellOpen(url).catch(() => undefined) }, async openPath(path: string, app?: string) { - const os = ostype() - if (os === "windows") { - const resolvedApp = (app && (await commands.resolveAppPath(app))) || app - const resolvedPath = await (async () => { - if (window.__OPENCODE__?.wsl) { - const converted = await commands.wslPath(path, "windows").catch(() => null) - if (converted) return converted - } - - return path - })() - return openerOpenPath(resolvedPath, resolvedApp) - } - return openerOpenPath(path, app) + await commands.openPath(path, app ?? null) }, back() { @@ -459,7 +445,7 @@ render(() => { } const server: ServerConnection.Any = data.is_sidecar ? { - displayName: "Local Server", + displayName: t("desktop.server.local"), type: "sidecar", variant: "base", http, diff --git a/packages/desktop/src/loading.tsx b/packages/desktop/src/loading.tsx index 23a8055c9d..a02f1a95e5 100644 --- a/packages/desktop/src/loading.tsx +++ b/packages/desktop/src/loading.tsx @@ -8,11 +8,18 @@ import "./styles.css" import { createEffect, createMemo, createSignal, onCleanup, onMount } from "solid-js" import { commands, events, InitStep } from "./bindings" import { Channel } from "@tauri-apps/api/core" +import { initI18n, t } from "./i18n" const root = document.getElementById("root")! -const lines = ["Just a moment...", "Migrating your database", "This may take a couple of minutes"] +const lines = [ + t("desktop.loading.status.initial"), + t("desktop.loading.status.migrating"), + t("desktop.loading.status.waiting"), +] const delays = [3000, 9000] +void initI18n() + render(() => { const [step, setStep] = createSignal(null) const [line, setLine] = createSignal(0) @@ -54,9 +61,9 @@ render(() => { }) const status = createMemo(() => { - if (phase() === "done") return "All done" + if (phase() === "done") return t("desktop.loading.status.done") if (phase() === "sqlite_waiting") return lines[line()] - return "Just a moment..." + return t("desktop.loading.status.initial") }) return ( @@ -72,7 +79,7 @@ render(() => { `${Math.round(value)}%`} />
    diff --git a/packages/desktop/src/menu.ts b/packages/desktop/src/menu.ts index 9fcb6115b1..de6a1d6a76 100644 --- a/packages/desktop/src/menu.ts +++ b/packages/desktop/src/menu.ts @@ -16,7 +16,7 @@ export async function createMenu(trigger: (id: string) => void) { const menu = await Menu.new({ items: [ await Submenu.new({ - text: "OpenCode", + text: t("desktop.menu.app"), items: [ await PredefinedMenuItem.new({ item: { About: null }, @@ -62,15 +62,15 @@ export async function createMenu(trigger: (id: string) => void) { ].filter(Boolean), }), await Submenu.new({ - text: "File", + text: t("desktop.menu.file"), items: [ await MenuItem.new({ - text: "New Session", + text: t("desktop.menu.file.newSession"), accelerator: "Shift+Cmd+S", action: () => trigger("session.new"), }), await MenuItem.new({ - text: "Open Project...", + text: t("desktop.menu.file.openProject"), accelerator: "Cmd+O", action: () => trigger("project.open"), }), @@ -83,7 +83,7 @@ export async function createMenu(trigger: (id: string) => void) { ], }), await Submenu.new({ - text: "Edit", + text: t("desktop.menu.edit"), items: [ await PredefinedMenuItem.new({ item: "Undo", @@ -109,44 +109,44 @@ export async function createMenu(trigger: (id: string) => void) { ], }), await Submenu.new({ - text: "View", + text: t("desktop.menu.view"), items: [ await MenuItem.new({ action: () => trigger("sidebar.toggle"), - text: "Toggle Sidebar", + text: t("desktop.menu.view.toggleSidebar"), accelerator: "Cmd+B", }), await MenuItem.new({ action: () => trigger("terminal.toggle"), - text: "Toggle Terminal", + text: t("desktop.menu.view.toggleTerminal"), accelerator: "Ctrl+`", }), await MenuItem.new({ action: () => trigger("fileTree.toggle"), - text: "Toggle File Tree", + text: t("desktop.menu.view.toggleFileTree"), }), await PredefinedMenuItem.new({ item: "Separator", }), await MenuItem.new({ action: () => trigger("common.goBack"), - text: "Back", + text: t("desktop.menu.view.back"), }), await MenuItem.new({ action: () => trigger("common.goForward"), - text: "Forward", + text: t("desktop.menu.view.forward"), }), await PredefinedMenuItem.new({ item: "Separator", }), await MenuItem.new({ action: () => trigger("session.previous"), - text: "Previous Session", + text: t("desktop.menu.view.previousSession"), accelerator: "Option+ArrowUp", }), await MenuItem.new({ action: () => trigger("session.next"), - text: "Next Session", + text: t("desktop.menu.view.nextSession"), accelerator: "Option+ArrowDown", }), await PredefinedMenuItem.new({ @@ -155,16 +155,16 @@ export async function createMenu(trigger: (id: string) => void) { ], }), await Submenu.new({ - text: "Help", + text: t("desktop.menu.help"), items: [ // missing native macos search await MenuItem.new({ action: () => openUrl("https://opencode.ai/docs"), - text: "OpenCode Documentation", + text: t("desktop.menu.help.documentation"), }), await MenuItem.new({ action: () => openUrl("https://discord.com/invite/opencode"), - text: "Support Forum", + text: t("desktop.menu.help.supportForum"), }), await PredefinedMenuItem.new({ item: "Separator", @@ -177,11 +177,11 @@ export async function createMenu(trigger: (id: string) => void) { }), await MenuItem.new({ action: () => openUrl("https://github.com/anomalyco/opencode/issues/new?template=feature_request.yml"), - text: "Share Feedback", + text: t("desktop.menu.help.shareFeedback"), }), await MenuItem.new({ action: () => openUrl("https://github.com/anomalyco/opencode/issues/new?template=bug_report.yml"), - text: "Report a Bug", + text: t("desktop.menu.help.reportBug"), }), ], }), diff --git a/packages/enterprise/package.json b/packages/enterprise/package.json index fae66ab31a..1b14e3f142 100644 --- a/packages/enterprise/package.json +++ b/packages/enterprise/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/enterprise", - "version": "1.2.10", + "version": "1.2.24", "private": true, "type": "module", "license": "MIT", diff --git a/packages/enterprise/src/app.tsx b/packages/enterprise/src/app.tsx index 6f9cdcafb8..b73888ec5d 100644 --- a/packages/enterprise/src/app.tsx +++ b/packages/enterprise/src/app.tsx @@ -56,8 +56,9 @@ function detectLocale() { function UiI18nBridge(props: ParentProps) { const locale = createMemo(() => detectLocale()) + const zh = uiZh as Partial> const t = (key: keyof typeof uiEn, params?: UiI18nParams) => { - const value = locale() === "zh" ? (uiZh[key] ?? uiEn[key]) : uiEn[key] + const value = locale() === "zh" ? (zh[key] ?? uiEn[key]) : uiEn[key] const text = value ?? String(key) return resolveTemplate(text, params) } diff --git a/packages/enterprise/src/core/share.ts b/packages/enterprise/src/core/share.ts index d7f5c8b8d5..c6291b75d2 100644 --- a/packages/enterprise/src/core/share.ts +++ b/packages/enterprise/src/core/share.ts @@ -1,10 +1,8 @@ import { FileDiff, Message, Model, Part, Session } from "@opencode-ai/sdk/v2" import { fn } from "@opencode-ai/util/fn" import { iife } from "@opencode-ai/util/iife" -import { Identifier } from "@opencode-ai/util/identifier" import z from "zod" import { Storage } from "./storage" -import { Binary } from "@opencode-ai/util/binary" export namespace Share { export const Info = z.object({ @@ -38,6 +36,81 @@ export namespace Share { ]) export type Data = z.infer + type Snapshot = { + data: Data[] + } + + type Compaction = { + event?: string + data: Data[] + } + + function key(item: Data) { + switch (item.type) { + case "session": + return "session" + case "message": + return `message/${item.data.id}` + case "part": + return `part/${item.data.messageID}/${item.data.id}` + case "session_diff": + return "session_diff" + case "model": + return "model" + } + } + + function merge(...items: Data[][]) { + const map = new Map() + for (const list of items) { + for (const item of list) { + map.set(key(item), item) + } + } + return Array.from(map.entries()) + .sort(([a], [b]) => a.localeCompare(b)) + .map(([, item]) => item) + } + + async function readSnapshot(shareID: string) { + return (await Storage.read(["share_snapshot", shareID]))?.data + } + + async function writeSnapshot(shareID: string, data: Data[]) { + await Storage.write(["share_snapshot", shareID], { data }) + } + + async function legacy(shareID: string) { + const compaction: Compaction = (await Storage.read(["share_compaction", shareID])) ?? { + data: [], + event: undefined, + } + const list = await Storage.list({ + prefix: ["share_event", shareID], + before: compaction.event, + }).then((x) => x.toReversed()) + if (list.length === 0) { + if (compaction.data.length > 0) await writeSnapshot(shareID, compaction.data) + return compaction.data + } + + const next = merge( + compaction.data, + await Promise.all(list.map(async (event) => await Storage.read(event))).then((x) => + x.flatMap((item) => item ?? []), + ), + ) + + await Promise.all([ + Storage.write(["share_compaction", shareID], { + event: list.at(-1)?.at(-1), + data: next, + }), + writeSnapshot(shareID, next), + ]) + return next + } + export const create = fn(z.object({ sessionID: z.string() }), async (body) => { const isTest = process.env.NODE_ENV === "test" || body.sessionID.startsWith("test_") const info: Info = { @@ -47,7 +120,7 @@ export namespace Share { } const exists = await get(info.id) if (exists) throw new Errors.AlreadyExists(info.id) - await Storage.write(["share", info.id], info) + await Promise.all([Storage.write(["share", info.id], info), writeSnapshot(info.id, [])]) return info }) @@ -60,8 +133,13 @@ export namespace Share { if (!share) throw new Errors.NotFound(body.id) if (share.secret !== body.secret) throw new Errors.InvalidSecret(body.id) await Storage.remove(["share", body.id]) - const list = await Storage.list({ prefix: ["share_data", body.id] }) - for (const item of list) { + const groups = await Promise.all([ + Storage.list({ prefix: ["share_snapshot", body.id] }), + Storage.list({ prefix: ["share_compaction", body.id] }), + Storage.list({ prefix: ["share_event", body.id] }), + Storage.list({ prefix: ["share_data", body.id] }), + ]) + for (const item of groups.flat()) { await Storage.remove(item) } }) @@ -75,59 +153,13 @@ export namespace Share { const share = await get(input.share.id) if (!share) throw new Errors.NotFound(input.share.id) if (share.secret !== input.share.secret) throw new Errors.InvalidSecret(input.share.id) - await Storage.write(["share_event", input.share.id, Identifier.descending()], input.data) + const data = (await readSnapshot(input.share.id)) ?? (await legacy(input.share.id)) + await writeSnapshot(input.share.id, merge(data, input.data)) }, ) - type Compaction = { - event?: string - data: Data[] - } - export async function data(shareID: string) { - console.log("reading compaction") - const compaction: Compaction = (await Storage.read(["share_compaction", shareID])) ?? { - data: [], - event: undefined, - } - console.log("reading pending events") - const list = await Storage.list({ - prefix: ["share_event", shareID], - before: compaction.event, - }).then((x) => x.toReversed()) - - console.log("compacting", list.length) - - if (list.length > 0) { - const data = await Promise.all(list.map(async (event) => await Storage.read(event))).then((x) => x.flat()) - for (const item of data) { - if (!item) continue - const key = (item: Data) => { - switch (item.type) { - case "session": - return "session" - case "message": - return `message/${item.data.id}` - case "part": - return `${item.data.messageID}/${item.data.id}` - case "session_diff": - return "session_diff" - case "model": - return "model" - } - } - const id = key(item) - const result = Binary.search(compaction.data, id, key) - if (result.found) { - compaction.data[result.index] = item - } else { - compaction.data.splice(result.index, 0, item) - } - } - compaction.event = list.at(-1)?.at(-1) - await Storage.write(["share_compaction", shareID], compaction) - } - return compaction.data + return (await readSnapshot(shareID)) ?? legacy(shareID) } export const syncOld = fn( diff --git a/packages/enterprise/src/routes/api/[...path].ts b/packages/enterprise/src/routes/api/[...path].ts index e77c00de92..f97788bd03 100644 --- a/packages/enterprise/src/routes/api/[...path].ts +++ b/packages/enterprise/src/routes/api/[...path].ts @@ -108,6 +108,7 @@ app validator("param", z.object({ shareID: z.string() })), async (c) => { const { shareID } = c.req.valid("param") + c.header("Cache-Control", "public, max-age=30, s-maxage=300, stale-while-revalidate=86400") return c.json(await Share.data(shareID)) }, ) diff --git a/packages/enterprise/src/routes/share/[shareID].tsx b/packages/enterprise/src/routes/share/[shareID].tsx index eb830e4a64..e755ea75a1 100644 --- a/packages/enterprise/src/routes/share/[shareID].tsx +++ b/packages/enterprise/src/routes/share/[shareID].tsx @@ -2,16 +2,14 @@ import { FileDiff, Message, Model, Part, Session, SessionStatus, UserMessage } f import { SessionTurn } from "@opencode-ai/ui/session-turn" import { SessionReview } from "@opencode-ai/ui/session-review" import { DataProvider } from "@opencode-ai/ui/context" -import { DiffComponentProvider } from "@opencode-ai/ui/context/diff" -import { CodeComponentProvider } from "@opencode-ai/ui/context/code" +import { FileComponentProvider } from "@opencode-ai/ui/context/file" import { WorkerPoolProvider } from "@opencode-ai/ui/context/worker-pool" import { createAsync, query, useParams } from "@solidjs/router" -import { createEffect, createMemo, ErrorBoundary, For, Match, Show, Switch } from "solid-js" +import { createMemo, createSignal, ErrorBoundary, For, Match, Show, Switch } from "solid-js" import { Share } from "~/core/share" import { Logo, Mark } from "@opencode-ai/ui/logo" import { IconButton } from "@opencode-ai/ui/icon-button" import { ProviderIcon } from "@opencode-ai/ui/provider-icon" -import { createDefaultOptions } from "@opencode-ai/ui/pierre" import { iife } from "@opencode-ai/util/iife" import { Binary } from "@opencode-ai/util/binary" import { NamedError } from "@opencode-ai/util/error" @@ -21,15 +19,12 @@ import z from "zod" import NotFound from "../[...404]" import { Tabs } from "@opencode-ai/ui/tabs" import { MessageNav } from "@opencode-ai/ui/message-nav" -import { preloadMultiFileDiff, PreloadMultiFileDiffResult } from "@pierre/diffs/ssr" -import { Diff as SSRDiff } from "@opencode-ai/ui/diff-ssr" +import { FileSSR } from "@opencode-ai/ui/file-ssr" import { clientOnly } from "@solidjs/start" -import { type IconName } from "@opencode-ai/ui/icons/provider" import { Meta, Title } from "@solidjs/meta" import { Base64 } from "js-base64" +import { getRequestEvent } from "solid-js/web" -const ClientOnlyDiff = clientOnly(() => import("@opencode-ai/ui/diff").then((m) => ({ default: m.Diff }))) -const ClientOnlyCode = clientOnly(() => import("@opencode-ai/ui/code").then((m) => ({ default: m.Code }))) const ClientOnlyWorkerPoolProvider = clientOnly(() => import("@opencode-ai/ui/pierre/worker").then((m) => ({ default: (props: { children: any }) => ( @@ -58,12 +53,6 @@ const getData = query(async (shareID) => { session_diff: { [sessionID: string]: FileDiff[] } - session_diff_preload: { - [sessionID: string]: PreloadMultiFileDiffResult[] - } - session_diff_preload_split: { - [sessionID: string]: PreloadMultiFileDiffResult[] - } session_status: { [sessionID: string]: SessionStatus } @@ -83,12 +72,6 @@ const getData = query(async (shareID) => { session_diff: { [share.sessionID]: [], }, - session_diff_preload: { - [share.sessionID]: [], - }, - session_diff_preload_split: { - [share.sessionID]: [], - }, session_status: { [share.sessionID]: { type: "idle", @@ -105,28 +88,6 @@ const getData = query(async (shareID) => { break case "session_diff": result.session_diff[share.sessionID] = item.data - await Promise.all([ - Promise.all( - item.data.map(async (diff) => - preloadMultiFileDiff({ - oldFile: { name: diff.file, contents: diff.before }, - newFile: { name: diff.file, contents: diff.after }, - options: createDefaultOptions("unified"), - // annotations, - }), - ), - ).then((r) => (result.session_diff_preload[share.sessionID] = r)), - Promise.all( - item.data.map(async (diff) => - preloadMultiFileDiff({ - oldFile: { name: diff.file, contents: diff.before }, - newFile: { name: diff.file, contents: diff.after }, - options: createDefaultOptions("split"), - // annotations, - }), - ), - ).then((r) => (result.session_diff_preload_split[share.sessionID] = r)), - ]) break case "message": result.message[item.data.sessionID] = result.message[item.data.sessionID] ?? [] @@ -147,17 +108,15 @@ const getData = query(async (shareID) => { }, "getShareData") export default function () { + getRequestEvent()?.response.headers.set( + "Cache-Control", + "public, max-age=30, s-maxage=300, stale-while-revalidate=86400", + ) + const params = useParams() const data = createAsync(async () => { if (!params.shareID) throw new Error("Missing shareID") - const now = Date.now() - const data = getData(params.shareID) - console.log("getData", Date.now() - now) - return data - }) - - createEffect(() => { - console.log(data()) + return getData(params.shareID) }) return ( @@ -218,252 +177,216 @@ export default function () { - - - - {iife(() => { - const [store, setStore] = createStore({ - messageId: undefined as string | undefined, - }) - const messages = createMemo(() => - data().sessionID - ? (data().message[data().sessionID]?.filter((m) => m.role === "user") ?? []).sort( - (a, b) => a.time.created - b.time.created, - ) - : [], - ) - const firstUserMessage = createMemo(() => messages().at(0)) - const activeMessage = createMemo( - () => messages().find((m) => m.id === store.messageId) ?? firstUserMessage(), - ) - function setActiveMessage(message: UserMessage | undefined) { - if (message) { - setStore("messageId", message.id) - } else { - setStore("messageId", undefined) - } + + + {iife(() => { + const [store, setStore] = createStore({ + messageId: undefined as string | undefined, + }) + const messages = createMemo(() => + data().sessionID + ? (data().message[data().sessionID]?.filter((m) => m.role === "user") ?? []).sort( + (a, b) => a.time.created - b.time.created, + ) + : [], + ) + const firstUserMessage = createMemo(() => messages().at(0)) + const activeMessage = createMemo( + () => messages().find((m) => m.id === store.messageId) ?? firstUserMessage(), + ) + function setActiveMessage(message: UserMessage | undefined) { + if (message) { + setStore("messageId", message.id) + } else { + setStore("messageId", undefined) } - const provider = createMemo(() => activeMessage()?.model?.providerID) - const modelID = createMemo(() => activeMessage()?.model?.modelID) - const model = createMemo(() => data().model[data().sessionID]?.find((m) => m.id === modelID())) - const diffs = createMemo(() => { - const diffs = data().session_diff[data().sessionID] ?? [] - const preloaded = data().session_diff_preload[data().sessionID] ?? [] - return diffs.map((diff) => ({ - ...diff, - preloaded: preloaded.find((d) => d.newFile.name === diff.file), - })) - }) - const splitDiffs = createMemo(() => { - const diffs = data().session_diff[data().sessionID] ?? [] - const preloaded = data().session_diff_preload_split[data().sessionID] ?? [] - return diffs.map((diff) => ({ - ...diff, - preloaded: preloaded.find((d) => d.newFile.name === diff.file), - })) - }) + } + const provider = createMemo(() => activeMessage()?.model?.providerID) + const modelID = createMemo(() => activeMessage()?.model?.modelID) + const model = createMemo(() => data().model[data().sessionID]?.find((m) => m.id === modelID())) + const diffs = createMemo(() => data().session_diff[data().sessionID] ?? []) + const [diffStyle, setDiffStyle] = createSignal<"unified" | "split">("unified") - const title = () => ( -
    -
    -
    - -
    v{info().version}
    -
    -
    -
    - -
    {model()?.name ?? modelID()}
    -
    -
    - {DateTime.fromMillis(info().time.created).toFormat("dd MMM yyyy, HH:mm")} -
    -
    + const title = () => ( +
    +
    +
    + +
    v{info().version}
    -
    {info().title}
    -
    - ) - - const turns = () => ( -
    -
    {title()}
    -
    - - {(message) => ( - - )} - -
    -
    - +
    +
    + + + +
    {model()?.name ?? modelID()}
    +
    +
    + {DateTime.fromMillis(info().time.created).toFormat("dd MMM yyyy, HH:mm")} +
    - ) +
    {info().title}
    +
    + ) - const wide = createMemo(() => diffs().length === 0) + const turns = () => ( +
    +
    {title()}
    +
    + + {(message) => ( + + )} + +
    +
    + +
    +
    + ) - return ( -
    -
    -
    - - - -
    -
    - - -
    -
    -
    + const wide = createMemo(() => diffs().length === 0) + + return ( +
    +
    +
    + + + +
    +
    + + +
    +
    +
    +
    -
    +
    + 1}> + + + - {title()} -
    -
    - 1}> - - - -
    - -
    -
    -
    +
    + +
    +
    - 0}> - -
    +
    + 0}> +
    + +
    +
    +
    + + 0}> + + + + Session + + + {diffs().length} Files Changed + + + + {turns()} + +
    - - 0}> - - - - Session - - - {diffs().length} Files Changed - - - - {turns()} - - - - - -
    - {turns()} -
    -
    -
    -
    + + + + +
    + {turns()} +
    +
    +
    - ) - })} - - - +
    + ) + })} + + ) diff --git a/packages/enterprise/sst-env.d.ts b/packages/enterprise/sst-env.d.ts index 73f83d1676..23ae6e44bf 100644 --- a/packages/enterprise/sst-env.d.ts +++ b/packages/enterprise/sst-env.d.ts @@ -119,10 +119,6 @@ declare module "sst" { "type": "sst.cloudflare.StaticSite" "url": string } - "ZEN_BLACK_LIMITS": { - "type": "sst.sst.Secret" - "value": string - } "ZEN_BLACK_PRICE": { "plan100": string "plan20": string @@ -130,6 +126,15 @@ declare module "sst" { "product": string "type": "sst.sst.Linkable" } + "ZEN_LIMITS": { + "type": "sst.sst.Secret" + "value": string + } + "ZEN_LITE_PRICE": { + "price": string + "product": string + "type": "sst.sst.Linkable" + } "ZEN_MODELS1": { "type": "sst.sst.Secret" "value": string diff --git a/packages/enterprise/test/core/share.test.ts b/packages/enterprise/test/core/share.test.ts index 9e9c06db38..d49d4b7639 100644 --- a/packages/enterprise/test/core/share.test.ts +++ b/packages/enterprise/test/core/share.test.ts @@ -30,8 +30,8 @@ describe.concurrent("core.share", () => { data, }) - const events = await Storage.list({ prefix: ["share_event", share.id] }) - expect(events.length).toBe(1) + const snapshot = await Storage.read<{ data: Share.Data[] }>(["share_snapshot", share.id]) + expect(snapshot?.data).toHaveLength(1) await Share.remove({ id: share.id, secret: share.secret }) }) @@ -64,8 +64,8 @@ describe.concurrent("core.share", () => { data: data2, }) - const events = await Storage.list({ prefix: ["share_event", share.id] }) - expect(events.length).toBe(2) + const snapshot = await Storage.read<{ data: Share.Data[] }>(["share_snapshot", share.id]) + expect(snapshot?.data).toHaveLength(2) await Share.remove({ id: share.id, secret: share.secret }) }) @@ -194,6 +194,28 @@ describe.concurrent("core.share", () => { await Share.remove({ id: share.id, secret: share.secret }) }) + test("should migrate legacy event data into the snapshot", async () => { + const sessionID = Identifier.descending() + const share = await Share.create({ sessionID }) + const data: Share.Data[] = [ + { + type: "part", + data: { id: "part1", sessionID, messageID: "msg1", type: "text", text: "Hello" }, + }, + ] + + await Storage.remove(["share_snapshot", share.id]) + await Storage.write(["share_event", share.id, Identifier.descending()], data) + + const result = await Share.data(share.id) + const snapshot = await Storage.read<{ data: Share.Data[] }>(["share_snapshot", share.id]) + + expect(result).toHaveLength(1) + expect(snapshot?.data).toHaveLength(1) + + await Share.remove({ id: share.id, secret: share.secret }) + }) + test("should throw error for invalid secret", async () => { const sessionID = Identifier.descending() const share = await Share.create({ sessionID }) diff --git a/packages/extensions/zed/extension.toml b/packages/extensions/zed/extension.toml index a112d793fd..44cdeb9d94 100644 --- a/packages/extensions/zed/extension.toml +++ b/packages/extensions/zed/extension.toml @@ -1,7 +1,7 @@ id = "opencode" name = "OpenCode" description = "The open source coding agent." -version = "1.2.10" +version = "1.2.24" schema_version = 1 authors = ["Anomaly"] repository = "https://github.com/anomalyco/opencode" @@ -11,26 +11,26 @@ name = "OpenCode" icon = "./icons/opencode.svg" [agent_servers.opencode.targets.darwin-aarch64] -archive = "https://github.com/anomalyco/opencode/releases/download/v1.2.10/opencode-darwin-arm64.zip" +archive = "https://github.com/anomalyco/opencode/releases/download/v1.2.24/opencode-darwin-arm64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.darwin-x86_64] -archive = "https://github.com/anomalyco/opencode/releases/download/v1.2.10/opencode-darwin-x64.zip" +archive = "https://github.com/anomalyco/opencode/releases/download/v1.2.24/opencode-darwin-x64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.linux-aarch64] -archive = "https://github.com/anomalyco/opencode/releases/download/v1.2.10/opencode-linux-arm64.tar.gz" +archive = "https://github.com/anomalyco/opencode/releases/download/v1.2.24/opencode-linux-arm64.tar.gz" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.linux-x86_64] -archive = "https://github.com/anomalyco/opencode/releases/download/v1.2.10/opencode-linux-x64.tar.gz" +archive = "https://github.com/anomalyco/opencode/releases/download/v1.2.24/opencode-linux-x64.tar.gz" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.windows-x86_64] -archive = "https://github.com/anomalyco/opencode/releases/download/v1.2.10/opencode-windows-x64.zip" +archive = "https://github.com/anomalyco/opencode/releases/download/v1.2.24/opencode-windows-x64.zip" cmd = "./opencode.exe" args = ["acp"] diff --git a/packages/function/package.json b/packages/function/package.json index c67be67096..7b64af1f99 100644 --- a/packages/function/package.json +++ b/packages/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/function", - "version": "1.2.10", + "version": "1.2.24", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/function/sst-env.d.ts b/packages/function/sst-env.d.ts index 73f83d1676..23ae6e44bf 100644 --- a/packages/function/sst-env.d.ts +++ b/packages/function/sst-env.d.ts @@ -119,10 +119,6 @@ declare module "sst" { "type": "sst.cloudflare.StaticSite" "url": string } - "ZEN_BLACK_LIMITS": { - "type": "sst.sst.Secret" - "value": string - } "ZEN_BLACK_PRICE": { "plan100": string "plan20": string @@ -130,6 +126,15 @@ declare module "sst" { "product": string "type": "sst.sst.Linkable" } + "ZEN_LIMITS": { + "type": "sst.sst.Secret" + "value": string + } + "ZEN_LITE_PRICE": { + "price": string + "product": string + "type": "sst.sst.Linkable" + } "ZEN_MODELS1": { "type": "sst.sst.Secret" "value": string diff --git a/packages/opencode/BUN_SHELL_MIGRATION_PLAN.md b/packages/opencode/BUN_SHELL_MIGRATION_PLAN.md new file mode 100644 index 0000000000..6cb21ac8f6 --- /dev/null +++ b/packages/opencode/BUN_SHELL_MIGRATION_PLAN.md @@ -0,0 +1,136 @@ +# Bun shell migration plan + +Practical phased replacement of Bun `$` calls. + +## Goal + +Replace runtime Bun shell template-tag usage in `packages/opencode/src` with a unified `Process` API in `util/process.ts`. + +Keep behavior stable while improving safety, testability, and observability. + +Current baseline from audit: + +- 143 runtime command invocations across 17 files +- 84 are git commands +- Largest hotspots: + - `src/cli/cmd/github.ts` (33) + - `src/worktree/index.ts` (22) + - `src/lsp/server.ts` (21) + - `src/installation/index.ts` (20) + - `src/snapshot/index.ts` (18) + +## Decisions + +- Extend `src/util/process.ts` (do not create a separate exec module). +- Proceed with phased migration for both git and non-git paths. +- Keep plugin `$` compatibility in 1.x and remove in 2.0. + +## Non-goals + +- Do not remove plugin `$` compatibility in this effort. +- Do not redesign command semantics beyond what is needed to preserve behavior. + +## Constraints + +- Keep migration phased, not big-bang. +- Minimize behavioral drift. +- Keep these explicit shell-only exceptions: + - `src/session/prompt.ts` raw command execution + - worktree start scripts in `src/worktree/index.ts` + +## Process API proposal (`src/util/process.ts`) + +Add higher-level wrappers on top of current spawn support. + +Core methods: + +- `Process.run(cmd, opts)` +- `Process.text(cmd, opts)` +- `Process.lines(cmd, opts)` +- `Process.status(cmd, opts)` +- `Process.shell(command, opts)` for intentional shell execution + +Git helpers: + +- `Process.git(args, opts)` +- `Process.gitText(args, opts)` + +Shared options: + +- `cwd`, `env`, `stdin`, `stdout`, `stderr`, `abort`, `timeout`, `kill` +- `allowFailure` / non-throw mode +- optional redaction + trace metadata + +Standard result shape: + +- `code`, `stdout`, `stderr`, `duration_ms`, `cmd` +- helpers like `text()` and `arrayBuffer()` where useful + +## Phased rollout + +### Phase 0: Foundation + +- Implement Process wrappers in `src/util/process.ts`. +- Refactor `src/util/git.ts` to use Process only. +- Add tests for exit handling, timeout, abort, and output capture. + +### Phase 1: High-impact hotspots + +Migrate these first: + +- `src/cli/cmd/github.ts` +- `src/worktree/index.ts` +- `src/lsp/server.ts` +- `src/installation/index.ts` +- `src/snapshot/index.ts` + +Within each file, migrate git paths first where applicable. + +### Phase 2: Remaining git-heavy files + +Migrate git-centric call sites to `Process.git*` helpers: + +- `src/file/index.ts` +- `src/project/vcs.ts` +- `src/file/watcher.ts` +- `src/storage/storage.ts` +- `src/cli/cmd/pr.ts` + +### Phase 3: Remaining non-git files + +Migrate residual non-git usages: + +- `src/cli/cmd/tui/util/clipboard.ts` +- `src/util/archive.ts` +- `src/file/ripgrep.ts` +- `src/tool/bash.ts` +- `src/cli/cmd/uninstall.ts` + +### Phase 4: Stabilize + +- Remove dead wrappers and one-off patterns. +- Keep plugin `$` compatibility isolated and documented as temporary. +- Create linked 2.0 task for plugin `$` removal. + +## Validation strategy + +- Unit tests for new `Process` methods and options. +- Integration tests on hotspot modules. +- Smoke tests for install, snapshot, worktree, and GitHub flows. +- Regression checks for output parsing behavior. + +## Risk mitigation + +- File-by-file PRs with small diffs. +- Preserve behavior first, simplify second. +- Keep shell-only exceptions explicit and documented. +- Add consistent error shaping and logging at Process layer. + +## Definition of done + +- Runtime Bun `$` usage in `packages/opencode/src` is removed except: + - approved shell-only exceptions + - temporary plugin compatibility path (1.x) +- Git paths use `Process.git*` consistently. +- CI and targeted smoke tests pass. +- 2.0 issue exists for plugin `$` removal. diff --git a/packages/opencode/migration/20260225215848_workspace/migration.sql b/packages/opencode/migration/20260225215848_workspace/migration.sql new file mode 100644 index 0000000000..5b1b4e5a47 --- /dev/null +++ b/packages/opencode/migration/20260225215848_workspace/migration.sql @@ -0,0 +1,7 @@ +CREATE TABLE `workspace` ( + `id` text PRIMARY KEY, + `branch` text, + `project_id` text NOT NULL, + `config` text NOT NULL, + CONSTRAINT `fk_workspace_project_id_project_id_fk` FOREIGN KEY (`project_id`) REFERENCES `project`(`id`) ON DELETE CASCADE +); diff --git a/packages/opencode/migration/20260225215848_workspace/snapshot.json b/packages/opencode/migration/20260225215848_workspace/snapshot.json new file mode 100644 index 0000000000..a75001d58f --- /dev/null +++ b/packages/opencode/migration/20260225215848_workspace/snapshot.json @@ -0,0 +1,959 @@ +{ + "version": "7", + "dialect": "sqlite", + "id": "1f1dbf2d-bf66-4b25-8af4-4ba7633b7e40", + "prevIds": ["d2736e43-700f-4e9e-8151-9f2f0d967bc8"], + "ddl": [ + { + "name": "workspace", + "entityType": "tables" + }, + { + "name": "control_account", + "entityType": "tables" + }, + { + "name": "project", + "entityType": "tables" + }, + { + "name": "message", + "entityType": "tables" + }, + { + "name": "part", + "entityType": "tables" + }, + { + "name": "permission", + "entityType": "tables" + }, + { + "name": "session", + "entityType": "tables" + }, + { + "name": "todo", + "entityType": "tables" + }, + { + "name": "session_share", + "entityType": "tables" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "workspace" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "branch", + "entityType": "columns", + "table": "workspace" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "project_id", + "entityType": "columns", + "table": "workspace" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "config", + "entityType": "columns", + "table": "workspace" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "email", + "entityType": "columns", + "table": "control_account" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "url", + "entityType": "columns", + "table": "control_account" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "access_token", + "entityType": "columns", + "table": "control_account" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "refresh_token", + "entityType": "columns", + "table": "control_account" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "token_expiry", + "entityType": "columns", + "table": "control_account" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "active", + "entityType": "columns", + "table": "control_account" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "control_account" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "control_account" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "project" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "worktree", + "entityType": "columns", + "table": "project" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "vcs", + "entityType": "columns", + "table": "project" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "name", + "entityType": "columns", + "table": "project" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "icon_url", + "entityType": "columns", + "table": "project" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "icon_color", + "entityType": "columns", + "table": "project" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "project" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "project" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_initialized", + "entityType": "columns", + "table": "project" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "sandboxes", + "entityType": "columns", + "table": "project" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "commands", + "entityType": "columns", + "table": "project" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "message" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "session_id", + "entityType": "columns", + "table": "message" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "message" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "message" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "data", + "entityType": "columns", + "table": "message" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "part" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "message_id", + "entityType": "columns", + "table": "part" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "session_id", + "entityType": "columns", + "table": "part" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "part" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "part" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "data", + "entityType": "columns", + "table": "part" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "project_id", + "entityType": "columns", + "table": "permission" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "permission" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "permission" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "data", + "entityType": "columns", + "table": "permission" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "session" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "project_id", + "entityType": "columns", + "table": "session" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "parent_id", + "entityType": "columns", + "table": "session" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "slug", + "entityType": "columns", + "table": "session" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "directory", + "entityType": "columns", + "table": "session" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "title", + "entityType": "columns", + "table": "session" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "version", + "entityType": "columns", + "table": "session" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "share_url", + "entityType": "columns", + "table": "session" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "summary_additions", + "entityType": "columns", + "table": "session" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "summary_deletions", + "entityType": "columns", + "table": "session" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "summary_files", + "entityType": "columns", + "table": "session" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "summary_diffs", + "entityType": "columns", + "table": "session" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "revert", + "entityType": "columns", + "table": "session" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "permission", + "entityType": "columns", + "table": "session" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "session" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "session" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_compacting", + "entityType": "columns", + "table": "session" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_archived", + "entityType": "columns", + "table": "session" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "session_id", + "entityType": "columns", + "table": "todo" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "content", + "entityType": "columns", + "table": "todo" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "status", + "entityType": "columns", + "table": "todo" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "priority", + "entityType": "columns", + "table": "todo" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "position", + "entityType": "columns", + "table": "todo" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "todo" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "todo" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "session_id", + "entityType": "columns", + "table": "session_share" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "session_share" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "secret", + "entityType": "columns", + "table": "session_share" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "url", + "entityType": "columns", + "table": "session_share" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "session_share" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "session_share" + }, + { + "columns": ["project_id"], + "tableTo": "project", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_workspace_project_id_project_id_fk", + "entityType": "fks", + "table": "workspace" + }, + { + "columns": ["session_id"], + "tableTo": "session", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_message_session_id_session_id_fk", + "entityType": "fks", + "table": "message" + }, + { + "columns": ["message_id"], + "tableTo": "message", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_part_message_id_message_id_fk", + "entityType": "fks", + "table": "part" + }, + { + "columns": ["project_id"], + "tableTo": "project", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_permission_project_id_project_id_fk", + "entityType": "fks", + "table": "permission" + }, + { + "columns": ["project_id"], + "tableTo": "project", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_session_project_id_project_id_fk", + "entityType": "fks", + "table": "session" + }, + { + "columns": ["session_id"], + "tableTo": "session", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_todo_session_id_session_id_fk", + "entityType": "fks", + "table": "todo" + }, + { + "columns": ["session_id"], + "tableTo": "session", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_session_share_session_id_session_id_fk", + "entityType": "fks", + "table": "session_share" + }, + { + "columns": ["email", "url"], + "nameExplicit": false, + "name": "control_account_pk", + "entityType": "pks", + "table": "control_account" + }, + { + "columns": ["session_id", "position"], + "nameExplicit": false, + "name": "todo_pk", + "entityType": "pks", + "table": "todo" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "workspace_pk", + "table": "workspace", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "project_pk", + "table": "project", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "message_pk", + "table": "message", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "part_pk", + "table": "part", + "entityType": "pks" + }, + { + "columns": ["project_id"], + "nameExplicit": false, + "name": "permission_pk", + "table": "permission", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "session_pk", + "table": "session", + "entityType": "pks" + }, + { + "columns": ["session_id"], + "nameExplicit": false, + "name": "session_share_pk", + "table": "session_share", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "session_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "message_session_idx", + "entityType": "indexes", + "table": "message" + }, + { + "columns": [ + { + "value": "message_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "part_message_idx", + "entityType": "indexes", + "table": "part" + }, + { + "columns": [ + { + "value": "session_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "part_session_idx", + "entityType": "indexes", + "table": "part" + }, + { + "columns": [ + { + "value": "project_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "session_project_idx", + "entityType": "indexes", + "table": "session" + }, + { + "columns": [ + { + "value": "parent_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "session_parent_idx", + "entityType": "indexes", + "table": "session" + }, + { + "columns": [ + { + "value": "session_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "todo_session_idx", + "entityType": "indexes", + "table": "todo" + } + ], + "renames": [] +} diff --git a/packages/opencode/migration/20260227213759_add_session_workspace_id/migration.sql b/packages/opencode/migration/20260227213759_add_session_workspace_id/migration.sql new file mode 100644 index 0000000000..f5488af218 --- /dev/null +++ b/packages/opencode/migration/20260227213759_add_session_workspace_id/migration.sql @@ -0,0 +1,2 @@ +ALTER TABLE `session` ADD `workspace_id` text;--> statement-breakpoint +CREATE INDEX `session_workspace_idx` ON `session` (`workspace_id`); \ No newline at end of file diff --git a/packages/opencode/migration/20260227213759_add_session_workspace_id/snapshot.json b/packages/opencode/migration/20260227213759_add_session_workspace_id/snapshot.json new file mode 100644 index 0000000000..8cd94d0052 --- /dev/null +++ b/packages/opencode/migration/20260227213759_add_session_workspace_id/snapshot.json @@ -0,0 +1,983 @@ +{ + "version": "7", + "dialect": "sqlite", + "id": "572fb732-56f4-4b1e-b981-77152c9980dd", + "prevIds": ["1f1dbf2d-bf66-4b25-8af4-4ba7633b7e40"], + "ddl": [ + { + "name": "workspace", + "entityType": "tables" + }, + { + "name": "control_account", + "entityType": "tables" + }, + { + "name": "project", + "entityType": "tables" + }, + { + "name": "message", + "entityType": "tables" + }, + { + "name": "part", + "entityType": "tables" + }, + { + "name": "permission", + "entityType": "tables" + }, + { + "name": "session", + "entityType": "tables" + }, + { + "name": "todo", + "entityType": "tables" + }, + { + "name": "session_share", + "entityType": "tables" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "workspace" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "branch", + "entityType": "columns", + "table": "workspace" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "project_id", + "entityType": "columns", + "table": "workspace" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "config", + "entityType": "columns", + "table": "workspace" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "email", + "entityType": "columns", + "table": "control_account" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "url", + "entityType": "columns", + "table": "control_account" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "access_token", + "entityType": "columns", + "table": "control_account" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "refresh_token", + "entityType": "columns", + "table": "control_account" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "token_expiry", + "entityType": "columns", + "table": "control_account" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "active", + "entityType": "columns", + "table": "control_account" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "control_account" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "control_account" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "project" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "worktree", + "entityType": "columns", + "table": "project" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "vcs", + "entityType": "columns", + "table": "project" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "name", + "entityType": "columns", + "table": "project" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "icon_url", + "entityType": "columns", + "table": "project" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "icon_color", + "entityType": "columns", + "table": "project" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "project" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "project" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_initialized", + "entityType": "columns", + "table": "project" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "sandboxes", + "entityType": "columns", + "table": "project" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "commands", + "entityType": "columns", + "table": "project" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "message" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "session_id", + "entityType": "columns", + "table": "message" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "message" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "message" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "data", + "entityType": "columns", + "table": "message" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "part" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "message_id", + "entityType": "columns", + "table": "part" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "session_id", + "entityType": "columns", + "table": "part" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "part" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "part" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "data", + "entityType": "columns", + "table": "part" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "project_id", + "entityType": "columns", + "table": "permission" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "permission" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "permission" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "data", + "entityType": "columns", + "table": "permission" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "session" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "project_id", + "entityType": "columns", + "table": "session" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "workspace_id", + "entityType": "columns", + "table": "session" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "parent_id", + "entityType": "columns", + "table": "session" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "slug", + "entityType": "columns", + "table": "session" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "directory", + "entityType": "columns", + "table": "session" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "title", + "entityType": "columns", + "table": "session" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "version", + "entityType": "columns", + "table": "session" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "share_url", + "entityType": "columns", + "table": "session" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "summary_additions", + "entityType": "columns", + "table": "session" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "summary_deletions", + "entityType": "columns", + "table": "session" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "summary_files", + "entityType": "columns", + "table": "session" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "summary_diffs", + "entityType": "columns", + "table": "session" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "revert", + "entityType": "columns", + "table": "session" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "permission", + "entityType": "columns", + "table": "session" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "session" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "session" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_compacting", + "entityType": "columns", + "table": "session" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_archived", + "entityType": "columns", + "table": "session" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "session_id", + "entityType": "columns", + "table": "todo" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "content", + "entityType": "columns", + "table": "todo" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "status", + "entityType": "columns", + "table": "todo" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "priority", + "entityType": "columns", + "table": "todo" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "position", + "entityType": "columns", + "table": "todo" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "todo" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "todo" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "session_id", + "entityType": "columns", + "table": "session_share" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "session_share" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "secret", + "entityType": "columns", + "table": "session_share" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "url", + "entityType": "columns", + "table": "session_share" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "session_share" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "session_share" + }, + { + "columns": ["project_id"], + "tableTo": "project", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_workspace_project_id_project_id_fk", + "entityType": "fks", + "table": "workspace" + }, + { + "columns": ["session_id"], + "tableTo": "session", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_message_session_id_session_id_fk", + "entityType": "fks", + "table": "message" + }, + { + "columns": ["message_id"], + "tableTo": "message", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_part_message_id_message_id_fk", + "entityType": "fks", + "table": "part" + }, + { + "columns": ["project_id"], + "tableTo": "project", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_permission_project_id_project_id_fk", + "entityType": "fks", + "table": "permission" + }, + { + "columns": ["project_id"], + "tableTo": "project", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_session_project_id_project_id_fk", + "entityType": "fks", + "table": "session" + }, + { + "columns": ["session_id"], + "tableTo": "session", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_todo_session_id_session_id_fk", + "entityType": "fks", + "table": "todo" + }, + { + "columns": ["session_id"], + "tableTo": "session", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_session_share_session_id_session_id_fk", + "entityType": "fks", + "table": "session_share" + }, + { + "columns": ["email", "url"], + "nameExplicit": false, + "name": "control_account_pk", + "entityType": "pks", + "table": "control_account" + }, + { + "columns": ["session_id", "position"], + "nameExplicit": false, + "name": "todo_pk", + "entityType": "pks", + "table": "todo" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "workspace_pk", + "table": "workspace", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "project_pk", + "table": "project", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "message_pk", + "table": "message", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "part_pk", + "table": "part", + "entityType": "pks" + }, + { + "columns": ["project_id"], + "nameExplicit": false, + "name": "permission_pk", + "table": "permission", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "session_pk", + "table": "session", + "entityType": "pks" + }, + { + "columns": ["session_id"], + "nameExplicit": false, + "name": "session_share_pk", + "table": "session_share", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "session_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "message_session_idx", + "entityType": "indexes", + "table": "message" + }, + { + "columns": [ + { + "value": "message_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "part_message_idx", + "entityType": "indexes", + "table": "part" + }, + { + "columns": [ + { + "value": "session_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "part_session_idx", + "entityType": "indexes", + "table": "part" + }, + { + "columns": [ + { + "value": "project_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "session_project_idx", + "entityType": "indexes", + "table": "session" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "session_workspace_idx", + "entityType": "indexes", + "table": "session" + }, + { + "columns": [ + { + "value": "parent_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "session_parent_idx", + "entityType": "indexes", + "table": "session" + }, + { + "columns": [ + { + "value": "session_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "todo_session_idx", + "entityType": "indexes", + "table": "todo" + } + ], + "renames": [] +} diff --git a/packages/opencode/migration/20260303231226_add_workspace_fields/migration.sql b/packages/opencode/migration/20260303231226_add_workspace_fields/migration.sql new file mode 100644 index 0000000000..185de59133 --- /dev/null +++ b/packages/opencode/migration/20260303231226_add_workspace_fields/migration.sql @@ -0,0 +1,5 @@ +ALTER TABLE `workspace` ADD `type` text NOT NULL;--> statement-breakpoint +ALTER TABLE `workspace` ADD `name` text;--> statement-breakpoint +ALTER TABLE `workspace` ADD `directory` text;--> statement-breakpoint +ALTER TABLE `workspace` ADD `extra` text;--> statement-breakpoint +ALTER TABLE `workspace` DROP COLUMN `config`; \ No newline at end of file diff --git a/packages/opencode/migration/20260303231226_add_workspace_fields/snapshot.json b/packages/opencode/migration/20260303231226_add_workspace_fields/snapshot.json new file mode 100644 index 0000000000..4fe320a2cc --- /dev/null +++ b/packages/opencode/migration/20260303231226_add_workspace_fields/snapshot.json @@ -0,0 +1,1013 @@ +{ + "version": "7", + "dialect": "sqlite", + "id": "4ec9de62-88a7-4bec-91cc-0a759e84db21", + "prevIds": ["572fb732-56f4-4b1e-b981-77152c9980dd"], + "ddl": [ + { + "name": "workspace", + "entityType": "tables" + }, + { + "name": "control_account", + "entityType": "tables" + }, + { + "name": "project", + "entityType": "tables" + }, + { + "name": "message", + "entityType": "tables" + }, + { + "name": "part", + "entityType": "tables" + }, + { + "name": "permission", + "entityType": "tables" + }, + { + "name": "session", + "entityType": "tables" + }, + { + "name": "todo", + "entityType": "tables" + }, + { + "name": "session_share", + "entityType": "tables" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "workspace" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "type", + "entityType": "columns", + "table": "workspace" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "branch", + "entityType": "columns", + "table": "workspace" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "name", + "entityType": "columns", + "table": "workspace" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "directory", + "entityType": "columns", + "table": "workspace" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "extra", + "entityType": "columns", + "table": "workspace" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "project_id", + "entityType": "columns", + "table": "workspace" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "email", + "entityType": "columns", + "table": "control_account" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "url", + "entityType": "columns", + "table": "control_account" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "access_token", + "entityType": "columns", + "table": "control_account" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "refresh_token", + "entityType": "columns", + "table": "control_account" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "token_expiry", + "entityType": "columns", + "table": "control_account" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "active", + "entityType": "columns", + "table": "control_account" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "control_account" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "control_account" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "project" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "worktree", + "entityType": "columns", + "table": "project" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "vcs", + "entityType": "columns", + "table": "project" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "name", + "entityType": "columns", + "table": "project" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "icon_url", + "entityType": "columns", + "table": "project" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "icon_color", + "entityType": "columns", + "table": "project" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "project" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "project" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_initialized", + "entityType": "columns", + "table": "project" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "sandboxes", + "entityType": "columns", + "table": "project" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "commands", + "entityType": "columns", + "table": "project" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "message" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "session_id", + "entityType": "columns", + "table": "message" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "message" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "message" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "data", + "entityType": "columns", + "table": "message" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "part" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "message_id", + "entityType": "columns", + "table": "part" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "session_id", + "entityType": "columns", + "table": "part" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "part" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "part" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "data", + "entityType": "columns", + "table": "part" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "project_id", + "entityType": "columns", + "table": "permission" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "permission" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "permission" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "data", + "entityType": "columns", + "table": "permission" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "session" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "project_id", + "entityType": "columns", + "table": "session" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "workspace_id", + "entityType": "columns", + "table": "session" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "parent_id", + "entityType": "columns", + "table": "session" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "slug", + "entityType": "columns", + "table": "session" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "directory", + "entityType": "columns", + "table": "session" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "title", + "entityType": "columns", + "table": "session" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "version", + "entityType": "columns", + "table": "session" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "share_url", + "entityType": "columns", + "table": "session" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "summary_additions", + "entityType": "columns", + "table": "session" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "summary_deletions", + "entityType": "columns", + "table": "session" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "summary_files", + "entityType": "columns", + "table": "session" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "summary_diffs", + "entityType": "columns", + "table": "session" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "revert", + "entityType": "columns", + "table": "session" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "permission", + "entityType": "columns", + "table": "session" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "session" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "session" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_compacting", + "entityType": "columns", + "table": "session" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_archived", + "entityType": "columns", + "table": "session" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "session_id", + "entityType": "columns", + "table": "todo" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "content", + "entityType": "columns", + "table": "todo" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "status", + "entityType": "columns", + "table": "todo" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "priority", + "entityType": "columns", + "table": "todo" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "position", + "entityType": "columns", + "table": "todo" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "todo" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "todo" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "session_id", + "entityType": "columns", + "table": "session_share" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "session_share" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "secret", + "entityType": "columns", + "table": "session_share" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "url", + "entityType": "columns", + "table": "session_share" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "session_share" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "session_share" + }, + { + "columns": ["project_id"], + "tableTo": "project", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_workspace_project_id_project_id_fk", + "entityType": "fks", + "table": "workspace" + }, + { + "columns": ["session_id"], + "tableTo": "session", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_message_session_id_session_id_fk", + "entityType": "fks", + "table": "message" + }, + { + "columns": ["message_id"], + "tableTo": "message", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_part_message_id_message_id_fk", + "entityType": "fks", + "table": "part" + }, + { + "columns": ["project_id"], + "tableTo": "project", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_permission_project_id_project_id_fk", + "entityType": "fks", + "table": "permission" + }, + { + "columns": ["project_id"], + "tableTo": "project", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_session_project_id_project_id_fk", + "entityType": "fks", + "table": "session" + }, + { + "columns": ["session_id"], + "tableTo": "session", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_todo_session_id_session_id_fk", + "entityType": "fks", + "table": "todo" + }, + { + "columns": ["session_id"], + "tableTo": "session", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_session_share_session_id_session_id_fk", + "entityType": "fks", + "table": "session_share" + }, + { + "columns": ["email", "url"], + "nameExplicit": false, + "name": "control_account_pk", + "entityType": "pks", + "table": "control_account" + }, + { + "columns": ["session_id", "position"], + "nameExplicit": false, + "name": "todo_pk", + "entityType": "pks", + "table": "todo" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "workspace_pk", + "table": "workspace", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "project_pk", + "table": "project", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "message_pk", + "table": "message", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "part_pk", + "table": "part", + "entityType": "pks" + }, + { + "columns": ["project_id"], + "nameExplicit": false, + "name": "permission_pk", + "table": "permission", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "session_pk", + "table": "session", + "entityType": "pks" + }, + { + "columns": ["session_id"], + "nameExplicit": false, + "name": "session_share_pk", + "table": "session_share", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "session_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "message_session_idx", + "entityType": "indexes", + "table": "message" + }, + { + "columns": [ + { + "value": "message_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "part_message_idx", + "entityType": "indexes", + "table": "part" + }, + { + "columns": [ + { + "value": "session_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "part_session_idx", + "entityType": "indexes", + "table": "part" + }, + { + "columns": [ + { + "value": "project_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "session_project_idx", + "entityType": "indexes", + "table": "session" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "session_workspace_idx", + "entityType": "indexes", + "table": "session" + }, + { + "columns": [ + { + "value": "parent_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "session_parent_idx", + "entityType": "indexes", + "table": "session" + }, + { + "columns": [ + { + "value": "session_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "todo_session_idx", + "entityType": "indexes", + "table": "todo" + } + ], + "renames": [] +} diff --git a/packages/opencode/package.json b/packages/opencode/package.json index f891273737..4e4f46b0c6 100644 --- a/packages/opencode/package.json +++ b/packages/opencode/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "1.2.10", + "version": "1.2.24", "name": "opencode", "type": "module", "license": "MIT", @@ -41,11 +41,13 @@ "@types/babel__core": "7.20.5", "@types/bun": "catalog:", "@types/mime-types": "3.0.1", + "@types/semver": "^7.5.8", "@types/turndown": "5.0.5", "@types/yargs": "17.0.33", + "@types/which": "3.0.4", "@typescript/native-preview": "catalog:", - "drizzle-kit": "1.0.0-beta.12-a5629fb", - "drizzle-orm": "1.0.0-beta.12-a5629fb", + "drizzle-kit": "1.0.0-beta.16-ea816b6", + "drizzle-orm": "1.0.0-beta.16-ea816b6", "typescript": "catalog:", "vscode-languageserver-types": "3.17.5", "why-is-node-running": "3.2.2", @@ -89,8 +91,8 @@ "@opencode-ai/sdk": "workspace:*", "@opencode-ai/util": "workspace:*", "@openrouter/ai-sdk-provider": "1.5.4", - "@opentui/core": "0.1.79", - "@opentui/solid": "0.1.79", + "@opentui/core": "0.1.86", + "@opentui/solid": "0.1.86", "@parcel/watcher": "2.5.1", "@pierre/diffs": "catalog:", "@solid-primitives/event-bus": "1.1.2", @@ -105,7 +107,7 @@ "clipboardy": "4.0.0", "decimal.js": "10.5.0", "diff": "catalog:", - "drizzle-orm": "1.0.0-beta.12-a5629fb", + "drizzle-orm": "1.0.0-beta.16-ea816b6", "fuzzysort": "3.1.0", "glob": "13.0.5", "google-auth-library": "10.5.0", @@ -120,6 +122,7 @@ "opentui-spinner": "0.0.6", "partial-json": "0.1.7", "remeda": "catalog:", + "semver": "^7.6.3", "solid-js": "catalog:", "strip-ansi": "7.1.2", "tree-sitter-bash": "0.25.0", @@ -127,12 +130,13 @@ "ulid": "catalog:", "vscode-jsonrpc": "8.2.1", "web-tree-sitter": "0.25.10", + "which": "6.0.1", "xdg-basedir": "5.1.0", "yargs": "18.0.0", "zod": "catalog:", "zod-to-json-schema": "3.24.5" }, "overrides": { - "drizzle-orm": "1.0.0-beta.12-a5629fb" + "drizzle-orm": "1.0.0-beta.16-ea816b6" } } diff --git a/packages/opencode/script/build.ts b/packages/opencode/script/build.ts index 34e80d71a0..4ff610862d 100755 --- a/packages/opencode/script/build.ts +++ b/packages/opencode/script/build.ts @@ -4,7 +4,7 @@ import { $ } from "bun" import fs from "fs" import path from "path" import { fileURLToPath } from "url" -import solidPlugin from "../node_modules/@opentui/solid/scripts/solid-plugin" +import solidPlugin from "@opentui/solid/bun-plugin" const __filename = fileURLToPath(import.meta.url) const __dirname = path.dirname(__filename) @@ -51,7 +51,7 @@ const migrations = await Promise.all( Number(match[6]), ) : 0 - return { sql, timestamp } + return { sql, timestamp, name } }), ) console.log(`Loaded ${migrations.length} migrations`) @@ -161,7 +161,9 @@ for (const item of targets) { console.log(`building ${name}`) await $`mkdir -p dist/${name}/bin` - const parserWorker = fs.realpathSync(path.resolve(dir, "./node_modules/@opentui/core/parser.worker.js")) + const localPath = path.resolve(dir, "node_modules/@opentui/core/parser.worker.js") + const rootPath = path.resolve(dir, "../../node_modules/@opentui/core/parser.worker.js") + const parserWorker = fs.realpathSync(fs.existsSync(localPath) ? localPath : rootPath) const workerPath = "./src/cli/cmd/tui/worker.ts" // Use platform-specific bunfs root path based on target OS diff --git a/packages/opencode/script/schema.ts b/packages/opencode/script/schema.ts index 585701c951..61d11ea7c9 100755 --- a/packages/opencode/script/schema.ts +++ b/packages/opencode/script/schema.ts @@ -2,46 +2,62 @@ import { z } from "zod" import { Config } from "../src/config/config" +import { TuiConfig } from "../src/config/tui" -const file = process.argv[2] -console.log(file) +function generate(schema: z.ZodType) { + const result = z.toJSONSchema(schema, { + io: "input", // Generate input shape (treats optional().default() as not required) + /** + * We'll use the `default` values of the field as the only value in `examples`. + * This will ensure no docs are needed to be read, as the configuration is + * self-documenting. + * + * See https://json-schema.org/draft/2020-12/draft-bhutton-json-schema-validation-00#rfc.section.9.5 + */ + override(ctx) { + const schema = ctx.jsonSchema -const result = z.toJSONSchema(Config.Info, { - io: "input", // Generate input shape (treats optional().default() as not required) - /** - * We'll use the `default` values of the field as the only value in `examples`. - * This will ensure no docs are needed to be read, as the configuration is - * self-documenting. - * - * See https://json-schema.org/draft/2020-12/draft-bhutton-json-schema-validation-00#rfc.section.9.5 - */ - override(ctx) { - const schema = ctx.jsonSchema - - // Preserve strictness: set additionalProperties: false for objects - if (schema && typeof schema === "object" && schema.type === "object" && schema.additionalProperties === undefined) { - schema.additionalProperties = false - } - - // Add examples and default descriptions for string fields with defaults - if (schema && typeof schema === "object" && "type" in schema && schema.type === "string" && schema?.default) { - if (!schema.examples) { - schema.examples = [schema.default] + // Preserve strictness: set additionalProperties: false for objects + if ( + schema && + typeof schema === "object" && + schema.type === "object" && + schema.additionalProperties === undefined + ) { + schema.additionalProperties = false } - schema.description = [schema.description || "", `default: \`${schema.default}\``] - .filter(Boolean) - .join("\n\n") - .trim() - } - }, -}) as Record & { - allowComments?: boolean - allowTrailingCommas?: boolean + // Add examples and default descriptions for string fields with defaults + if (schema && typeof schema === "object" && "type" in schema && schema.type === "string" && schema?.default) { + if (!schema.examples) { + schema.examples = [schema.default] + } + + schema.description = [schema.description || "", `default: \`${schema.default}\``] + .filter(Boolean) + .join("\n\n") + .trim() + } + }, + }) as Record & { + allowComments?: boolean + allowTrailingCommas?: boolean + } + + // used for json lsps since config supports jsonc + result.allowComments = true + result.allowTrailingCommas = true + + return result } -// used for json lsps since config supports jsonc -result.allowComments = true -result.allowTrailingCommas = true +const configFile = process.argv[2] +const tuiFile = process.argv[3] -await Bun.write(file, JSON.stringify(result, null, 2)) +console.log(configFile) +await Bun.write(configFile, JSON.stringify(generate(Config.Info), null, 2)) + +if (tuiFile) { + console.log(tuiFile) + await Bun.write(tuiFile, JSON.stringify(generate(TuiConfig.Info), null, 2)) +} diff --git a/packages/opencode/src/acp/agent.ts b/packages/opencode/src/acp/agent.ts index 765c741c0d..2552682dbe 100644 --- a/packages/opencode/src/acp/agent.ts +++ b/packages/opencode/src/acp/agent.ts @@ -29,8 +29,9 @@ import { } from "@agentclientprotocol/sdk" import { Log } from "../util/log" -import { pathToFileURL } from "bun" +import { pathToFileURL } from "url" import { Filesystem } from "../util/filesystem" +import { Hash } from "../util/hash" import { ACPSessionManager } from "./session" import type { ACPConfig } from "./types" import { Provider } from "../provider/provider" @@ -41,7 +42,7 @@ import { Config } from "@/config/config" import { Todo } from "@/session/todo" import { z } from "zod" import { LoadAPIKeyError } from "ai" -import type { AssistantMessage, Event, OpencodeClient, SessionMessageResponse } from "@opencode-ai/sdk/v2" +import type { AssistantMessage, Event, OpencodeClient, SessionMessageResponse, ToolPart } from "@opencode-ai/sdk/v2" import { applyPatch } from "diff" type ModeOption = { id: string; name: string; description?: string } @@ -135,6 +136,8 @@ export namespace ACP { private sessionManager: ACPSessionManager private eventAbort = new AbortController() private eventStarted = false + private bashSnapshots = new Map() + private toolStarts = new Set() private permissionQueues = new Map>() private permissionOptions: PermissionOption[] = [ { optionId: "once", kind: "allow_once", name: "Allow once" }, @@ -266,47 +269,50 @@ export namespace ACP { const session = this.sessionManager.tryGet(part.sessionID) if (!session) return const sessionId = session.id - const directory = session.cwd - - const message = await this.sdk.session - .message( - { - sessionID: part.sessionID, - messageID: part.messageID, - directory, - }, - { throwOnError: true }, - ) - .then((x) => x.data) - .catch((error) => { - log.error("unexpected error when fetching message", { error }) - return undefined - }) - - if (!message || message.info.role !== "assistant") return if (part.type === "tool") { + await this.toolStart(sessionId, part) + switch (part.state.status) { case "pending": - await this.connection - .sessionUpdate({ - sessionId, - update: { - sessionUpdate: "tool_call", - toolCallId: part.callID, - title: part.tool, - kind: toToolKind(part.tool), - status: "pending", - locations: [], - rawInput: {}, - }, - }) - .catch((error) => { - log.error("failed to send tool pending to ACP", { error }) - }) + this.bashSnapshots.delete(part.callID) return case "running": + const output = this.bashOutput(part) + const content: ToolCallContent[] = [] + if (output) { + const hash = Hash.fast(output) + if (part.tool === "bash") { + if (this.bashSnapshots.get(part.callID) === hash) { + await this.connection + .sessionUpdate({ + sessionId, + update: { + sessionUpdate: "tool_call_update", + toolCallId: part.callID, + status: "in_progress", + kind: toToolKind(part.tool), + title: part.tool, + locations: toLocations(part.tool, part.state.input), + rawInput: part.state.input, + }, + }) + .catch((error) => { + log.error("failed to send tool in_progress to ACP", { error }) + }) + return + } + this.bashSnapshots.set(part.callID, hash) + } + content.push({ + type: "content", + content: { + type: "text", + text: output, + }, + }) + } await this.connection .sessionUpdate({ sessionId, @@ -318,6 +324,7 @@ export namespace ACP { title: part.tool, locations: toLocations(part.tool, part.state.input), rawInput: part.state.input, + ...(content.length > 0 && { content }), }, }) .catch((error) => { @@ -326,6 +333,8 @@ export namespace ACP { return case "completed": { + this.toolStarts.delete(part.callID) + this.bashSnapshots.delete(part.callID) const kind = toToolKind(part.tool) const content: ToolCallContent[] = [ { @@ -405,6 +414,8 @@ export namespace ACP { return } case "error": + this.toolStarts.delete(part.callID) + this.bashSnapshots.delete(part.callID) await this.connection .sessionUpdate({ sessionId, @@ -426,6 +437,7 @@ export namespace ACP { ], rawOutput: { error: part.state.error, + metadata: part.state.metadata, }, }, }) @@ -800,26 +812,23 @@ export namespace ACP { for (const part of message.parts) { if (part.type === "tool") { + await this.toolStart(sessionId, part) switch (part.state.status) { case "pending": - await this.connection - .sessionUpdate({ - sessionId, - update: { - sessionUpdate: "tool_call", - toolCallId: part.callID, - title: part.tool, - kind: toToolKind(part.tool), - status: "pending", - locations: [], - rawInput: {}, - }, - }) - .catch((err) => { - log.error("failed to send tool pending to ACP", { error: err }) - }) + this.bashSnapshots.delete(part.callID) break case "running": + const output = this.bashOutput(part) + const runningContent: ToolCallContent[] = [] + if (output) { + runningContent.push({ + type: "content", + content: { + type: "text", + text: output, + }, + }) + } await this.connection .sessionUpdate({ sessionId, @@ -831,6 +840,7 @@ export namespace ACP { title: part.tool, locations: toLocations(part.tool, part.state.input), rawInput: part.state.input, + ...(runningContent.length > 0 && { content: runningContent }), }, }) .catch((err) => { @@ -838,6 +848,8 @@ export namespace ACP { }) break case "completed": + this.toolStarts.delete(part.callID) + this.bashSnapshots.delete(part.callID) const kind = toToolKind(part.tool) const content: ToolCallContent[] = [ { @@ -916,6 +928,8 @@ export namespace ACP { }) break case "error": + this.toolStarts.delete(part.callID) + this.bashSnapshots.delete(part.callID) await this.connection .sessionUpdate({ sessionId, @@ -937,6 +951,7 @@ export namespace ACP { ], rawOutput: { error: part.state.error, + metadata: part.state.metadata, }, }, }) @@ -1063,6 +1078,35 @@ export namespace ACP { } } + private bashOutput(part: ToolPart) { + if (part.tool !== "bash") return + if (!("metadata" in part.state) || !part.state.metadata || typeof part.state.metadata !== "object") return + const output = part.state.metadata["output"] + if (typeof output !== "string") return + return output + } + + private async toolStart(sessionId: string, part: ToolPart) { + if (this.toolStarts.has(part.callID)) return + this.toolStarts.add(part.callID) + await this.connection + .sessionUpdate({ + sessionId, + update: { + sessionUpdate: "tool_call", + toolCallId: part.callID, + title: part.tool, + kind: toToolKind(part.tool), + status: "pending", + locations: [], + rawInput: {}, + }, + }) + .catch((error) => { + log.error("failed to send tool pending to ACP", { error }) + }) + } + private async loadAvailableModes(directory: string): Promise { const agents = await this.config.sdk.app .agents( diff --git a/packages/opencode/src/auth/index.ts b/packages/opencode/src/auth/index.ts index 776cc99b44..80253a665e 100644 --- a/packages/opencode/src/auth/index.ts +++ b/packages/opencode/src/auth/index.ts @@ -56,13 +56,18 @@ export namespace Auth { } export async function set(key: string, info: Info) { + const normalized = key.replace(/\/+$/, "") const data = await all() - await Filesystem.writeJson(filepath, { ...data, [key]: info }, 0o600) + if (normalized !== key) delete data[key] + delete data[normalized + "/"] + await Filesystem.writeJson(filepath, { ...data, [normalized]: info }, 0o600) } export async function remove(key: string) { + const normalized = key.replace(/\/+$/, "") const data = await all() delete data[key] + delete data[normalized] await Filesystem.writeJson(filepath, data, 0o600) } } diff --git a/packages/opencode/src/bun/index.ts b/packages/opencode/src/bun/index.ts index 79aaae2bcc..e3bddcc226 100644 --- a/packages/opencode/src/bun/index.ts +++ b/packages/opencode/src/bun/index.ts @@ -4,20 +4,21 @@ import { Log } from "../util/log" import path from "path" import { Filesystem } from "../util/filesystem" import { NamedError } from "@opencode-ai/util/error" -import { readableStreamToText } from "bun" +import { text } from "node:stream/consumers" import { Lock } from "../util/lock" import { PackageRegistry } from "./registry" import { proxied } from "@/util/proxied" +import { Process } from "../util/process" export namespace BunProc { const log = Log.create({ service: "bun" }) - export async function run(cmd: string[], options?: Bun.SpawnOptions.OptionsObject) { + export async function run(cmd: string[], options?: Process.Options) { log.info("running", { cmd: [which(), ...cmd], ...options, }) - const result = Bun.spawn([which(), ...cmd], { + const result = Process.spawn([which(), ...cmd], { ...options, stdout: "pipe", stderr: "pipe", @@ -28,23 +29,15 @@ export namespace BunProc { }, }) const code = await result.exited - const stdout = result.stdout - ? typeof result.stdout === "number" - ? result.stdout - : await readableStreamToText(result.stdout) - : undefined - const stderr = result.stderr - ? typeof result.stderr === "number" - ? result.stderr - : await readableStreamToText(result.stderr) - : undefined + const stdout = result.stdout ? await text(result.stdout) : undefined + const stderr = result.stderr ? await text(result.stderr) : undefined log.info("done", { code, stdout, stderr, }) if (code !== 0) { - throw new Error(`Command failed with exit code ${result.exitCode}`) + throw new Error(`Command failed with exit code ${code}`) } return result } @@ -93,7 +86,7 @@ export namespace BunProc { "--force", "--exact", // TODO: get rid of this case (see: https://github.com/oven-sh/bun/issues/19936) - ...(proxied() ? ["--no-cache"] : []), + ...(proxied() || process.env.CI ? ["--no-cache"] : []), "--cwd", Global.Path.cache, pkg + "@" + version, diff --git a/packages/opencode/src/bun/registry.ts b/packages/opencode/src/bun/registry.ts index c567668acd..1fc8531442 100644 --- a/packages/opencode/src/bun/registry.ts +++ b/packages/opencode/src/bun/registry.ts @@ -1,5 +1,7 @@ -import { readableStreamToText, semver } from "bun" +import semver from "semver" +import { text } from "node:stream/consumers" import { Log } from "../util/log" +import { Process } from "../util/process" export namespace PackageRegistry { const log = Log.create({ service: "bun" }) @@ -9,7 +11,7 @@ export namespace PackageRegistry { } export async function info(pkg: string, field: string, cwd?: string): Promise { - const result = Bun.spawn([which(), "info", pkg, field], { + const result = Process.spawn([which(), "info", pkg, field], { cwd, stdout: "pipe", stderr: "pipe", @@ -20,8 +22,8 @@ export namespace PackageRegistry { }) const code = await result.exited - const stdout = result.stdout ? await readableStreamToText(result.stdout) : "" - const stderr = result.stderr ? await readableStreamToText(result.stderr) : "" + const stdout = result.stdout ? await text(result.stdout) : "" + const stderr = result.stderr ? await text(result.stderr) : "" if (code !== 0) { log.warn("bun info failed", { pkg, field, code, stderr }) @@ -43,6 +45,6 @@ export namespace PackageRegistry { const isRange = /[\s^~*xX<>|=]/.test(cachedVersion) if (isRange) return !semver.satisfies(latestVersion, cachedVersion) - return semver.order(cachedVersion, latestVersion) === -1 + return semver.lt(cachedVersion, latestVersion) } } diff --git a/packages/opencode/src/cli/cmd/auth.ts b/packages/opencode/src/cli/cmd/auth.ts index e050a0abf8..38fba0ce70 100644 --- a/packages/opencode/src/cli/cmd/auth.ts +++ b/packages/opencode/src/cli/cmd/auth.ts @@ -11,6 +11,9 @@ import { Global } from "../../global" import { Plugin } from "../../plugin" import { Instance } from "../../project/instance" import type { Hooks } from "@opencode-ai/plugin" +import { Process } from "../../util/process" +import { text } from "node:stream/consumers" +import { setTimeout as sleep } from "node:timers/promises" type PluginAuth = NonNullable @@ -18,10 +21,19 @@ type PluginAuth = NonNullable * Handle plugin-based authentication flow. * Returns true if auth was handled, false if it should fall through to default handling. */ -async function handlePluginAuth(plugin: { auth: PluginAuth }, provider: string): Promise { +async function handlePluginAuth(plugin: { auth: PluginAuth }, provider: string, methodName?: string): Promise { let index = 0 - if (plugin.auth.methods.length > 1) { - const method = await prompts.select({ + if (methodName) { + const match = plugin.auth.methods.findIndex((x) => x.label.toLowerCase() === methodName.toLowerCase()) + if (match === -1) { + prompts.log.error( + `Unknown method "${methodName}" for ${provider}. Available: ${plugin.auth.methods.map((x) => x.label).join(", ")}`, + ) + process.exit(1) + } + index = match + } else if (plugin.auth.methods.length > 1) { + const selected = await prompts.select({ message: "Login method", options: [ ...plugin.auth.methods.map((x, index) => ({ @@ -30,13 +42,13 @@ async function handlePluginAuth(plugin: { auth: PluginAuth }, provider: string): })), ], }) - if (prompts.isCancel(method)) throw new UI.CancelledError() - index = parseInt(method) + if (prompts.isCancel(selected)) throw new UI.CancelledError() + index = parseInt(selected) } const method = plugin.auth.methods[index] // Handle prompts for all auth types - await Bun.sleep(10) + await sleep(10) const inputs: Record = {} if (method.prompts) { for (const prompt of method.prompts) { @@ -250,10 +262,21 @@ export const AuthLoginCommand = cmd({ command: "login [url]", describe: "log in to a provider", builder: (yargs) => - yargs.positional("url", { - describe: "opencode auth provider", - type: "string", - }), + yargs + .positional("url", { + describe: "opencode auth provider", + type: "string", + }) + .option("provider", { + alias: ["p"], + describe: "provider id or name to log in to (skips provider selection)", + type: "string", + }) + .option("method", { + alias: ["m"], + describe: "login method label (skips method selection)", + type: "string", + }), async handler(args) { await Instance.provide({ directory: process.cwd(), @@ -261,25 +284,29 @@ export const AuthLoginCommand = cmd({ UI.empty() prompts.intro("Add credential") if (args.url) { - const wellknown = await fetch(`${args.url}/.well-known/opencode`).then((x) => x.json() as any) + const url = args.url.replace(/\/+$/, "") + const wellknown = await fetch(`${url}/.well-known/opencode`).then((x) => x.json() as any) prompts.log.info(`Running \`${wellknown.auth.command.join(" ")}\``) - const proc = Bun.spawn({ - cmd: wellknown.auth.command, + const proc = Process.spawn(wellknown.auth.command, { stdout: "pipe", }) - const exit = await proc.exited + if (!proc.stdout) { + prompts.log.error("Failed") + prompts.outro("Done") + return + } + const [exit, token] = await Promise.all([proc.exited, text(proc.stdout)]) if (exit !== 0) { prompts.log.error("Failed") prompts.outro("Done") return } - const token = await new Response(proc.stdout).text() - await Auth.set(args.url, { + await Auth.set(url, { type: "wellknown", key: wellknown.auth.env, token: token.trim(), }) - prompts.log.success("Logged into " + args.url) + prompts.log.success("Logged into " + url) prompts.outro("Done") return } @@ -316,60 +343,76 @@ export const AuthLoginCommand = cmd({ enabled, providerNames: Object.fromEntries(Object.entries(config.provider ?? {}).map(([id, p]) => [id, p.name])), }) - let provider = await prompts.autocomplete({ - message: "Select provider", - maxItems: 8, - options: [ - ...pipe( - providers, - values(), - sortBy( - (x) => priority[x.id] ?? 99, - (x) => x.name ?? x.id, - ), - map((x) => ({ - label: x.name, - value: x.id, - hint: { - opencode: "recommended", - anthropic: "Claude Max or API key", - openai: "ChatGPT Plus/Pro or API key", - }[x.id], - })), + const options = [ + ...pipe( + providers, + values(), + sortBy( + (x) => priority[x.id] ?? 99, + (x) => x.name ?? x.id, ), - ...pluginProviders.map((x) => ({ + map((x) => ({ label: x.name, value: x.id, - hint: "plugin", + hint: { + opencode: "recommended", + anthropic: "Claude Max or API key", + openai: "ChatGPT Plus/Pro or API key", + }[x.id], })), - { - value: "other", - label: "Other", - }, - ], - }) + ), + ...pluginProviders.map((x) => ({ + label: x.name, + value: x.id, + hint: "plugin", + })), + ] - if (prompts.isCancel(provider)) throw new UI.CancelledError() + let provider: string + if (args.provider) { + const input = args.provider + const byID = options.find((x) => x.value === input) + const byName = options.find((x) => x.label.toLowerCase() === input.toLowerCase()) + const match = byID ?? byName + if (!match) { + prompts.log.error(`Unknown provider "${input}"`) + process.exit(1) + } + provider = match.value + } else { + const selected = await prompts.autocomplete({ + message: "Select provider", + maxItems: 8, + options: [ + ...options, + { + value: "other", + label: "Other", + }, + ], + }) + if (prompts.isCancel(selected)) throw new UI.CancelledError() + provider = selected as string + } const plugin = await Plugin.list().then((x) => x.findLast((x) => x.auth?.provider === provider)) if (plugin && plugin.auth) { - const handled = await handlePluginAuth({ auth: plugin.auth }, provider) + const handled = await handlePluginAuth({ auth: plugin.auth }, provider, args.method) if (handled) return } if (provider === "other") { - provider = await prompts.text({ + const custom = await prompts.text({ message: "Enter provider id", validate: (x) => (x && x.match(/^[0-9a-z-]+$/) ? undefined : "a-z, 0-9 and hyphens only"), }) - if (prompts.isCancel(provider)) throw new UI.CancelledError() - provider = provider.replace(/^@ai-sdk\//, "") - if (prompts.isCancel(provider)) throw new UI.CancelledError() + if (prompts.isCancel(custom)) throw new UI.CancelledError() + provider = custom.replace(/^@ai-sdk\//, "") // Check if a plugin provides auth for this custom provider const customPlugin = await Plugin.list().then((x) => x.findLast((x) => x.auth?.provider === provider)) if (customPlugin && customPlugin.auth) { - const handled = await handlePluginAuth({ auth: customPlugin.auth }, provider) + const handled = await handlePluginAuth({ auth: customPlugin.auth }, provider, args.method) if (handled) return } diff --git a/packages/opencode/src/cli/cmd/debug/lsp.ts b/packages/opencode/src/cli/cmd/debug/lsp.ts index d83c4ed8a4..4b8a3e7d45 100644 --- a/packages/opencode/src/cli/cmd/debug/lsp.ts +++ b/packages/opencode/src/cli/cmd/debug/lsp.ts @@ -3,6 +3,7 @@ import { bootstrap } from "../../bootstrap" import { cmd } from "../cmd" import { Log } from "../../../util/log" import { EOL } from "os" +import { setTimeout as sleep } from "node:timers/promises" export const LSPCommand = cmd({ command: "lsp", @@ -19,7 +20,7 @@ const DiagnosticsCommand = cmd({ async handler(args) { await bootstrap(process.cwd(), async () => { await LSP.touchFile(args.file, true) - await Bun.sleep(1000) + await sleep(1000) process.stdout.write(JSON.stringify(await LSP.diagnostics(), null, 2) + EOL) }) }, diff --git a/packages/opencode/src/cli/cmd/github.ts b/packages/opencode/src/cli/cmd/github.ts index 672e73d49a..a58151308c 100644 --- a/packages/opencode/src/cli/cmd/github.ts +++ b/packages/opencode/src/cli/cmd/github.ts @@ -27,7 +27,9 @@ import { Provider } from "../../provider/provider" import { Bus } from "../../bus" import { MessageV2 } from "../../session/message-v2" import { SessionPrompt } from "@/session/prompt" -import { $ } from "bun" +import { setTimeout as sleep } from "node:timers/promises" +import { Process } from "@/util/process" +import { git } from "@/util/git" type GitHubAuthor = { login: string @@ -254,7 +256,7 @@ export const GithubInstallCommand = cmd({ } // Get repo info - const info = (await $`git remote get-url origin`.quiet().nothrow().text()).trim() + const info = (await git(["remote", "get-url", "origin"], { cwd: Instance.worktree })).text().trim() const parsed = parseGitHubRemote(info) if (!parsed) { prompts.log.error(`Could not find git repository. Please run this command from a git repository.`) @@ -353,7 +355,7 @@ export const GithubInstallCommand = cmd({ } retries++ - await Bun.sleep(1000) + await sleep(1000) } while (true) s.stop("Installed GitHub app") @@ -492,6 +494,26 @@ export const GithubRunCommand = cmd({ ? "pr_review" : "issue" : undefined + const gitText = async (args: string[]) => { + const result = await git(args, { cwd: Instance.worktree }) + if (result.exitCode !== 0) { + throw new Process.RunFailedError(["git", ...args], result.exitCode, result.stdout, result.stderr) + } + return result.text().trim() + } + const gitRun = async (args: string[]) => { + const result = await git(args, { cwd: Instance.worktree }) + if (result.exitCode !== 0) { + throw new Process.RunFailedError(["git", ...args], result.exitCode, result.stdout, result.stderr) + } + return result + } + const gitStatus = (args: string[]) => git(args, { cwd: Instance.worktree }) + const commitChanges = async (summary: string, actor?: string) => { + const args = ["commit", "-m", summary] + if (actor) args.push("-m", `Co-authored-by: ${actor} <${actor}@users.noreply.github.com>`) + await gitRun(args) + } try { if (useGithubToken) { @@ -552,7 +574,7 @@ export const GithubRunCommand = cmd({ } const branchPrefix = isWorkflowDispatchEvent ? "dispatch" : "schedule" const branch = await checkoutNewBranch(branchPrefix) - const head = (await $`git rev-parse HEAD`).stdout.toString().trim() + const head = await gitText(["rev-parse", "HEAD"]) const response = await chat(userPrompt, promptFiles) const { dirty, uncommittedChanges, switched } = await branchIsDirty(head, branch) if (switched) { @@ -586,7 +608,7 @@ export const GithubRunCommand = cmd({ // Local PR if (prData.headRepository.nameWithOwner === prData.baseRepository.nameWithOwner) { await checkoutLocalBranch(prData) - const head = (await $`git rev-parse HEAD`).stdout.toString().trim() + const head = await gitText(["rev-parse", "HEAD"]) const dataPrompt = buildPromptDataForPR(prData) const response = await chat(`${userPrompt}\n\n${dataPrompt}`, promptFiles) const { dirty, uncommittedChanges, switched } = await branchIsDirty(head, prData.headRefName) @@ -604,7 +626,7 @@ export const GithubRunCommand = cmd({ // Fork PR else { const forkBranch = await checkoutForkBranch(prData) - const head = (await $`git rev-parse HEAD`).stdout.toString().trim() + const head = await gitText(["rev-parse", "HEAD"]) const dataPrompt = buildPromptDataForPR(prData) const response = await chat(`${userPrompt}\n\n${dataPrompt}`, promptFiles) const { dirty, uncommittedChanges, switched } = await branchIsDirty(head, forkBranch) @@ -623,7 +645,7 @@ export const GithubRunCommand = cmd({ // Issue else { const branch = await checkoutNewBranch("issue") - const head = (await $`git rev-parse HEAD`).stdout.toString().trim() + const head = await gitText(["rev-parse", "HEAD"]) const issueData = await fetchIssue() const dataPrompt = buildPromptDataForIssue(issueData) const response = await chat(`${userPrompt}\n\n${dataPrompt}`, promptFiles) @@ -657,7 +679,7 @@ export const GithubRunCommand = cmd({ exitCode = 1 console.error(e instanceof Error ? e.message : String(e)) let msg = e - if (e instanceof $.ShellError) { + if (e instanceof Process.RunFailedError) { msg = e.stderr.toString() } else if (e instanceof Error) { msg = e.message @@ -1048,29 +1070,29 @@ export const GithubRunCommand = cmd({ const config = "http.https://github.com/.extraheader" // actions/checkout@v6 no longer stores credentials in .git/config, // so this may not exist - use nothrow() to handle gracefully - const ret = await $`git config --local --get ${config}`.nothrow() + const ret = await gitStatus(["config", "--local", "--get", config]) if (ret.exitCode === 0) { gitConfig = ret.stdout.toString().trim() - await $`git config --local --unset-all ${config}` + await gitRun(["config", "--local", "--unset-all", config]) } const newCredentials = Buffer.from(`x-access-token:${appToken}`, "utf8").toString("base64") - await $`git config --local ${config} "AUTHORIZATION: basic ${newCredentials}"` - await $`git config --global user.name "${AGENT_USERNAME}"` - await $`git config --global user.email "${AGENT_USERNAME}@users.noreply.github.com"` + await gitRun(["config", "--local", config, `AUTHORIZATION: basic ${newCredentials}`]) + await gitRun(["config", "--global", "user.name", AGENT_USERNAME]) + await gitRun(["config", "--global", "user.email", `${AGENT_USERNAME}@users.noreply.github.com`]) } async function restoreGitConfig() { if (gitConfig === undefined) return const config = "http.https://github.com/.extraheader" - await $`git config --local ${config} "${gitConfig}"` + await gitRun(["config", "--local", config, gitConfig]) } async function checkoutNewBranch(type: "issue" | "schedule" | "dispatch") { console.log("Checking out new branch...") const branch = generateBranchName(type) - await $`git checkout -b ${branch}` + await gitRun(["checkout", "-b", branch]) return branch } @@ -1080,8 +1102,8 @@ export const GithubRunCommand = cmd({ const branch = pr.headRefName const depth = Math.max(pr.commits.totalCount, 20) - await $`git fetch origin --depth=${depth} ${branch}` - await $`git checkout ${branch}` + await gitRun(["fetch", "origin", `--depth=${depth}`, branch]) + await gitRun(["checkout", branch]) } async function checkoutForkBranch(pr: GitHubPullRequest) { @@ -1091,9 +1113,9 @@ export const GithubRunCommand = cmd({ const localBranch = generateBranchName("pr") const depth = Math.max(pr.commits.totalCount, 20) - await $`git remote add fork https://github.com/${pr.headRepository.nameWithOwner}.git` - await $`git fetch fork --depth=${depth} ${remoteBranch}` - await $`git checkout -b ${localBranch} fork/${remoteBranch}` + await gitRun(["remote", "add", "fork", `https://github.com/${pr.headRepository.nameWithOwner}.git`]) + await gitRun(["fetch", "fork", `--depth=${depth}`, remoteBranch]) + await gitRun(["checkout", "-b", localBranch, `fork/${remoteBranch}`]) return localBranch } @@ -1114,28 +1136,23 @@ export const GithubRunCommand = cmd({ async function pushToNewBranch(summary: string, branch: string, commit: boolean, isSchedule: boolean) { console.log("Pushing to new branch...") if (commit) { - await $`git add .` + await gitRun(["add", "."]) if (isSchedule) { - // No co-author for scheduled events - the schedule is operating as the repo - await $`git commit -m "${summary}"` + await commitChanges(summary) } else { - await $`git commit -m "${summary} - -Co-authored-by: ${actor} <${actor}@users.noreply.github.com>"` + await commitChanges(summary, actor) } } - await $`git push -u origin ${branch}` + await gitRun(["push", "-u", "origin", branch]) } async function pushToLocalBranch(summary: string, commit: boolean) { console.log("Pushing to local branch...") if (commit) { - await $`git add .` - await $`git commit -m "${summary} - -Co-authored-by: ${actor} <${actor}@users.noreply.github.com>"` + await gitRun(["add", "."]) + await commitChanges(summary, actor) } - await $`git push` + await gitRun(["push"]) } async function pushToForkBranch(summary: string, pr: GitHubPullRequest, commit: boolean) { @@ -1144,30 +1161,28 @@ Co-authored-by: ${actor} <${actor}@users.noreply.github.com>"` const remoteBranch = pr.headRefName if (commit) { - await $`git add .` - await $`git commit -m "${summary} - -Co-authored-by: ${actor} <${actor}@users.noreply.github.com>"` + await gitRun(["add", "."]) + await commitChanges(summary, actor) } - await $`git push fork HEAD:${remoteBranch}` + await gitRun(["push", "fork", `HEAD:${remoteBranch}`]) } async function branchIsDirty(originalHead: string, expectedBranch: string) { console.log("Checking if branch is dirty...") // Detect if the agent switched branches during chat (e.g. created // its own branch, committed, and possibly pushed/created a PR). - const current = (await $`git rev-parse --abbrev-ref HEAD`).stdout.toString().trim() + const current = await gitText(["rev-parse", "--abbrev-ref", "HEAD"]) if (current !== expectedBranch) { console.log(`Branch changed during chat: expected ${expectedBranch}, now on ${current}`) return { dirty: true, uncommittedChanges: false, switched: true } } - const ret = await $`git status --porcelain` + const ret = await gitStatus(["status", "--porcelain"]) const status = ret.stdout.toString().trim() if (status.length > 0) { return { dirty: true, uncommittedChanges: true, switched: false } } - const head = (await $`git rev-parse HEAD`).stdout.toString().trim() + const head = await gitText(["rev-parse", "HEAD"]) return { dirty: head !== originalHead, uncommittedChanges: false, @@ -1179,11 +1194,11 @@ Co-authored-by: ${actor} <${actor}@users.noreply.github.com>"` // Falls back to fetching from origin when local refs are missing // (common in shallow clones from actions/checkout). async function hasNewCommits(base: string, head: string) { - const result = await $`git rev-list --count ${base}..${head}`.nothrow() + const result = await gitStatus(["rev-list", "--count", `${base}..${head}`]) if (result.exitCode !== 0) { console.log(`rev-list failed, fetching origin/${base}...`) - await $`git fetch origin ${base} --depth=1`.nothrow() - const retry = await $`git rev-list --count origin/${base}..${head}`.nothrow() + await gitStatus(["fetch", "origin", base, "--depth=1"]) + const retry = await gitStatus(["rev-list", "--count", `origin/${base}..${head}`]) if (retry.exitCode !== 0) return true // assume dirty if we can't tell return parseInt(retry.stdout.toString().trim()) > 0 } @@ -1372,7 +1387,7 @@ Co-authored-by: ${actor} <${actor}@users.noreply.github.com>"` } catch (e) { if (retries > 0) { console.log(`Retrying after ${delayMs}ms...`) - await Bun.sleep(delayMs) + await sleep(delayMs) return withRetry(fn, retries - 1, delayMs) } throw e diff --git a/packages/opencode/src/cli/cmd/import.ts b/packages/opencode/src/cli/cmd/import.ts index 4d65060f18..58c1928256 100644 --- a/packages/opencode/src/cli/cmd/import.ts +++ b/packages/opencode/src/cli/cmd/import.ts @@ -131,7 +131,14 @@ export const ImportCommand = cmd({ return } - Database.use((db) => db.insert(SessionTable).values(Session.toRow(exportData.info)).onConflictDoNothing().run()) + const row = { ...Session.toRow(exportData.info), project_id: Instance.project.id } + Database.use((db) => + db + .insert(SessionTable) + .values(row) + .onConflictDoUpdate({ target: SessionTable.id, set: { project_id: row.project_id } }) + .run(), + ) for (const msg of exportData.messages) { Database.use((db) => diff --git a/packages/opencode/src/cli/cmd/pr.ts b/packages/opencode/src/cli/cmd/pr.ts index d617657200..ea61354741 100644 --- a/packages/opencode/src/cli/cmd/pr.ts +++ b/packages/opencode/src/cli/cmd/pr.ts @@ -1,7 +1,8 @@ import { UI } from "../ui" import { cmd } from "./cmd" import { Instance } from "@/project/instance" -import { $ } from "bun" +import { Process } from "@/util/process" +import { git } from "@/util/git" export const PrCommand = cmd({ command: "pr ", @@ -27,21 +28,35 @@ export const PrCommand = cmd({ UI.println(`Fetching and checking out PR #${prNumber}...`) // Use gh pr checkout with custom branch name - const result = await $`gh pr checkout ${prNumber} --branch ${localBranchName} --force`.nothrow() + const result = await Process.run( + ["gh", "pr", "checkout", `${prNumber}`, "--branch", localBranchName, "--force"], + { + nothrow: true, + }, + ) - if (result.exitCode !== 0) { + if (result.code !== 0) { UI.error(`Failed to checkout PR #${prNumber}. Make sure you have gh CLI installed and authenticated.`) process.exit(1) } // Fetch PR info for fork handling and session link detection - const prInfoResult = - await $`gh pr view ${prNumber} --json headRepository,headRepositoryOwner,isCrossRepository,headRefName,body`.nothrow() + const prInfoResult = await Process.text( + [ + "gh", + "pr", + "view", + `${prNumber}`, + "--json", + "headRepository,headRepositoryOwner,isCrossRepository,headRefName,body", + ], + { nothrow: true }, + ) let sessionId: string | undefined - if (prInfoResult.exitCode === 0) { - const prInfoText = prInfoResult.text() + if (prInfoResult.code === 0) { + const prInfoText = prInfoResult.text if (prInfoText.trim()) { const prInfo = JSON.parse(prInfoText) @@ -52,15 +67,19 @@ export const PrCommand = cmd({ const remoteName = forkOwner // Check if remote already exists - const remotes = (await $`git remote`.nothrow().text()).trim() + const remotes = (await git(["remote"], { cwd: Instance.worktree })).text().trim() if (!remotes.split("\n").includes(remoteName)) { - await $`git remote add ${remoteName} https://github.com/${forkOwner}/${forkName}.git`.nothrow() + await git(["remote", "add", remoteName, `https://github.com/${forkOwner}/${forkName}.git`], { + cwd: Instance.worktree, + }) UI.println(`Added fork remote: ${remoteName}`) } // Set upstream to the fork so pushes go there const headRefName = prInfo.headRefName - await $`git branch --set-upstream-to=${remoteName}/${headRefName} ${localBranchName}`.nothrow() + await git(["branch", `--set-upstream-to=${remoteName}/${headRefName}`, localBranchName], { + cwd: Instance.worktree, + }) } // Check for opencode session link in PR body @@ -71,9 +90,11 @@ export const PrCommand = cmd({ UI.println(`Found opencode session: ${sessionUrl}`) UI.println(`Importing session...`) - const importResult = await $`opencode import ${sessionUrl}`.nothrow() - if (importResult.exitCode === 0) { - const importOutput = importResult.text().trim() + const importResult = await Process.text(["opencode", "import", sessionUrl], { + nothrow: true, + }) + if (importResult.code === 0) { + const importOutput = importResult.text.trim() // Extract session ID from the output (format: "Imported session: ") const sessionIdMatch = importOutput.match(/Imported session: ([a-zA-Z0-9_-]+)/) if (sessionIdMatch) { diff --git a/packages/opencode/src/cli/cmd/run.ts b/packages/opencode/src/cli/cmd/run.ts index f3781f1abd..f92d3305bf 100644 --- a/packages/opencode/src/cli/cmd/run.ts +++ b/packages/opencode/src/cli/cmd/run.ts @@ -1,6 +1,6 @@ import type { Argv } from "yargs" import path from "path" -import { pathToFileURL } from "bun" +import { pathToFileURL } from "url" import { UI } from "../ui" import { cmd } from "./cmd" import { Flag } from "../../flag/flag" @@ -280,6 +280,11 @@ export const RunCommand = cmd({ type: "string", describe: "attach to a running opencode server (e.g., http://localhost:4096)", }) + .option("password", { + alias: ["p"], + type: "string", + describe: "basic auth password (defaults to OPENCODE_SERVER_PASSWORD)", + }) .option("dir", { type: "string", describe: "directory to run in, path on remote server if attaching", @@ -555,6 +560,45 @@ export const RunCommand = cmd({ // Validate agent if specified const agent = await (async () => { if (!args.agent) return undefined + + // When attaching, validate against the running server instead of local Instance state. + if (args.attach) { + const modes = await sdk.app + .agents(undefined, { throwOnError: true }) + .then((x) => x.data ?? []) + .catch(() => undefined) + + if (!modes) { + UI.println( + UI.Style.TEXT_WARNING_BOLD + "!", + UI.Style.TEXT_NORMAL, + `failed to list agents from ${args.attach}. Falling back to default agent`, + ) + return undefined + } + + const agent = modes.find((a) => a.name === args.agent) + if (!agent) { + UI.println( + UI.Style.TEXT_WARNING_BOLD + "!", + UI.Style.TEXT_NORMAL, + `agent "${args.agent}" not found. Falling back to default agent`, + ) + return undefined + } + + if (agent.mode === "subagent") { + UI.println( + UI.Style.TEXT_WARNING_BOLD + "!", + UI.Style.TEXT_NORMAL, + `agent "${args.agent}" is a subagent, not a primary agent. Falling back to default agent`, + ) + return undefined + } + + return args.agent + } + const entry = await Agent.get(args.agent) if (!entry) { UI.println( @@ -609,14 +653,21 @@ export const RunCommand = cmd({ } if (args.attach) { - const sdk = createOpencodeClient({ baseUrl: args.attach, directory }) + const headers = (() => { + const password = args.password ?? process.env.OPENCODE_SERVER_PASSWORD + if (!password) return undefined + const username = process.env.OPENCODE_SERVER_USERNAME ?? "opencode" + const auth = `Basic ${Buffer.from(`${username}:${password}`).toString("base64")}` + return { Authorization: auth } + })() + const sdk = createOpencodeClient({ baseUrl: args.attach, directory, headers }) return await execute(sdk) } await bootstrap(process.cwd(), async () => { const fetchFn = (async (input: RequestInfo | URL, init?: RequestInit) => { const request = new Request(input, init) - return Server.App().fetch(request) + return Server.Default().fetch(request) }) as typeof globalThis.fetch const sdk = createOpencodeClient({ baseUrl: "http://opencode.internal", fetch: fetchFn }) await execute(sdk) diff --git a/packages/opencode/src/cli/cmd/serve.ts b/packages/opencode/src/cli/cmd/serve.ts index bee2c8f711..ab51fe8c3e 100644 --- a/packages/opencode/src/cli/cmd/serve.ts +++ b/packages/opencode/src/cli/cmd/serve.ts @@ -2,6 +2,9 @@ import { Server } from "../../server/server" import { cmd } from "./cmd" import { withNetworkOptions, resolveNetworkOptions } from "../network" import { Flag } from "../../flag/flag" +import { Workspace } from "../../control-plane/workspace" +import { Project } from "../../project/project" +import { Installation } from "../../installation" export const ServeCommand = cmd({ command: "serve", @@ -14,6 +17,7 @@ export const ServeCommand = cmd({ const opts = await resolveNetworkOptions(args) const server = Server.listen(opts) console.log(`opencode server listening on http://${server.hostname}:${server.port}`) + await new Promise(() => {}) await server.stop() }, diff --git a/packages/opencode/src/cli/cmd/session.ts b/packages/opencode/src/cli/cmd/session.ts index 4aa702359d..84840392a6 100644 --- a/packages/opencode/src/cli/cmd/session.ts +++ b/packages/opencode/src/cli/cmd/session.ts @@ -6,8 +6,10 @@ import { UI } from "../ui" import { Locale } from "../../util/locale" import { Flag } from "../../flag/flag" import { Filesystem } from "../../util/filesystem" +import { Process } from "../../util/process" import { EOL } from "os" import path from "path" +import { which } from "../../util/which" function pagerCmd(): string[] { const lessOptions = ["-R", "-S"] @@ -16,7 +18,7 @@ function pagerCmd(): string[] { } // user could have less installed via other options - const lessOnPath = Bun.which("less") + const lessOnPath = which("less") if (lessOnPath) { if (Filesystem.stat(lessOnPath)?.size) return [lessOnPath, ...lessOptions] } @@ -26,7 +28,7 @@ function pagerCmd(): string[] { if (Filesystem.stat(less)?.size) return [less, ...lessOptions] } - const git = Bun.which("git") + const git = which("git") if (git) { const less = path.join(git, "..", "..", "usr", "bin", "less.exe") if (Filesystem.stat(less)?.size) return [less, ...lessOptions] @@ -102,13 +104,17 @@ export const SessionListCommand = cmd({ const shouldPaginate = process.stdout.isTTY && !args.maxCount && args.format === "table" if (shouldPaginate) { - const proc = Bun.spawn({ - cmd: pagerCmd(), + const proc = Process.spawn(pagerCmd(), { stdin: "pipe", stdout: "inherit", stderr: "inherit", }) + if (!proc.stdin) { + console.log(output) + return + } + proc.stdin.write(output) proc.stdin.end() await proc.exited diff --git a/packages/opencode/src/cli/cmd/tui/app.tsx b/packages/opencode/src/cli/cmd/tui/app.tsx index ab3d096892..d5aef34f6e 100644 --- a/packages/opencode/src/cli/cmd/tui/app.tsx +++ b/packages/opencode/src/cli/cmd/tui/app.tsx @@ -20,6 +20,7 @@ import { DialogHelp } from "./ui/dialog-help" import { CommandProvider, useCommandDialog } from "@tui/component/dialog-command" import { DialogAgent } from "@tui/component/dialog-agent" import { DialogSessionList } from "@tui/component/dialog-session-list" +import { DialogWorkspaceList } from "@tui/component/dialog-workspace-list" import { KeybindProvider } from "@tui/context/keybind" import { ThemeProvider, useTheme } from "@tui/context/theme" import { Home } from "@tui/routes/home" @@ -38,6 +39,8 @@ import { ArgsProvider, useArgs, type Args } from "./context/args" import open from "open" import { writeHeapSnapshot } from "v8" import { PromptRefProvider, usePromptRef } from "./context/prompt" +import { TuiConfigProvider } from "./context/tui-config" +import { TuiConfig } from "@/config/tui" async function getTerminalBackgroundColor(): Promise<"dark" | "light"> { // can't set raw mode if not a TTY @@ -104,11 +107,11 @@ import type { EventSource } from "./context/sdk" export function tui(input: { url: string args: Args + config: TuiConfig.Info directory?: string fetch?: typeof fetch headers?: RequestInit["headers"] events?: EventSource - onExit?: () => Promise }) { // promise to prevent immediate exit return new Promise(async (resolve) => { @@ -123,7 +126,6 @@ export function tui(input: { const onExit = async () => { unguard?.() - await input.onExit?.() resolve() } @@ -138,35 +140,37 @@ export function tui(input: { - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + @@ -368,6 +372,22 @@ function App() { dialog.replace(() => ) }, }, + ...(Flag.OPENCODE_EXPERIMENTAL_WORKSPACES + ? [ + { + title: "Manage workspaces", + value: "workspace.list", + category: "Workspace", + suggested: true, + slash: { + name: "workspaces", + }, + onSelect: () => { + dialog.replace(() => ) + }, + }, + ] + : []), { title: "New session", suggested: route.data.type === "session", diff --git a/packages/opencode/src/cli/cmd/tui/attach.ts b/packages/opencode/src/cli/cmd/tui/attach.ts index a2559cfce6..e892f9922d 100644 --- a/packages/opencode/src/cli/cmd/tui/attach.ts +++ b/packages/opencode/src/cli/cmd/tui/attach.ts @@ -2,6 +2,9 @@ import { cmd } from "../cmd" import { UI } from "@/cli/ui" import { tui } from "./app" import { win32DisableProcessedInput, win32InstallCtrlCGuard } from "./win32" +import { TuiConfig } from "@/config/tui" +import { Instance } from "@/project/instance" +import { existsSync } from "fs" export const AttachCommand = cmd({ command: "attach ", @@ -63,8 +66,13 @@ export const AttachCommand = cmd({ const auth = `Basic ${Buffer.from(`opencode:${password}`).toString("base64")}` return { Authorization: auth } })() + const config = await Instance.provide({ + directory: directory && existsSync(directory) ? directory : process.cwd(), + fn: () => TuiConfig.get(), + }) await tui({ url: args.url, + config, args: { continue: args.continue, sessionID: args.session, diff --git a/packages/opencode/src/cli/cmd/tui/component/dialog-command.tsx b/packages/opencode/src/cli/cmd/tui/component/dialog-command.tsx index 38dc402758..be031296e9 100644 --- a/packages/opencode/src/cli/cmd/tui/component/dialog-command.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/dialog-command.tsx @@ -10,8 +10,7 @@ import { type ParentProps, } from "solid-js" import { useKeyboard } from "@opentui/solid" -import { useKeybind } from "@tui/context/keybind" -import type { KeybindsConfig } from "@opencode-ai/sdk/v2" +import { type KeybindKey, useKeybind } from "@tui/context/keybind" type Context = ReturnType const ctx = createContext() @@ -22,7 +21,7 @@ export type Slash = { } export type CommandOption = DialogSelectOption & { - keybind?: keyof KeybindsConfig + keybind?: KeybindKey suggested?: boolean slash?: Slash hidden?: boolean diff --git a/packages/opencode/src/cli/cmd/tui/component/dialog-provider.tsx b/packages/opencode/src/cli/cmd/tui/component/dialog-provider.tsx index 9682bee4ea..7bf189f090 100644 --- a/packages/opencode/src/cli/cmd/tui/component/dialog-provider.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/dialog-provider.tsx @@ -16,10 +16,11 @@ import { useToast } from "../ui/toast" const PROVIDER_PRIORITY: Record = { opencode: 0, - anthropic: 1, - "github-copilot": 2, - openai: 3, - google: 4, + "opencode-go": 1, + openai: 2, + "github-copilot": 3, + anthropic: 4, + google: 5, } export function createDialogProviderOptions() { @@ -37,6 +38,7 @@ export function createDialogProviderOptions() { opencode: "(Recommended)", anthropic: "(Claude Max or API key)", openai: "(ChatGPT Plus/Pro or API key)", + "opencode-go": "Low cost subscription for everyone", }[provider.id], category: provider.id in PROVIDER_PRIORITY ? "Popular" : "Other", async onSelect() { @@ -214,16 +216,30 @@ function ApiMethod(props: ApiMethodProps) { title={props.title} placeholder="API key" description={ - props.providerID === "opencode" ? ( - - - OpenCode Zen gives you access to all the best coding models at the cheapest prices with a single API key. - - - Go to https://opencode.ai/zen to get a key - - - ) : undefined + { + opencode: ( + + + OpenCode Zen gives you access to all the best coding models at the cheapest prices with a single API + key. + + + Go to https://opencode.ai/zen to get a key + + + ), + "opencode-go": ( + + + OpenCode Go is a $10 per month subscription that provides reliable access to popular open coding models + with generous usage limits. + + + Go to https://opencode.ai/zen and enable OpenCode Go + + + ), + }[props.providerID] ?? undefined } onConfirm={async (value) => { if (!value) return diff --git a/packages/opencode/src/cli/cmd/tui/component/dialog-workspace-list.tsx b/packages/opencode/src/cli/cmd/tui/component/dialog-workspace-list.tsx new file mode 100644 index 0000000000..a25b20505c --- /dev/null +++ b/packages/opencode/src/cli/cmd/tui/component/dialog-workspace-list.tsx @@ -0,0 +1,326 @@ +import { useDialog } from "@tui/ui/dialog" +import { DialogSelect } from "@tui/ui/dialog-select" +import { useRoute } from "@tui/context/route" +import { useSync } from "@tui/context/sync" +import { createEffect, createMemo, createSignal, onMount } from "solid-js" +import type { Session } from "@opencode-ai/sdk/v2" +import { useSDK } from "../context/sdk" +import { useToast } from "../ui/toast" +import { useKeybind } from "../context/keybind" +import { DialogSessionList } from "./workspace/dialog-session-list" +import { createOpencodeClient } from "@opencode-ai/sdk/v2" + +async function openWorkspace(input: { + dialog: ReturnType + route: ReturnType + sdk: ReturnType + sync: ReturnType + toast: ReturnType + workspaceID: string + forceCreate?: boolean +}) { + const cacheSession = (session: Session) => { + input.sync.set( + "session", + [...input.sync.data.session.filter((item) => item.id !== session.id), session].toSorted((a, b) => + a.id.localeCompare(b.id), + ), + ) + } + + const client = createOpencodeClient({ + baseUrl: input.sdk.url, + fetch: input.sdk.fetch, + directory: input.sync.data.path.directory || input.sdk.directory, + experimental_workspaceID: input.workspaceID, + }) + const listed = input.forceCreate ? undefined : await client.session.list({ roots: true, limit: 1 }) + const session = listed?.data?.[0] + if (session?.id) { + cacheSession(session) + input.route.navigate({ + type: "session", + sessionID: session.id, + }) + input.dialog.clear() + return + } + let created: Session | undefined + while (!created) { + const result = await client.session.create({}).catch(() => undefined) + if (!result) { + input.toast.show({ + message: "Failed to open workspace", + variant: "error", + }) + return + } + if (result.response.status >= 500 && result.response.status < 600) { + await Bun.sleep(1000) + continue + } + if (!result.data) { + input.toast.show({ + message: "Failed to open workspace", + variant: "error", + }) + return + } + created = result.data + } + cacheSession(created) + input.route.navigate({ + type: "session", + sessionID: created.id, + }) + input.dialog.clear() +} + +function DialogWorkspaceCreate(props: { onSelect: (workspaceID: string) => Promise }) { + const dialog = useDialog() + const sync = useSync() + const sdk = useSDK() + const toast = useToast() + const [creating, setCreating] = createSignal() + + onMount(() => { + dialog.setSize("medium") + }) + + const options = createMemo(() => { + const type = creating() + if (type) { + return [ + { + title: `Creating ${type} workspace...`, + value: "creating" as const, + description: "This can take a while for remote environments", + }, + ] + } + return [ + { + title: "Worktree", + value: "worktree" as const, + description: "Create a local git worktree", + }, + ] + }) + + const createWorkspace = async (type: string) => { + if (creating()) return + setCreating(type) + + const result = await sdk.client.experimental.workspace.create({ type, branch: null }).catch((err) => { + console.log(err) + return undefined + }) + console.log(JSON.stringify(result, null, 2)) + const workspace = result?.data + if (!workspace) { + setCreating(undefined) + toast.show({ + message: "Failed to create workspace", + variant: "error", + }) + return + } + await sync.workspace.sync() + await props.onSelect(workspace.id) + setCreating(undefined) + } + + return ( + { + if (option.value === "creating") return + void createWorkspace(option.value) + }} + /> + ) +} + +export function DialogWorkspaceList() { + const dialog = useDialog() + const route = useRoute() + const sync = useSync() + const sdk = useSDK() + const toast = useToast() + const keybind = useKeybind() + const [toDelete, setToDelete] = createSignal() + const [counts, setCounts] = createSignal>({}) + + const open = (workspaceID: string, forceCreate?: boolean) => + openWorkspace({ + dialog, + route, + sdk, + sync, + toast, + workspaceID, + forceCreate, + }) + + async function selectWorkspace(workspaceID: string) { + if (workspaceID === "__local__") { + if (localCount() > 0) { + dialog.replace(() => ) + return + } + route.navigate({ + type: "home", + }) + dialog.clear() + return + } + const count = counts()[workspaceID] + if (count && count > 0) { + dialog.replace(() => ) + return + } + + if (count === 0) { + await open(workspaceID) + return + } + const client = createOpencodeClient({ + baseUrl: sdk.url, + fetch: sdk.fetch, + directory: sync.data.path.directory || sdk.directory, + experimental_workspaceID: workspaceID, + }) + const listed = await client.session.list({ roots: true, limit: 1 }).catch(() => undefined) + if (listed?.data?.length) { + dialog.replace(() => ) + return + } + await open(workspaceID) + } + + const currentWorkspaceID = createMemo(() => { + if (route.data.type === "session") { + return sync.session.get(route.data.sessionID)?.workspaceID ?? "__local__" + } + return "__local__" + }) + + const localCount = createMemo( + () => sync.data.session.filter((session) => !session.workspaceID && !session.parentID).length, + ) + + let run = 0 + createEffect(() => { + const workspaces = sync.data.workspaceList + const next = ++run + if (!workspaces.length) { + setCounts({}) + return + } + setCounts(Object.fromEntries(workspaces.map((workspace) => [workspace.id, undefined]))) + void Promise.all( + workspaces.map(async (workspace) => { + const client = createOpencodeClient({ + baseUrl: sdk.url, + fetch: sdk.fetch, + directory: sync.data.path.directory || sdk.directory, + experimental_workspaceID: workspace.id, + }) + const result = await client.session.list({ roots: true }).catch(() => undefined) + return [workspace.id, result ? (result.data?.length ?? 0) : null] as const + }), + ).then((entries) => { + if (run !== next) return + setCounts(Object.fromEntries(entries)) + }) + }) + + const options = createMemo(() => [ + { + title: "Local", + value: "__local__", + category: "Workspace", + description: "Use the local machine", + footer: `${localCount()} session${localCount() === 1 ? "" : "s"}`, + }, + ...sync.data.workspaceList.map((workspace) => { + const count = counts()[workspace.id] + return { + title: + toDelete() === workspace.id + ? `Delete ${workspace.id}? Press ${keybind.print("session_delete")} again` + : workspace.id, + value: workspace.id, + category: workspace.type, + description: workspace.branch ? `Branch ${workspace.branch}` : undefined, + footer: + count === undefined + ? "Loading sessions..." + : count === null + ? "Sessions unavailable" + : `${count} session${count === 1 ? "" : "s"}`, + } + }), + { + title: "+ New workspace", + value: "__create__", + category: "Actions", + description: "Create a new workspace", + }, + ]) + + onMount(() => { + dialog.setSize("large") + void sync.workspace.sync() + }) + + return ( + { + setToDelete(undefined) + }} + onSelect={(option) => { + setToDelete(undefined) + if (option.value === "__create__") { + dialog.replace(() => open(workspaceID, true)} />) + return + } + void selectWorkspace(option.value) + }} + keybind={[ + { + keybind: keybind.all.session_delete?.[0], + title: "delete", + onTrigger: async (option) => { + if (option.value === "__create__" || option.value === "__local__") return + if (toDelete() !== option.value) { + setToDelete(option.value) + return + } + const result = await sdk.client.experimental.workspace.remove({ id: option.value }).catch(() => undefined) + setToDelete(undefined) + if (result?.error) { + toast.show({ + message: "Failed to delete workspace", + variant: "error", + }) + return + } + if (currentWorkspaceID() === option.value) { + route.navigate({ + type: "home", + }) + } + await sync.workspace.sync() + }, + }, + ]} + /> + ) +} diff --git a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx index d63c248fb8..77577b2a0e 100644 --- a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx @@ -539,12 +539,25 @@ export function Prompt(props: PromptProps) { promptModelWarning() return } - const sessionID = props.sessionID - ? props.sessionID - : await (async () => { - const sessionID = await sdk.client.session.create({}).then((x) => x.data!.id) - return sessionID - })() + + let sessionID = props.sessionID + if (sessionID == null) { + const res = await sdk.client.session.create({}) + + if (res.error) { + console.log("Creating a session failed:", res.error) + + toast.show({ + message: "Creating a session failed. Open console for more details.", + variant: "error", + }) + + return + } + + sessionID = res.data.id + } + const messageID = Identifier.ascending("message") let inputText = store.prompt.input diff --git a/packages/opencode/src/cli/cmd/tui/component/tips.tsx b/packages/opencode/src/cli/cmd/tui/component/tips.tsx index d0a7e5b44e..73d82248ad 100644 --- a/packages/opencode/src/cli/cmd/tui/component/tips.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/tips.tsx @@ -80,11 +80,11 @@ const TIPS = [ "Switch to {highlight}Plan{/highlight} agent to get suggestions without making actual changes", "Use {highlight}@agent-name{/highlight} in prompts to invoke specialized subagents", "Press {highlight}Ctrl+X Right/Left{/highlight} to cycle through parent and child sessions", - "Create {highlight}opencode.json{/highlight} in project root for project-specific settings", - "Place settings in {highlight}~/.config/opencode/opencode.json{/highlight} for global config", + "Create {highlight}opencode.json{/highlight} for server settings and {highlight}tui.json{/highlight} for TUI settings", + "Place TUI settings in {highlight}~/.config/opencode/tui.json{/highlight} for global config", "Add {highlight}$schema{/highlight} to your config for autocomplete in your editor", "Configure {highlight}model{/highlight} in config to set your default model", - "Override any keybind in config via the {highlight}keybinds{/highlight} section", + "Override any keybind in {highlight}tui.json{/highlight} via the {highlight}keybinds{/highlight} section", "Set any keybind to {highlight}none{/highlight} to disable it completely", "Configure local or remote MCP servers in the {highlight}mcp{/highlight} config section", "OpenCode auto-handles OAuth for remote MCP servers requiring auth", @@ -140,7 +140,7 @@ const TIPS = [ "Press {highlight}Ctrl+X G{/highlight} or {highlight}/timeline{/highlight} to jump to specific messages", "Press {highlight}Ctrl+X H{/highlight} to toggle code block visibility in messages", "Press {highlight}Ctrl+X S{/highlight} or {highlight}/status{/highlight} to see system status info", - "Enable {highlight}tui.scroll_acceleration{/highlight} for smooth macOS-style scrolling", + "Enable {highlight}scroll_acceleration{/highlight} in {highlight}tui.json{/highlight} for smooth macOS-style scrolling", "Toggle username display in chat via command palette ({highlight}Ctrl+P{/highlight})", "Run {highlight}docker run -it --rm ghcr.io/anomalyco/opencode{/highlight} for containerized use", "Use {highlight}/connect{/highlight} with OpenCode Zen for curated, tested models", diff --git a/packages/opencode/src/cli/cmd/tui/component/workspace/dialog-session-list.tsx b/packages/opencode/src/cli/cmd/tui/component/workspace/dialog-session-list.tsx new file mode 100644 index 0000000000..326f094a56 --- /dev/null +++ b/packages/opencode/src/cli/cmd/tui/component/workspace/dialog-session-list.tsx @@ -0,0 +1,151 @@ +import { useDialog } from "@tui/ui/dialog" +import { DialogSelect } from "@tui/ui/dialog-select" +import { useRoute } from "@tui/context/route" +import { useSync } from "@tui/context/sync" +import { createMemo, createSignal, createResource, onMount, Show } from "solid-js" +import { Locale } from "@/util/locale" +import { useKeybind } from "../../context/keybind" +import { useTheme } from "../../context/theme" +import { useSDK } from "../../context/sdk" +import { DialogSessionRename } from "../dialog-session-rename" +import { useKV } from "../../context/kv" +import { createDebouncedSignal } from "../../util/signal" +import { Spinner } from "../spinner" +import { useToast } from "../../ui/toast" + +export function DialogSessionList(props: { workspaceID?: string; localOnly?: boolean } = {}) { + const dialog = useDialog() + const route = useRoute() + const sync = useSync() + const keybind = useKeybind() + const { theme } = useTheme() + const sdk = useSDK() + const kv = useKV() + const toast = useToast() + const [toDelete, setToDelete] = createSignal() + const [search, setSearch] = createDebouncedSignal("", 150) + + const [listed, listedActions] = createResource( + () => props.workspaceID, + async (workspaceID) => { + if (!workspaceID) return undefined + const result = await sdk.client.session.list({ roots: true }) + return result.data ?? [] + }, + ) + + const [searchResults] = createResource(search, async (query) => { + if (!query || props.localOnly) return undefined + const result = await sdk.client.session.list({ + search: query, + limit: 30, + ...(props.workspaceID ? { roots: true } : {}), + }) + return result.data ?? [] + }) + + const currentSessionID = createMemo(() => (route.data.type === "session" ? route.data.sessionID : undefined)) + + const sessions = createMemo(() => { + if (searchResults()) return searchResults()! + if (props.workspaceID) return listed() ?? [] + if (props.localOnly) return sync.data.session.filter((session) => !session.workspaceID) + return sync.data.session + }) + + const options = createMemo(() => { + const today = new Date().toDateString() + return sessions() + .filter((x) => { + if (x.parentID !== undefined) return false + if (props.workspaceID && listed()) return true + if (props.workspaceID) return x.workspaceID === props.workspaceID + if (props.localOnly) return !x.workspaceID + return true + }) + .toSorted((a, b) => b.time.updated - a.time.updated) + .map((x) => { + const date = new Date(x.time.updated) + let category = date.toDateString() + if (category === today) { + category = "Today" + } + const isDeleting = toDelete() === x.id + const status = sync.data.session_status?.[x.id] + const isWorking = status?.type === "busy" + return { + title: isDeleting ? `Press ${keybind.print("session_delete")} again to confirm` : x.title, + bg: isDeleting ? theme.error : undefined, + value: x.id, + category, + footer: Locale.time(x.time.updated), + gutter: isWorking ? : undefined, + } + }) + }) + + onMount(() => { + dialog.setSize("large") + }) + + return ( + { + setToDelete(undefined) + }} + onSelect={(option) => { + route.navigate({ + type: "session", + sessionID: option.value, + }) + dialog.clear() + }} + keybind={[ + { + keybind: keybind.all.session_delete?.[0], + title: "delete", + onTrigger: async (option) => { + if (toDelete() === option.value) { + const deleted = await sdk.client.session + .delete({ + sessionID: option.value, + }) + .then(() => true) + .catch(() => false) + setToDelete(undefined) + if (!deleted) { + toast.show({ + message: "Failed to delete session", + variant: "error", + }) + return + } + if (props.workspaceID) { + listedActions.mutate((sessions) => sessions?.filter((session) => session.id !== option.value)) + return + } + sync.set( + "session", + sync.data.session.filter((session) => session.id !== option.value), + ) + return + } + setToDelete(option.value) + }, + }, + { + keybind: keybind.all.session_rename?.[0], + title: "rename", + onTrigger: async (option) => { + dialog.replace(() => ) + }, + }, + ]} + /> + ) +} diff --git a/packages/opencode/src/cli/cmd/tui/context/exit.tsx b/packages/opencode/src/cli/cmd/tui/context/exit.tsx index a6f775913a..3ed4ae3d2c 100644 --- a/packages/opencode/src/cli/cmd/tui/context/exit.tsx +++ b/packages/opencode/src/cli/cmd/tui/context/exit.tsx @@ -15,6 +15,7 @@ export const { use: useExit, provider: ExitProvider } = createSimpleContext({ init: (input: { onExit?: () => Promise }) => { const renderer = useRenderer() let message: string | undefined + let task: Promise | undefined const store = { set: (value?: string) => { const prev = message @@ -29,20 +30,24 @@ export const { use: useExit, provider: ExitProvider } = createSimpleContext({ get: () => message, } const exit: Exit = Object.assign( - async (reason?: unknown) => { - // Reset window title before destroying renderer - renderer.setTerminalTitle("") - renderer.destroy() - win32FlushInputBuffer() - if (reason) { - const formatted = FormatError(reason) ?? FormatUnknownError(reason) - if (formatted) { - process.stderr.write(formatted + "\n") + (reason?: unknown) => { + if (task) return task + task = (async () => { + // Reset window title before destroying renderer + renderer.setTerminalTitle("") + renderer.destroy() + win32FlushInputBuffer() + if (reason) { + const formatted = FormatError(reason) ?? FormatUnknownError(reason) + if (formatted) { + process.stderr.write(formatted + "\n") + } } - } - const text = store.get() - if (text) process.stdout.write(text + "\n") - await input.onExit?.() + const text = store.get() + if (text) process.stdout.write(text + "\n") + await input.onExit?.() + })() + return task }, { message: store, diff --git a/packages/opencode/src/cli/cmd/tui/context/keybind.tsx b/packages/opencode/src/cli/cmd/tui/context/keybind.tsx index 0dbbbc6f9e..566d66ade5 100644 --- a/packages/opencode/src/cli/cmd/tui/context/keybind.tsx +++ b/packages/opencode/src/cli/cmd/tui/context/keybind.tsx @@ -1,20 +1,22 @@ import { createMemo } from "solid-js" -import { useSync } from "@tui/context/sync" import { Keybind } from "@/util/keybind" import { pipe, mapValues } from "remeda" -import type { KeybindsConfig } from "@opencode-ai/sdk/v2" +import type { TuiConfig } from "@/config/tui" import type { ParsedKey, Renderable } from "@opentui/core" import { createStore } from "solid-js/store" import { useKeyboard, useRenderer } from "@opentui/solid" import { createSimpleContext } from "./helper" +import { useTuiConfig } from "./tui-config" + +export type KeybindKey = keyof NonNullable & string export const { use: useKeybind, provider: KeybindProvider } = createSimpleContext({ name: "Keybind", init: () => { - const sync = useSync() - const keybinds = createMemo(() => { + const config = useTuiConfig() + const keybinds = createMemo>(() => { return pipe( - sync.data.config.keybinds ?? {}, + (config.keybinds ?? {}) as Record, mapValues((value) => Keybind.parse(value)), ) }) @@ -78,7 +80,7 @@ export const { use: useKeybind, provider: KeybindProvider } = createSimpleContex } return Keybind.fromParsedKey(evt, store.leader) }, - match(key: keyof KeybindsConfig, evt: ParsedKey) { + match(key: KeybindKey, evt: ParsedKey) { const keybind = keybinds()[key] if (!keybind) return false const parsed: Keybind.Info = result.parse(evt) @@ -88,7 +90,7 @@ export const { use: useKeybind, provider: KeybindProvider } = createSimpleContex } } }, - print(key: keyof KeybindsConfig) { + print(key: KeybindKey) { const first = keybinds()[key]?.at(0) if (!first) return "" const result = Keybind.toString(first) diff --git a/packages/opencode/src/cli/cmd/tui/context/sdk.tsx b/packages/opencode/src/cli/cmd/tui/context/sdk.tsx index 7fa7e05c3d..2403a4e938 100644 --- a/packages/opencode/src/cli/cmd/tui/context/sdk.tsx +++ b/packages/opencode/src/cli/cmd/tui/context/sdk.tsx @@ -5,6 +5,7 @@ import { batch, onCleanup, onMount } from "solid-js" export type EventSource = { on: (handler: (event: Event) => void) => () => void + setWorkspace?: (workspaceID?: string) => void } export const { use: useSDK, provider: SDKProvider } = createSimpleContext({ @@ -17,13 +18,21 @@ export const { use: useSDK, provider: SDKProvider } = createSimpleContext({ events?: EventSource }) => { const abort = new AbortController() - const sdk = createOpencodeClient({ - baseUrl: props.url, - signal: abort.signal, - directory: props.directory, - fetch: props.fetch, - headers: props.headers, - }) + let workspaceID: string | undefined + let sse: AbortController | undefined + + function createSDK() { + return createOpencodeClient({ + baseUrl: props.url, + signal: abort.signal, + directory: props.directory, + fetch: props.fetch, + headers: props.headers, + experimental_workspaceID: workspaceID, + }) + } + + let sdk = createSDK() const emitter = createGlobalEmitter<{ [key in Event["type"]]: Extract @@ -61,41 +70,56 @@ export const { use: useSDK, provider: SDKProvider } = createSimpleContext({ flush() } - onMount(async () => { - // If an event source is provided, use it instead of SSE + function startSSE() { + sse?.abort() + const ctrl = new AbortController() + sse = ctrl + ;(async () => { + while (true) { + if (abort.signal.aborted || ctrl.signal.aborted) break + const events = await sdk.event.subscribe({}, { signal: ctrl.signal }) + + for await (const event of events.stream) { + if (ctrl.signal.aborted) break + handleEvent(event) + } + + if (timer) clearTimeout(timer) + if (queue.length > 0) flush() + } + })().catch(() => {}) + } + + onMount(() => { if (props.events) { const unsub = props.events.on(handleEvent) onCleanup(unsub) - return - } - - // Fall back to SSE - while (true) { - if (abort.signal.aborted) break - const events = await sdk.event.subscribe( - {}, - { - signal: abort.signal, - }, - ) - - for await (const event of events.stream) { - handleEvent(event) - } - - // Flush any remaining events - if (timer) clearTimeout(timer) - if (queue.length > 0) { - flush() - } + } else { + startSSE() } }) onCleanup(() => { abort.abort() + sse?.abort() if (timer) clearTimeout(timer) }) - return { client: sdk, event: emitter, url: props.url } + return { + get client() { + return sdk + }, + directory: props.directory, + event: emitter, + fetch: props.fetch ?? fetch, + setWorkspace(next?: string) { + if (workspaceID === next) return + workspaceID = next + sdk = createSDK() + props.events?.setWorkspace?.(next) + if (!props.events) startSSE() + }, + url: props.url, + } }, }) diff --git a/packages/opencode/src/cli/cmd/tui/context/sync.tsx b/packages/opencode/src/cli/cmd/tui/context/sync.tsx index 269ed7ae0b..3b296a927a 100644 --- a/packages/opencode/src/cli/cmd/tui/context/sync.tsx +++ b/packages/opencode/src/cli/cmd/tui/context/sync.tsx @@ -28,6 +28,7 @@ import { useArgs } from "./args" import { batch, onMount } from "solid-js" import { Log } from "@/util/log" import type { Path } from "@opencode-ai/sdk" +import type { Workspace } from "@opencode-ai/sdk/v2" export const { use: useSync, provider: SyncProvider } = createSimpleContext({ name: "Sync", @@ -73,6 +74,7 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({ formatter: FormatterStatus[] vcs: VcsInfo | undefined path: Path + workspaceList: Workspace[] }>({ provider_next: { all: [], @@ -100,10 +102,17 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({ formatter: [], vcs: undefined, path: { state: "", config: "", worktree: "", directory: "" }, + workspaceList: [], }) const sdk = useSDK() + async function syncWorkspaces() { + const result = await sdk.client.experimental.workspace.list().catch(() => undefined) + if (!result?.data) return + setStore("workspaceList", reconcile(result.data)) + } + sdk.event.listen((e) => { const event = e.details switch (event.type) { @@ -413,6 +422,7 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({ sdk.client.provider.auth().then((x) => setStore("provider_auth", reconcile(x.data ?? {}))), sdk.client.vcs.get().then((x) => setStore("vcs", reconcile(x.data))), sdk.client.path.get().then((x) => setStore("path", reconcile(x.data!))), + syncWorkspaces(), ]).then(() => { setStore("status", "complete") }) @@ -481,6 +491,12 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({ fullSyncedSessions.add(sessionID) }, }, + workspace: { + get(workspaceID: string) { + return store.workspaceList.find((workspace) => workspace.id === workspaceID) + }, + sync: syncWorkspaces, + }, bootstrap, } return result diff --git a/packages/opencode/src/cli/cmd/tui/context/theme.tsx b/packages/opencode/src/cli/cmd/tui/context/theme.tsx index 465ed805ea..2320c08ccc 100644 --- a/packages/opencode/src/cli/cmd/tui/context/theme.tsx +++ b/packages/opencode/src/cli/cmd/tui/context/theme.tsx @@ -1,7 +1,6 @@ import { SyntaxStyle, RGBA, type TerminalColors } from "@opentui/core" import path from "path" import { createEffect, createMemo, onMount } from "solid-js" -import { useSync } from "@tui/context/sync" import { createSimpleContext } from "./helper" import { Glob } from "../../../../util/glob" import aura from "./theme/aura.json" with { type: "json" } @@ -42,6 +41,7 @@ import { useRenderer } from "@opentui/solid" import { createStore, produce } from "solid-js/store" import { Global } from "@/global" import { Filesystem } from "@/util/filesystem" +import { useTuiConfig } from "./tui-config" type ThemeColors = { primary: RGBA @@ -280,17 +280,17 @@ function ansiToRgba(code: number): RGBA { export const { use: useTheme, provider: ThemeProvider } = createSimpleContext({ name: "Theme", init: (props: { mode: "dark" | "light" }) => { - const sync = useSync() + const config = useTuiConfig() const kv = useKV() const [store, setStore] = createStore({ themes: DEFAULT_THEMES, mode: kv.get("theme_mode", props.mode), - active: (sync.data.config.theme ?? kv.get("theme", "opencode")) as string, + active: (config.theme ?? kv.get("theme", "opencode")) as string, ready: false, }) createEffect(() => { - const theme = sync.data.config.theme + const theme = config.theme if (theme) setStore("active", theme) }) diff --git a/packages/opencode/src/cli/cmd/tui/context/tui-config.tsx b/packages/opencode/src/cli/cmd/tui/context/tui-config.tsx new file mode 100644 index 0000000000..62dbf1ebd1 --- /dev/null +++ b/packages/opencode/src/cli/cmd/tui/context/tui-config.tsx @@ -0,0 +1,9 @@ +import { TuiConfig } from "@/config/tui" +import { createSimpleContext } from "./helper" + +export const { use: useTuiConfig, provider: TuiConfigProvider } = createSimpleContext({ + name: "TuiConfig", + init: (props: { config: TuiConfig.Info }) => { + return props.config + }, +}) diff --git a/packages/opencode/src/cli/cmd/tui/routes/home.tsx b/packages/opencode/src/cli/cmd/tui/routes/home.tsx index c011f6c624..24ea8f3b31 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/home.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/home.tsx @@ -1,5 +1,5 @@ import { Prompt, type PromptRef } from "@tui/component/prompt" -import { createMemo, Match, onMount, Show, Switch } from "solid-js" +import { createEffect, createMemo, Match, on, onMount, Show, Switch } from "solid-js" import { useTheme } from "@tui/context/theme" import { useKeybind } from "@tui/context/keybind" import { Logo } from "../component/logo" @@ -14,6 +14,7 @@ import { usePromptRef } from "../context/prompt" import { Installation } from "@/installation" import { useKV } from "../context/kv" import { useCommandDialog } from "../component/dialog-command" +import { useLocal } from "../context/local" // TODO: what is the best way to do this? let once = false @@ -76,6 +77,7 @@ export function Home() { let prompt: PromptRef const args = useArgs() + const local = useLocal() onMount(() => { if (once) return if (route.initialPrompt) { @@ -84,9 +86,21 @@ export function Home() { } else if (args.prompt) { prompt.set({ input: args.prompt, parts: [] }) once = true - prompt.submit() } }) + + // Wait for sync and model store to be ready before auto-submitting --prompt + createEffect( + on( + () => sync.ready && local.model.ready, + (ready) => { + if (!ready) return + if (!args.prompt) return + if (prompt.current?.input !== args.prompt) return + prompt.submit() + }, + ), + ) const directory = useDirectory() const keybind = useKeybind() diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/header.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/header.tsx index 0c5ea9a857..f64dbe533a 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/header.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/header.tsx @@ -7,6 +7,7 @@ import { SplitBorder } from "@tui/component/border" import type { AssistantMessage, Session } from "@opencode-ai/sdk/v2" import { useCommandDialog } from "@tui/component/dialog-command" import { useKeybind } from "../../context/keybind" +import { Flag } from "@/flag/flag" import { useTerminalDimensions } from "@opentui/solid" const Title = (props: { session: Accessor }) => { @@ -29,6 +30,17 @@ const ContextInfo = (props: { context: Accessor; cost: Acces ) } +const WorkspaceInfo = (props: { workspace: Accessor }) => { + const { theme } = useTheme() + return ( + + + {props.workspace()} + + + ) +} + export function Header() { const route = useRouteData("session") const sync = useSync() @@ -59,6 +71,14 @@ export function Header() { return result }) + const workspace = createMemo(() => { + const id = session()?.workspaceID + if (!id) return "Workspace local" + const info = sync.workspace.get(id) + if (!info) return `Workspace ${id}` + return `Workspace ${id} (${info.type})` + }) + const { theme } = useTheme() const keybind = useKeybind() const command = useCommandDialog() @@ -83,9 +103,19 @@ export function Header() { - - Subagent session - + {Flag.OPENCODE_EXPERIMENTAL_WORKSPACES ? ( + + + Subagent session + + + + ) : ( + + Subagent session + + )} + @@ -124,7 +154,14 @@ export function Header() { - + {Flag.OPENCODE_EXPERIMENTAL_WORKSPACES ? ( + <box flexDirection="column"> + <Title session={session} /> + <WorkspaceInfo workspace={workspace} /> + </box> + ) : ( + <Title session={session} /> + )} <ContextInfo context={context} cost={cost} /> </box> </Match> diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx index f5a7f6f6ca..5358b61ef3 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx @@ -7,6 +7,7 @@ import { For, Match, on, + onMount, Show, Switch, useContext, @@ -48,6 +49,7 @@ import type { SkillTool } from "@/tool/skill" import { useKeyboard, useRenderer, useTerminalDimensions, type JSX } from "@opentui/solid" import { useSDK } from "@tui/context/sdk" import { useCommandDialog } from "@tui/component/dialog-command" +import type { DialogContext } from "@tui/ui/dialog" import { useKeybind } from "@tui/context/keybind" import { Header } from "./header" import { parsePatch } from "diff" @@ -78,6 +80,7 @@ import { QuestionPrompt } from "./question" import { DialogExportOptions } from "../../ui/dialog-export-options" import { formatTranscript } from "../../util/transcript" import { UI } from "@/cli/ui.ts" +import { useTuiConfig } from "../../context/tui-config" addDefaultParsers(parsers.parsers) @@ -101,6 +104,7 @@ const context = createContext<{ showGenericToolOutput: () => boolean diffWrapMode: () => "word" | "none" sync: ReturnType<typeof useSync> + tui: ReturnType<typeof useTuiConfig> }>() function use() { @@ -113,6 +117,7 @@ export function Session() { const route = useRouteData("session") const { navigate } = useRoute() const sync = useSync() + const tuiConfig = useTuiConfig() const kv = useKV() const { theme } = useTheme() const promptRef = usePromptRef() @@ -149,7 +154,7 @@ export function Session() { const [timestamps, setTimestamps] = kv.signal<"hide" | "show">("timestamps", "hide") const [showDetails, setShowDetails] = kv.signal("tool_details_visibility", true) const [showAssistantMetadata, setShowAssistantMetadata] = kv.signal("assistant_metadata_visibility", true) - const [showScrollbar, setShowScrollbar] = kv.signal("scrollbar_visible", false) + const [showScrollbar, setShowScrollbar] = kv.signal("scrollbar_visible", true) const [showHeader, setShowHeader] = kv.signal("header_visible", true) const [diffWrapMode] = kv.signal<"word" | "none">("diff_wrap_mode", "word") const [animationsEnabled, setAnimationsEnabled] = kv.signal("animations_enabled", true) @@ -166,7 +171,7 @@ export function Session() { const contentWidth = createMemo(() => dimensions().width - (sidebarVisible() ? 42 : 0) - 4) const scrollAcceleration = createMemo(() => { - const tui = sync.data.config.tui + const tui = tuiConfig if (tui?.scroll_acceleration?.enabled) { return new MacOSScrollAccel() } @@ -177,6 +182,12 @@ export function Session() { return new CustomSpeedScroll(3) }) + createEffect(() => { + if (session()?.workspaceID) { + sdk.setWorkspace(session()?.workspaceID) + } + }) + createEffect(async () => { await sync.session .sync(route.sessionID) @@ -223,6 +234,8 @@ export function Session() { let scroll: ScrollBoxRenderable let prompt: PromptRef const keybind = useKeybind() + const dialog = useDialog() + const renderer = useRenderer() // Allow exit when in child session (prompt is hidden) const exit = useExit() @@ -234,7 +247,6 @@ export function Session() { const logo = UI.logo(" ").split(/\r?\n/) return exit.message.set( [ - ``, `${logo[0] ?? ""}`, `${logo[1] ?? ""}`, `${logo[2] ?? ""}`, @@ -309,19 +321,40 @@ export function Session() { const local = useLocal() - function moveChild(direction: number) { + function moveFirstChild() { if (children().length === 1) return - let next = children().findIndex((x) => x.id === session()?.id) + direction - if (next >= children().length) next = 0 - if (next < 0) next = children().length - 1 - if (children()[next]) { + const next = children().find((x) => !!x.parentID) + if (next) { navigate({ type: "session", - sessionID: children()[next].id, + sessionID: next.id, }) } } + function moveChild(direction: number) { + if (children().length === 1) return + + const sessions = children().filter((x) => !!x.parentID) + let next = sessions.findIndex((x) => x.id === session()?.id) + direction + + if (next >= sessions.length) next = 0 + if (next < 0) next = sessions.length - 1 + if (sessions[next]) { + navigate({ + type: "session", + sessionID: sessions[next].id, + }) + } + } + + function childSessionHandler(func: (dialog: DialogContext) => void) { + return (dialog: DialogContext) => { + if (!session()?.parentID || dialog.stack.length > 0) return + func(dialog) + } + } + const command = useCommandDialog() command.register(() => [ { @@ -881,24 +914,13 @@ export function Session() { }, }, { - title: "Next child session", - value: "session.child.next", - keybind: "session_child_cycle", + title: "Go to child session", + value: "session.child.first", + keybind: "session_child_first", category: "Session", hidden: true, onSelect: (dialog) => { - moveChild(1) - dialog.clear() - }, - }, - { - title: "Previous child session", - value: "session.child.previous", - keybind: "session_child_cycle_reverse", - category: "Session", - hidden: true, - onSelect: (dialog) => { - moveChild(-1) + moveFirstChild() dialog.clear() }, }, @@ -908,7 +930,8 @@ export function Session() { keybind: "session_parent", category: "Session", hidden: true, - onSelect: (dialog) => { + enabled: !!session()?.parentID, + onSelect: childSessionHandler((dialog) => { const parentID = session()?.parentID if (parentID) { navigate({ @@ -917,7 +940,31 @@ export function Session() { }) } dialog.clear() - }, + }), + }, + { + title: "Next child session", + value: "session.child.next", + keybind: "session_child_cycle", + category: "Session", + hidden: true, + enabled: !!session()?.parentID, + onSelect: childSessionHandler((dialog) => { + moveChild(1) + dialog.clear() + }), + }, + { + title: "Previous child session", + value: "session.child.previous", + keybind: "session_child_cycle_reverse", + category: "Session", + hidden: true, + enabled: !!session()?.parentID, + onSelect: childSessionHandler((dialog) => { + moveChild(-1) + dialog.clear() + }), }, ]) @@ -968,9 +1015,6 @@ export function Session() { } }) - const dialog = useDialog() - const renderer = useRenderer() - // snap to bottom when session changes createEffect(on(() => route.sessionID, toBottom)) @@ -988,6 +1032,7 @@ export function Session() { showGenericToolOutput, diffWrapMode, sync, + tui: tuiConfig, }} > <box flexDirection="row"> @@ -1287,6 +1332,8 @@ function AssistantMessage(props: { message: AssistantMessage; parts: Part[]; las return props.message.time.completed - user.time.created }) + const keybind = useKeybind() + return ( <> <For each={props.parts}> @@ -1304,6 +1351,14 @@ function AssistantMessage(props: { message: AssistantMessage; parts: Part[]; las ) }} </For> + <Show when={props.parts.some((x) => x.type === "tool" && x.tool === "task")}> + <box paddingTop={1} paddingLeft={3}> + <text fg={theme.text}> + {keybind.print("session_child_first")} + <span style={{ fg: theme.textMuted }}> view subagents</span> + </text> + </box> + </Show> <Show when={props.message.error && props.message.error.name !== "MessageAbortedError"}> <box border={["left"]} @@ -1573,13 +1628,17 @@ function InlineTool(props: { iconColor?: RGBA complete: any pending: string + spinner?: boolean children: JSX.Element part: ToolPart + onClick?: () => void }) { const [margin, setMargin] = createSignal(0) const { theme } = useTheme() const ctx = use() const sync = useSync() + const renderer = useRenderer() + const [hover, setHover] = createSignal(false) const permission = createMemo(() => { const callID = sync.data.permission[ctx.sessionID]?.at(0)?.tool?.callID @@ -1589,6 +1648,7 @@ function InlineTool(props: { const fg = createMemo(() => { if (permission()) return theme.warning + if (hover() && props.onClick) return theme.text if (props.complete) return theme.textMuted return theme.text }) @@ -1606,6 +1666,12 @@ function InlineTool(props: { <box marginTop={margin()} paddingLeft={3} + onMouseOver={() => props.onClick && setHover(true)} + onMouseOut={() => setHover(false)} + onMouseUp={() => { + if (renderer.getSelection()?.getSelectedText()) return + props.onClick?.() + }} renderBefore={function () { const el = this as BoxRenderable const parent = el.parent @@ -1629,11 +1695,18 @@ function InlineTool(props: { } }} > - <text paddingLeft={3} fg={fg()} attributes={denied() ? TextAttributes.STRIKETHROUGH : undefined}> - <Show fallback={<>~ {props.pending}</>} when={props.complete}> - <span style={{ fg: props.iconColor }}>{props.icon}</span> {props.children} - </Show> - </text> + <Switch> + <Match when={props.spinner}> + <Spinner color={fg()} children={props.children} /> + </Match> + <Match when={true}> + <text paddingLeft={3} fg={fg()} attributes={denied() ? TextAttributes.STRIKETHROUGH : undefined}> + <Show fallback={<>~ {props.pending}</>} when={props.complete}> + <span style={{ fg: props.iconColor }}>{props.icon}</span> {props.children} + </Show> + </text> + </Match> + </Switch> <Show when={error() && !denied()}> <text fg={theme.error}>{error()}</text> </Show> @@ -1762,11 +1835,6 @@ function Write(props: ToolProps<typeof WriteTool>) { return props.input.content }) - const diagnostics = createMemo(() => { - const filePath = Filesystem.normalizePath(props.input.filePath ?? "") - return props.metadata.diagnostics?.[filePath] ?? [] - }) - return ( <Switch> <Match when={props.metadata.diagnostics !== undefined}> @@ -1780,15 +1848,7 @@ function Write(props: ToolProps<typeof WriteTool>) { content={code()} /> </line_number> - <Show when={diagnostics().length}> - <For each={diagnostics()}> - {(diagnostic) => ( - <text fg={theme.error}> - Error [{diagnostic.range.start.line}:{diagnostic.range.start.character}]: {diagnostic.message} - </text> - )} - </For> - </Show> + <Diagnostics diagnostics={props.metadata.diagnostics} filePath={props.input.filePath ?? ""} /> </BlockTool> </Match> <Match when={true}> @@ -1813,6 +1873,7 @@ function Glob(props: ToolProps<typeof GlobTool>) { function Read(props: ToolProps<typeof ReadTool>) { const { theme } = useTheme() + const isRunning = createMemo(() => props.part.state.status === "running") const loaded = createMemo(() => { if (props.part.state.status !== "completed") return [] if (props.part.state.time.compacted) return [] @@ -1822,7 +1883,13 @@ function Read(props: ToolProps<typeof ReadTool>) { }) return ( <> - <InlineTool icon="→" pending="Reading file..." complete={props.input.filePath} part={props.part}> + <InlineTool + icon="→" + pending="Reading file..." + complete={props.input.filePath} + spinner={isRunning()} + part={props.part} + > Read {normalizePath(props.input.filePath!)} {input(props.input, ["filePath"])} </InlineTool> <For each={loaded()}> @@ -1898,62 +1965,64 @@ function Task(props: ToolProps<typeof TaskTool>) { const local = useLocal() const sync = useSync() + onMount(() => { + if (props.metadata.sessionId && !sync.data.message[props.metadata.sessionId]?.length) + sync.session.sync(props.metadata.sessionId) + }) + + const messages = createMemo(() => sync.data.message[props.metadata.sessionId ?? ""] ?? []) + const tools = createMemo(() => { - const sessionID = props.metadata.sessionId - const msgs = sync.data.message[sessionID ?? ""] ?? [] - return msgs.flatMap((msg) => + return messages().flatMap((msg) => (sync.data.part[msg.id] ?? []) .filter((part): part is ToolPart => part.type === "tool") .map((part) => ({ tool: part.tool, state: part.state })), ) }) - const current = createMemo(() => tools().findLast((x) => x.state.status !== "pending")) + const current = createMemo(() => tools().findLast((x) => (x.state as any).title)) const isRunning = createMemo(() => props.part.state.status === "running") + const duration = createMemo(() => { + const first = messages().find((x) => x.role === "user")?.time.created + const assistant = messages().findLast((x) => x.role === "assistant")?.time.completed + if (!first || !assistant) return 0 + return assistant - first + }) + + const content = createMemo(() => { + if (!props.input.description) return "" + let content = [`Task ${props.input.description}`] + + if (isRunning() && tools().length > 0) { + // content[0] += ` · ${tools().length} toolcalls` + if (current()) content.push(`↳ ${Locale.titlecase(current()!.tool)} ${(current()!.state as any).title}`) + else content.push(`↳ ${tools().length} toolcalls`) + } + + if (props.part.state.status === "completed") { + content.push(`└ ${tools().length} toolcalls · ${Locale.duration(duration())}`) + } + + return content.join("\n") + }) + return ( - <Switch> - <Match when={props.input.description || props.input.subagent_type}> - <BlockTool - title={"# " + Locale.titlecase(props.input.subagent_type ?? "unknown") + " Task"} - onClick={ - props.metadata.sessionId - ? () => navigate({ type: "session", sessionID: props.metadata.sessionId! }) - : undefined - } - part={props.part} - spinner={isRunning()} - > - <box> - <text style={{ fg: theme.textMuted }}> - {props.input.description} ({tools().length} toolcalls) - </text> - <Show when={current()}> - {(item) => { - const title = item().state.status === "completed" ? (item().state as any).title : "" - return ( - <text style={{ fg: item().state.status === "error" ? theme.error : theme.textMuted }}> - └ {Locale.titlecase(item().tool)} {title} - </text> - ) - }} - </Show> - </box> - <Show when={props.metadata.sessionId}> - <text fg={theme.text}> - {keybind.print("session_child_cycle")} - <span style={{ fg: theme.textMuted }}> view subagents</span> - </text> - </Show> - </BlockTool> - </Match> - <Match when={true}> - <InlineTool icon="#" pending="Delegating..." complete={props.input.subagent_type} part={props.part}> - {props.input.subagent_type} Task {props.input.description} - </InlineTool> - </Match> - </Switch> + <InlineTool + icon="│" + spinner={isRunning()} + complete={props.input.description} + pending="Delegating..." + part={props.part} + onClick={() => { + if (props.metadata.sessionId) { + navigate({ type: "session", sessionID: props.metadata.sessionId }) + } + }} + > + {content()} + </InlineTool> ) } @@ -1962,7 +2031,7 @@ function Edit(props: ToolProps<typeof EditTool>) { const { theme, syntax } = useTheme() const view = createMemo(() => { - const diffStyle = ctx.sync.data.config.tui?.diff_style + const diffStyle = ctx.tui.diff_style if (diffStyle === "stacked") return "unified" // Default to "auto" behavior return ctx.width > 120 ? "split" : "unified" @@ -1972,12 +2041,6 @@ function Edit(props: ToolProps<typeof EditTool>) { const diffContent = createMemo(() => props.metadata.diff) - const diagnostics = createMemo(() => { - const filePath = Filesystem.normalizePath(props.input.filePath ?? "") - const arr = props.metadata.diagnostics?.[filePath] ?? [] - return arr.filter((x) => x.severity === 1).slice(0, 3) - }) - return ( <Switch> <Match when={props.metadata.diff !== undefined}> @@ -2003,18 +2066,7 @@ function Edit(props: ToolProps<typeof EditTool>) { removedLineNumberBg={theme.diffRemovedLineNumberBg} /> </box> - <Show when={diagnostics().length}> - <box> - <For each={diagnostics()}> - {(diagnostic) => ( - <text fg={theme.error}> - Error [{diagnostic.range.start.line + 1}:{diagnostic.range.start.character + 1}]{" "} - {diagnostic.message} - </text> - )} - </For> - </box> - </Show> + <Diagnostics diagnostics={props.metadata.diagnostics} filePath={props.input.filePath ?? ""} /> </BlockTool> </Match> <Match when={true}> @@ -2033,7 +2085,7 @@ function ApplyPatch(props: ToolProps<typeof ApplyPatchTool>) { const files = createMemo(() => props.metadata.files ?? []) const view = createMemo(() => { - const diffStyle = ctx.sync.data.config.tui?.diff_style + const diffStyle = ctx.tui.diff_style if (diffStyle === "stacked") return "unified" return ctx.width > 120 ? "split" : "unified" }) @@ -2086,6 +2138,7 @@ function ApplyPatch(props: ToolProps<typeof ApplyPatchTool>) { } > <Diff diff={file.diff} filePath={file.filePath} /> + <Diagnostics diagnostics={props.metadata.diagnostics} filePath={file.movePath ?? file.filePath} /> </Show> </BlockTool> )} @@ -2163,12 +2216,41 @@ function Skill(props: ToolProps<typeof SkillTool>) { ) } +function Diagnostics(props: { diagnostics?: Record<string, Record<string, any>[]>; filePath: string }) { + const { theme } = useTheme() + const errors = createMemo(() => { + const normalized = Filesystem.normalizePath(props.filePath) + const arr = props.diagnostics?.[normalized] ?? [] + return arr.filter((x) => x.severity === 1).slice(0, 3) + }) + + return ( + <Show when={errors().length}> + <box> + <For each={errors()}> + {(diagnostic) => ( + <text fg={theme.error}> + Error [{diagnostic.range.start.line + 1}:{diagnostic.range.start.character + 1}] {diagnostic.message} + </text> + )} + </For> + </box> + </Show> + ) +} + function normalizePath(input?: string) { if (!input) return "" - if (path.isAbsolute(input)) { - return path.relative(process.cwd(), input) || "." - } - return input + + const cwd = process.cwd() + const absolute = path.isAbsolute(input) ? input : path.resolve(cwd, input) + const relative = path.relative(cwd, absolute) + + if (!relative) return "." + if (!relative.startsWith("..")) return relative + + // outside cwd - use absolute + return absolute } function input(input: Record<string, any>, omit?: string[]): string { diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/permission.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/permission.tsx index 389fc2418c..a50cd96fc8 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/permission.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/permission.tsx @@ -15,6 +15,7 @@ import { Keybind } from "@/util/keybind" import { Locale } from "@/util/locale" import { Global } from "@/global" import { useDialog } from "../../ui/dialog" +import { useTuiConfig } from "../../context/tui-config" type PermissionStage = "permission" | "always" | "reject" @@ -48,14 +49,14 @@ function EditBody(props: { request: PermissionRequest }) { const themeState = useTheme() const theme = themeState.theme const syntax = themeState.syntax - const sync = useSync() + const config = useTuiConfig() const dimensions = useTerminalDimensions() const filepath = createMemo(() => (props.request.metadata?.filepath as string) ?? "") const diff = createMemo(() => (props.request.metadata?.diff as string) ?? "") const view = createMemo(() => { - const diffStyle = sync.data.config.tui?.diff_style + const diffStyle = config.diff_style if (diffStyle === "stacked") return "unified" return dimensions().width > 120 ? "split" : "unified" }) diff --git a/packages/opencode/src/cli/cmd/tui/thread.ts b/packages/opencode/src/cli/cmd/tui/thread.ts index 50f63c3dfb..6e787c7afd 100644 --- a/packages/opencode/src/cli/cmd/tui/thread.ts +++ b/packages/opencode/src/cli/cmd/tui/thread.ts @@ -5,13 +5,15 @@ import { type rpc } from "./worker" import path from "path" import { fileURLToPath } from "url" import { UI } from "@/cli/ui" -import { iife } from "@/util/iife" import { Log } from "@/util/log" +import { withTimeout } from "@/util/timeout" import { withNetworkOptions, resolveNetworkOptions } from "@/cli/network" import { Filesystem } from "@/util/filesystem" import type { Event } from "@opencode-ai/sdk/v2" import type { EventSource } from "./context/sdk" import { win32DisableProcessedInput, win32InstallCtrlCGuard } from "./win32" +import { TuiConfig } from "@/config/tui" +import { Instance } from "@/project/instance" declare global { const OPENCODE_WORKER_PATH: string @@ -40,9 +42,26 @@ function createWorkerFetch(client: RpcClient): typeof fetch { function createEventSource(client: RpcClient): EventSource { return { on: (handler) => client.on<Event>("event", handler), + setWorkspace: (workspaceID) => { + void client.call("setWorkspace", { workspaceID }) + }, } } +async function target() { + if (typeof OPENCODE_WORKER_PATH !== "undefined") return OPENCODE_WORKER_PATH + const dist = new URL("./cli/cmd/tui/worker.js", import.meta.url) + if (await Filesystem.exists(fileURLToPath(dist))) return dist + return new URL("./worker.ts", import.meta.url) +} + +async function input(value?: string) { + const piped = process.stdin.isTTY ? undefined : await Bun.stdin.text() + if (!value) return piped + if (!piped) return value + return piped + "\n" + value +} + export const TuiThreadCommand = cmd({ command: "$0 [project]", describe: "start opencode tui", @@ -94,24 +113,22 @@ export const TuiThreadCommand = cmd({ return } - // Resolve relative paths against PWD to preserve behavior when using --cwd flag - const baseCwd = process.env.PWD ?? process.cwd() - const cwd = args.project ? path.resolve(baseCwd, args.project) : process.cwd() - const localWorker = new URL("./worker.ts", import.meta.url) - const distWorker = new URL("./cli/cmd/tui/worker.js", import.meta.url) - const workerPath = await iife(async () => { - if (typeof OPENCODE_WORKER_PATH !== "undefined") return OPENCODE_WORKER_PATH - if (await Filesystem.exists(fileURLToPath(distWorker))) return distWorker - return localWorker - }) + // Resolve relative --project paths from PWD, then use the real cwd after + // chdir so the thread and worker share the same directory key. + const root = Filesystem.resolve(process.env.PWD ?? process.cwd()) + const next = args.project + ? Filesystem.resolve(path.isAbsolute(args.project) ? args.project : path.join(root, args.project)) + : Filesystem.resolve(process.cwd()) + const file = await target() try { - process.chdir(cwd) - } catch (e) { - UI.error("Failed to change directory to " + cwd) + process.chdir(next) + } catch { + UI.error("Failed to change directory to " + next) return } + const cwd = Filesystem.resolve(process.cwd()) - const worker = new Worker(workerPath, { + const worker = new Worker(file, { env: Object.fromEntries( Object.entries(process.env).filter((entry): entry is [string, string] => entry[1] !== undefined), ), @@ -119,70 +136,87 @@ export const TuiThreadCommand = cmd({ worker.onerror = (e) => { Log.Default.error(e) } + const client = Rpc.client<typeof rpc>(worker) - process.on("uncaughtException", (e) => { + const error = (e: unknown) => { Log.Default.error(e) - }) - process.on("unhandledRejection", (e) => { - Log.Default.error(e) - }) - process.on("SIGUSR2", async () => { - await client.call("reload", undefined) + } + const reload = () => { + client.call("reload", undefined).catch((err) => { + Log.Default.warn("worker reload failed", { + error: err instanceof Error ? err.message : String(err), + }) + }) + } + process.on("uncaughtException", error) + process.on("unhandledRejection", error) + process.on("SIGUSR2", reload) + + let stopped = false + const stop = async () => { + if (stopped) return + stopped = true + process.off("uncaughtException", error) + process.off("unhandledRejection", error) + process.off("SIGUSR2", reload) + await withTimeout(client.call("shutdown", undefined), 5000).catch((error) => { + Log.Default.warn("worker shutdown failed", { + error: error instanceof Error ? error.message : String(error), + }) + }) + worker.terminate() + } + + const prompt = await input(args.prompt) + const config = await Instance.provide({ + directory: cwd, + fn: () => TuiConfig.get(), }) - const prompt = await iife(async () => { - const piped = !process.stdin.isTTY ? await Bun.stdin.text() : undefined - if (!args.prompt) return piped - return piped ? piped + "\n" + args.prompt : args.prompt - }) - - // Check if server should be started (port or hostname explicitly set in CLI or config) - const networkOpts = await resolveNetworkOptions(args) - const shouldStartServer = + const network = await resolveNetworkOptions(args) + const external = process.argv.includes("--port") || process.argv.includes("--hostname") || process.argv.includes("--mdns") || - networkOpts.mdns || - networkOpts.port !== 0 || - networkOpts.hostname !== "127.0.0.1" + network.mdns || + network.port !== 0 || + network.hostname !== "127.0.0.1" - let url: string - let customFetch: typeof fetch | undefined - let events: EventSource | undefined - - if (shouldStartServer) { - // Start HTTP server for external access - const server = await client.call("server", networkOpts) - url = server.url - } else { - // Use direct RPC communication (no HTTP) - url = "http://opencode.internal" - customFetch = createWorkerFetch(client) - events = createEventSource(client) - } - - const tuiPromise = tui({ - url, - fetch: customFetch, - events, - args: { - continue: args.continue, - sessionID: args.session, - agent: args.agent, - model: args.model, - prompt, - fork: args.fork, - }, - onExit: async () => { - await client.call("shutdown", undefined) - }, - }) + const transport = external + ? { + url: (await client.call("server", network)).url, + fetch: undefined, + events: undefined, + } + : { + url: "http://opencode.internal", + fetch: createWorkerFetch(client), + events: createEventSource(client), + } setTimeout(() => { client.call("checkUpgrade", { directory: cwd }).catch(() => {}) - }, 1000) + }, 1000).unref?.() - await tuiPromise + try { + await tui({ + url: transport.url, + config, + directory: cwd, + fetch: transport.fetch, + events: transport.events, + args: { + continue: args.continue, + sessionID: args.session, + agent: args.agent, + model: args.model, + prompt, + fork: args.fork, + }, + }) + } finally { + await stop() + } } finally { unguard?.() } diff --git a/packages/opencode/src/cli/cmd/tui/ui/dialog-export-options.tsx b/packages/opencode/src/cli/cmd/tui/ui/dialog-export-options.tsx index 1e8d09bb0b..d29fe05ee9 100644 --- a/packages/opencode/src/cli/cmd/tui/ui/dialog-export-options.tsx +++ b/packages/opencode/src/cli/cmd/tui/ui/dialog-export-options.tsx @@ -56,7 +56,7 @@ export function DialogExportOptions(props: DialogExportOptionsProps) { setStore("active", order[nextIndex]) evt.preventDefault() } - if (evt.name === "space") { + if (evt.name === "space" || evt.name === " ") { if (store.active === "thinking") setStore("thinking", !store.thinking) if (store.active === "toolDetails") setStore("toolDetails", !store.toolDetails) if (store.active === "assistantMetadata") setStore("assistantMetadata", !store.assistantMetadata) diff --git a/packages/opencode/src/cli/cmd/tui/util/clipboard.ts b/packages/opencode/src/cli/cmd/tui/util/clipboard.ts index 7d1aad3a86..85e13d3133 100644 --- a/packages/opencode/src/cli/cmd/tui/util/clipboard.ts +++ b/packages/opencode/src/cli/cmd/tui/util/clipboard.ts @@ -1,10 +1,12 @@ -import { $ } from "bun" import { platform, release } from "os" import clipboardy from "clipboardy" import { lazy } from "../../../../util/lazy.js" import { tmpdir } from "os" import path from "path" +import fs from "fs/promises" import { Filesystem } from "../../../../util/filesystem" +import { Process } from "../../../../util/process" +import { which } from "../../../../util/which" /** * Writes text to clipboard via OSC 52 escape sequence. @@ -32,23 +34,38 @@ export namespace Clipboard { if (os === "darwin") { const tmpfile = path.join(tmpdir(), "opencode-clipboard.png") try { - await $`osascript -e 'set imageData to the clipboard as "PNGf"' -e 'set fileRef to open for access POSIX file "${tmpfile}" with write permission' -e 'set eof fileRef to 0' -e 'write imageData to fileRef' -e 'close access fileRef'` - .nothrow() - .quiet() + await Process.run( + [ + "osascript", + "-e", + 'set imageData to the clipboard as "PNGf"', + "-e", + `set fileRef to open for access POSIX file "${tmpfile}" with write permission`, + "-e", + "set eof fileRef to 0", + "-e", + "write imageData to fileRef", + "-e", + "close access fileRef", + ], + { nothrow: true }, + ) const buffer = await Filesystem.readBytes(tmpfile) return { data: buffer.toString("base64"), mime: "image/png" } } catch { } finally { - await $`rm -f "${tmpfile}"`.nothrow().quiet() + await fs.rm(tmpfile, { force: true }).catch(() => {}) } } if (os === "win32" || release().includes("WSL")) { const script = "Add-Type -AssemblyName System.Windows.Forms; $img = [System.Windows.Forms.Clipboard]::GetImage(); if ($img) { $ms = New-Object System.IO.MemoryStream; $img.Save($ms, [System.Drawing.Imaging.ImageFormat]::Png); [System.Convert]::ToBase64String($ms.ToArray()) }" - const base64 = await $`powershell.exe -NonInteractive -NoProfile -command "${script}"`.nothrow().text() - if (base64) { - const imageBuffer = Buffer.from(base64.trim(), "base64") + const base64 = await Process.text(["powershell.exe", "-NonInteractive", "-NoProfile", "-command", script], { + nothrow: true, + }) + if (base64.text) { + const imageBuffer = Buffer.from(base64.text.trim(), "base64") if (imageBuffer.length > 0) { return { data: imageBuffer.toString("base64"), mime: "image/png" } } @@ -56,13 +73,15 @@ export namespace Clipboard { } if (os === "linux") { - const wayland = await $`wl-paste -t image/png`.nothrow().arrayBuffer() - if (wayland && wayland.byteLength > 0) { - return { data: Buffer.from(wayland).toString("base64"), mime: "image/png" } + const wayland = await Process.run(["wl-paste", "-t", "image/png"], { nothrow: true }) + if (wayland.stdout.byteLength > 0) { + return { data: Buffer.from(wayland.stdout).toString("base64"), mime: "image/png" } } - const x11 = await $`xclip -selection clipboard -t image/png -o`.nothrow().arrayBuffer() - if (x11 && x11.byteLength > 0) { - return { data: Buffer.from(x11).toString("base64"), mime: "image/png" } + const x11 = await Process.run(["xclip", "-selection", "clipboard", "-t", "image/png", "-o"], { + nothrow: true, + }) + if (x11.stdout.byteLength > 0) { + return { data: Buffer.from(x11.stdout).toString("base64"), mime: "image/png" } } } @@ -75,45 +94,48 @@ export namespace Clipboard { const getCopyMethod = lazy(() => { const os = platform() - if (os === "darwin" && Bun.which("osascript")) { + if (os === "darwin" && which("osascript")) { console.log("clipboard: using osascript") return async (text: string) => { const escaped = text.replace(/\\/g, "\\\\").replace(/"/g, '\\"') - await $`osascript -e 'set the clipboard to "${escaped}"'`.nothrow().quiet() + await Process.run(["osascript", "-e", `set the clipboard to "${escaped}"`], { nothrow: true }) } } if (os === "linux") { - if (process.env["WAYLAND_DISPLAY"] && Bun.which("wl-copy")) { + if (process.env["WAYLAND_DISPLAY"] && which("wl-copy")) { console.log("clipboard: using wl-copy") return async (text: string) => { - const proc = Bun.spawn(["wl-copy"], { stdin: "pipe", stdout: "ignore", stderr: "ignore" }) + const proc = Process.spawn(["wl-copy"], { stdin: "pipe", stdout: "ignore", stderr: "ignore" }) + if (!proc.stdin) return proc.stdin.write(text) proc.stdin.end() await proc.exited.catch(() => {}) } } - if (Bun.which("xclip")) { + if (which("xclip")) { console.log("clipboard: using xclip") return async (text: string) => { - const proc = Bun.spawn(["xclip", "-selection", "clipboard"], { + const proc = Process.spawn(["xclip", "-selection", "clipboard"], { stdin: "pipe", stdout: "ignore", stderr: "ignore", }) + if (!proc.stdin) return proc.stdin.write(text) proc.stdin.end() await proc.exited.catch(() => {}) } } - if (Bun.which("xsel")) { + if (which("xsel")) { console.log("clipboard: using xsel") return async (text: string) => { - const proc = Bun.spawn(["xsel", "--clipboard", "--input"], { + const proc = Process.spawn(["xsel", "--clipboard", "--input"], { stdin: "pipe", stdout: "ignore", stderr: "ignore", }) + if (!proc.stdin) return proc.stdin.write(text) proc.stdin.end() await proc.exited.catch(() => {}) @@ -125,7 +147,7 @@ export namespace Clipboard { console.log("clipboard: using powershell") return async (text: string) => { // Pipe via stdin to avoid PowerShell string interpolation ($env:FOO, $(), etc.) - const proc = Bun.spawn( + const proc = Process.spawn( [ "powershell.exe", "-NonInteractive", @@ -140,6 +162,7 @@ export namespace Clipboard { }, ) + if (!proc.stdin) return proc.stdin.write(text) proc.stdin.end() await proc.exited.catch(() => {}) diff --git a/packages/opencode/src/cli/cmd/tui/util/editor.ts b/packages/opencode/src/cli/cmd/tui/util/editor.ts index cb7c691bbd..6d32c63c00 100644 --- a/packages/opencode/src/cli/cmd/tui/util/editor.ts +++ b/packages/opencode/src/cli/cmd/tui/util/editor.ts @@ -4,6 +4,7 @@ import { tmpdir } from "node:os" import { join } from "node:path" import { CliRenderer } from "@opentui/core" import { Filesystem } from "@/util/filesystem" +import { Process } from "@/util/process" export namespace Editor { export async function open(opts: { value: string; renderer: CliRenderer }): Promise<string | undefined> { @@ -17,8 +18,7 @@ export namespace Editor { opts.renderer.suspend() opts.renderer.currentRenderBuffer.clear() const parts = editor.split(" ") - const proc = Bun.spawn({ - cmd: [...parts, filepath], + const proc = Process.spawn([...parts, filepath], { stdin: "inherit", stdout: "inherit", stderr: "inherit", diff --git a/packages/opencode/src/cli/cmd/tui/worker.ts b/packages/opencode/src/cli/cmd/tui/worker.ts index bb5495c481..408350c520 100644 --- a/packages/opencode/src/cli/cmd/tui/worker.ts +++ b/packages/opencode/src/cli/cmd/tui/worker.ts @@ -10,6 +10,7 @@ import { GlobalBus } from "@/bus/global" import { createOpencodeClient, type Event } from "@opencode-ai/sdk/v2" import type { BunWebSocketData } from "hono/bun" import { Flag } from "@/flag/flag" +import { setTimeout as sleep } from "node:timers/promises" await Log.init({ print: process.argv.includes("--print-logs"), @@ -43,7 +44,7 @@ const eventStream = { abort: undefined as AbortController | undefined, } -const startEventStream = (directory: string) => { +const startEventStream = (input: { directory: string; workspaceID?: string }) => { if (eventStream.abort) eventStream.abort.abort() const abort = new AbortController() eventStream.abort = abort @@ -53,12 +54,13 @@ const startEventStream = (directory: string) => { const request = new Request(input, init) const auth = getAuthorizationHeader() if (auth) request.headers.set("Authorization", auth) - return Server.App().fetch(request) + return Server.Default().fetch(request) }) as typeof globalThis.fetch const sdk = createOpencodeClient({ baseUrl: "http://opencode.internal", - directory, + directory: input.directory, + experimental_workspaceID: input.workspaceID, fetch: fetchFn, signal, }) @@ -75,7 +77,7 @@ const startEventStream = (directory: string) => { ).catch(() => undefined) if (!events) { - await Bun.sleep(250) + await sleep(250) continue } @@ -84,7 +86,7 @@ const startEventStream = (directory: string) => { } if (!signal.aborted) { - await Bun.sleep(250) + await sleep(250) } } })().catch((error) => { @@ -94,7 +96,7 @@ const startEventStream = (directory: string) => { }) } -startEventStream(process.cwd()) +startEventStream({ directory: process.cwd() }) export const rpc = { async fetch(input: { url: string; method: string; headers: Record<string, string>; body?: string }) { @@ -108,7 +110,7 @@ export const rpc = { headers, body: input.body, }) - const response = await Server.App().fetch(request) + const response = await Server.Default().fetch(request) const body = await response.text() return { status: response.status, @@ -134,15 +136,13 @@ export const rpc = { Config.global.reset() await Instance.disposeAll() }, + async setWorkspace(input: { workspaceID?: string }) { + startEventStream({ directory: process.cwd(), workspaceID: input.workspaceID }) + }, async shutdown() { Log.Default.info("worker shutting down") if (eventStream.abort) eventStream.abort.abort() - await Promise.race([ - Instance.disposeAll(), - new Promise((resolve) => { - setTimeout(resolve, 5000) - }), - ]) + await Instance.disposeAll() if (server) server.stop(true) }, } diff --git a/packages/opencode/src/cli/cmd/uninstall.ts b/packages/opencode/src/cli/cmd/uninstall.ts index 3d8e7e3f75..de41f32a0d 100644 --- a/packages/opencode/src/cli/cmd/uninstall.ts +++ b/packages/opencode/src/cli/cmd/uninstall.ts @@ -3,11 +3,11 @@ import { UI } from "../ui" import * as prompts from "@clack/prompts" import { Installation } from "../../installation" import { Global } from "../../global" -import { $ } from "bun" import fs from "fs/promises" import path from "path" import os from "os" import { Filesystem } from "../../util/filesystem" +import { Process } from "../../util/process" interface UninstallArgs { keepConfig: boolean @@ -192,16 +192,13 @@ async function executeUninstall(method: Installation.Method, targets: RemovalTar const cmd = cmds[method] if (cmd) { spinner.start(`Running ${cmd.join(" ")}...`) - const result = - method === "choco" - ? await $`echo Y | choco uninstall opencode -y -r`.quiet().nothrow() - : await $`${cmd}`.quiet().nothrow() - if (result.exitCode !== 0) { - spinner.stop(`Package manager uninstall failed: exit code ${result.exitCode}`, 1) - if ( - method === "choco" && - result.stdout.toString("utf8").includes("not running from an elevated command shell") - ) { + const result = await Process.run(method === "choco" ? ["choco", "uninstall", "opencode", "-y", "-r"] : cmd, { + nothrow: true, + }) + if (result.code !== 0) { + spinner.stop(`Package manager uninstall failed: exit code ${result.code}`, 1) + const text = `${result.stdout.toString("utf8")}\n${result.stderr.toString("utf8")}` + if (method === "choco" && text.includes("not running from an elevated command shell")) { prompts.log.warn(`You may need to run '${cmd.join(" ")}' from an elevated command shell`) } else { prompts.log.warn(`You may need to run manually: ${cmd.join(" ")}`) diff --git a/packages/opencode/src/cli/cmd/workspace-serve.ts b/packages/opencode/src/cli/cmd/workspace-serve.ts new file mode 100644 index 0000000000..cb5c304e4b --- /dev/null +++ b/packages/opencode/src/cli/cmd/workspace-serve.ts @@ -0,0 +1,16 @@ +import { cmd } from "./cmd" +import { withNetworkOptions, resolveNetworkOptions } from "../network" +import { WorkspaceServer } from "../../control-plane/workspace-server/server" + +export const WorkspaceServeCommand = cmd({ + command: "workspace-serve", + builder: (yargs) => withNetworkOptions(yargs), + describe: "starts a remote workspace event server", + handler: async (args) => { + const opts = await resolveNetworkOptions(args) + const server = WorkspaceServer.Listen(opts) + console.log(`workspace event server listening on http://${server.hostname}:${server.port}/event`) + await new Promise(() => {}) + await server.stop() + }, +}) diff --git a/packages/opencode/src/cli/ui.ts b/packages/opencode/src/cli/ui.ts index f242a77f6c..39396997c6 100644 --- a/packages/opencode/src/cli/ui.ts +++ b/packages/opencode/src/cli/ui.ts @@ -25,12 +25,12 @@ export namespace UI { export function println(...message: string[]) { print(...message) - Bun.stderr.write(EOL) + process.stderr.write(EOL) } export function print(...message: string[]) { blank = false - Bun.stderr.write(message.join(" ")) + process.stderr.write(message.join(" ")) } let blank = false @@ -44,7 +44,7 @@ export namespace UI { const result: string[] = [] const reset = "\x1b[0m" const left = { - fg: Bun.color("gray", "ansi") ?? "", + fg: "\x1b[90m", shadow: "\x1b[38;5;235m", bg: "\x1b[48;5;235m", } diff --git a/packages/opencode/src/config/config.ts b/packages/opencode/src/config/config.ts index aad0fd76c4..6b4242a225 100644 --- a/packages/opencode/src/config/config.ts +++ b/packages/opencode/src/config/config.ts @@ -1,9 +1,9 @@ import { Log } from "../util/log" import path from "path" -import { pathToFileURL } from "url" +import { pathToFileURL, fileURLToPath } from "url" +import { createRequire } from "module" import os from "os" import z from "zod" -import { Filesystem } from "../util/filesystem" import { ModelsDev } from "../provider/models" import { mergeDeep, pipe, unique } from "remeda" import { Global } from "../global" @@ -33,6 +33,8 @@ import { PackageRegistry } from "@/bun/registry" import { proxied } from "@/util/proxied" import { iife } from "@/util/iife" import { Control } from "@/control" +import { ConfigPaths } from "./paths" +import { Filesystem } from "@/util/filesystem" export namespace Config { const ModelId = z.string().meta({ $ref: "https://models.dev/model-schema.json#/$defs/Model" }) @@ -41,7 +43,7 @@ export namespace Config { // Managed settings directory for enterprise deployments (highest priority, admin-controlled) // These settings override all user and project settings - function getManagedConfigDir(): string { + function systemManagedConfigDir(): string { switch (process.platform) { case "darwin": return "/Library/Application Support/opencode" @@ -52,10 +54,14 @@ export namespace Config { } } - const managedConfigDir = process.env.OPENCODE_TEST_MANAGED_CONFIG_DIR || getManagedConfigDir() + export function managedConfigDir() { + return process.env.OPENCODE_TEST_MANAGED_CONFIG_DIR || systemManagedConfigDir() + } + + const managedDir = managedConfigDir() // Custom merge function that concatenates array fields instead of replacing them - function merge(target: Info, source: Info): Info { + function mergeConfigConcatArrays(target: Info, source: Info): Info { const merged = mergeDeep(target, source) if (target.plugin && source.plugin) { merged.plugin = Array.from(new Set([...target.plugin, ...source.plugin])) @@ -80,24 +86,25 @@ export namespace Config { let result: Info = {} for (const [key, value] of Object.entries(auth)) { if (value.type === "wellknown") { + const url = key.replace(/\/+$/, "") process.env[value.key] = value.token - log.debug("fetching remote config", { url: `${key}/.well-known/opencode` }) - const response = await fetch(`${key}/.well-known/opencode`) + log.debug("fetching remote config", { url: `${url}/.well-known/opencode` }) + const response = await fetch(`${url}/.well-known/opencode`) if (!response.ok) { - throw new Error(`failed to fetch remote config from ${key}: ${response.status}`) + throw new Error(`failed to fetch remote config from ${url}: ${response.status}`) } const wellknown = (await response.json()) as any const remoteConfig = wellknown.config ?? {} // Add $schema to prevent load() from trying to write back to a non-existent file if (!remoteConfig.$schema) remoteConfig.$schema = "https://opencode.ai/config.json" - result = merge( + result = mergeConfigConcatArrays( result, await load(JSON.stringify(remoteConfig), { - dir: path.dirname(`${key}/.well-known/opencode`), - source: `${key}/.well-known/opencode`, + dir: path.dirname(`${url}/.well-known/opencode`), + source: `${url}/.well-known/opencode`, }), ) - log.debug("loaded remote config from well-known", { url: key }) + log.debug("loaded remote config from well-known", { url }) } } @@ -106,21 +113,18 @@ export namespace Config { } // Global user config overrides remote config. - result = merge(result, await global()) + result = mergeConfigConcatArrays(result, await global()) // Custom config path overrides global config. if (Flag.OPENCODE_CONFIG) { - result = merge(result, await loadFile(Flag.OPENCODE_CONFIG)) + result = mergeConfigConcatArrays(result, await loadFile(Flag.OPENCODE_CONFIG)) log.debug("loaded custom config", { path: Flag.OPENCODE_CONFIG }) } // Project config overrides global and remote config. if (!Flag.OPENCODE_DISABLE_PROJECT_CONFIG) { - for (const file of ["opencode.jsonc", "opencode.json"]) { - const found = await Filesystem.findUp(file, Instance.directory, Instance.worktree) - for (const resolved of found.toReversed()) { - result = merge(result, await loadFile(resolved)) - } + for (const file of await ConfigPaths.projectFiles("opencode", Instance.directory, Instance.worktree)) { + result = mergeConfigConcatArrays(result, await loadFile(file)) } } @@ -128,31 +132,10 @@ export namespace Config { result.mode = result.mode || {} result.plugin = result.plugin || [] - const directories = [ - Global.Path.config, - // Only scan project .opencode/ directories when project discovery is enabled - ...(!Flag.OPENCODE_DISABLE_PROJECT_CONFIG - ? await Array.fromAsync( - Filesystem.up({ - targets: [".opencode"], - start: Instance.directory, - stop: Instance.worktree, - }), - ) - : []), - // Always scan ~/.opencode/ (user home directory) - ...(await Array.fromAsync( - Filesystem.up({ - targets: [".opencode"], - start: Global.Path.home, - stop: Global.Path.home, - }), - )), - ] + const directories = await ConfigPaths.directories(Instance.directory, Instance.worktree) // .opencode directory config overrides (project and global) config sources. if (Flag.OPENCODE_CONFIG_DIR) { - directories.push(Flag.OPENCODE_CONFIG_DIR) log.debug("loading config from OPENCODE_CONFIG_DIR", { path: Flag.OPENCODE_CONFIG_DIR }) } @@ -162,7 +145,7 @@ export namespace Config { if (dir.endsWith(".opencode") || dir === Flag.OPENCODE_CONFIG_DIR) { for (const file of ["opencode.jsonc", "opencode.json"]) { log.debug(`loading config from ${path.join(dir, file)}`) - result = merge(result, await loadFile(path.join(dir, file))) + result = mergeConfigConcatArrays(result, await loadFile(path.join(dir, file))) // to satisfy the type checker result.agent ??= {} result.mode ??= {} @@ -185,7 +168,7 @@ export namespace Config { // Inline config content overrides all non-managed config sources. if (process.env.OPENCODE_CONFIG_CONTENT) { - result = merge( + result = mergeConfigConcatArrays( result, await load(process.env.OPENCODE_CONFIG_CONTENT, { dir: Instance.directory, @@ -199,9 +182,9 @@ export namespace Config { // Kept separate from directories array to avoid write operations when installing plugins // which would fail on system directories requiring elevated permissions // This way it only loads config file and not skills/plugins/commands - if (existsSync(managedConfigDir)) { + if (existsSync(managedDir)) { for (const file of ["opencode.jsonc", "opencode.json"]) { - result = merge(result, await loadFile(path.join(managedConfigDir, file))) + result = mergeConfigConcatArrays(result, await loadFile(path.join(managedDir, file))) } } @@ -240,8 +223,6 @@ export namespace Config { result.share = "auto" } - if (!result.keybinds) result.keybinds = Info.shape.keybinds.parse({}) - // Apply flag overrides for compaction settings if (Flag.OPENCODE_DISABLE_AUTOCOMPACT) { result.compaction = { ...result.compaction, auto: false } @@ -276,7 +257,6 @@ export namespace Config { "@opencode-ai/plugin": targetVersion, } await Filesystem.writeJson(pkg, json) - await new Promise((resolve) => setTimeout(resolve, 3000)) const gitignore = path.join(dir, ".gitignore") const hasGitIgnore = await Filesystem.exists(gitignore) @@ -289,7 +269,7 @@ export namespace Config { [ "install", // TODO: get rid of this case (see: https://github.com/oven-sh/bun/issues/19936) - ...(proxied() ? ["--no-cache"] : []), + ...(proxied() || process.env.CI ? ["--no-cache"] : []), ], { cwd: dir }, ).catch((err) => { @@ -306,7 +286,7 @@ export namespace Config { } } - async function needsInstall(dir: string) { + export async function needsInstall(dir: string) { // Some config dirs may be read-only. // Installing deps there will fail; skip installation in that case. const writable = await isWritable(dir) @@ -342,10 +322,11 @@ export namespace Config { } function rel(item: string, patterns: string[]) { + const normalizedItem = item.replaceAll("\\", "/") for (const pattern of patterns) { - const index = item.indexOf(pattern) + const index = normalizedItem.indexOf(pattern) if (index === -1) continue - return item.slice(index + pattern.length) + return normalizedItem.slice(index + pattern.length) } } @@ -916,9 +897,10 @@ export namespace Config { .describe("Delete word backward in input"), history_previous: z.string().optional().default("up").describe("Previous history item"), history_next: z.string().optional().default("down").describe("Next history item"), - session_child_cycle: z.string().optional().default("<leader>right").describe("Next child session"), - session_child_cycle_reverse: z.string().optional().default("<leader>left").describe("Previous child session"), - session_parent: z.string().optional().default("<leader>up").describe("Go to parent session"), + session_child_first: z.string().optional().default("<leader>down").describe("Go to first child session"), + session_child_cycle: z.string().optional().default("right").describe("Go to next child session"), + session_child_cycle_reverse: z.string().optional().default("left").describe("Go to previous child session"), + session_parent: z.string().optional().default("up").describe("Go to parent session"), terminal_suspend: z.string().optional().default("ctrl+z").describe("Suspend terminal"), terminal_title_toggle: z.string().optional().default("none").describe("Toggle terminal title"), tips_toggle: z.string().optional().default("<leader>h").describe("Toggle tips on home screen"), @@ -929,20 +911,6 @@ export namespace Config { ref: "KeybindsConfig", }) - export const TUI = z.object({ - scroll_speed: z.number().min(0.001).optional().describe("TUI scroll speed"), - scroll_acceleration: z - .object({ - enabled: z.boolean().describe("Enable scroll acceleration"), - }) - .optional() - .describe("Scroll acceleration settings"), - diff_style: z - .enum(["auto", "stacked"]) - .optional() - .describe("Control diff rendering style: 'auto' adapts to terminal width, 'stacked' always shows single column"), - }) - export const Server = z .object({ port: z.number().int().positive().optional().describe("Port to listen on"), @@ -1017,10 +985,7 @@ export namespace Config { export const Info = z .object({ $schema: z.string().optional().describe("JSON schema reference for configuration validation"), - theme: z.string().optional().describe("Theme name to use for the interface"), - keybinds: Keybinds.optional().describe("Custom keybind configurations"), logLevel: Log.Level.optional().describe("Log level"), - tui: TUI.optional().describe("TUI specific settings"), server: Server.optional().describe("Server configuration for opencode serve and web commands"), command: z .record(z.string(), Command) @@ -1240,91 +1205,42 @@ export namespace Config { return result }) + export const { readFile } = ConfigPaths + async function loadFile(filepath: string): Promise<Info> { log.info("loading", { path: filepath }) - let text = await Filesystem.readText(filepath).catch((err: any) => { - if (err.code === "ENOENT") return - throw new JsonError({ path: filepath }, { cause: err }) - }) + const text = await readFile(filepath) if (!text) return {} return load(text, { path: filepath }) } async function load(text: string, options: { path: string } | { dir: string; source: string }) { const original = text - const configDir = "path" in options ? path.dirname(options.path) : options.dir const source = "path" in options ? options.path : options.source const isFile = "path" in options + const data = await ConfigPaths.parseText( + text, + "path" in options ? options.path : { source: options.source, dir: options.dir }, + ) - text = text.replace(/\{env:([^}]+)\}/g, (_, varName) => { - return process.env[varName] || "" - }) + const normalized = (() => { + if (!data || typeof data !== "object" || Array.isArray(data)) return data + const copy = { ...(data as Record<string, unknown>) } + const hadLegacy = "theme" in copy || "keybinds" in copy || "tui" in copy + if (!hadLegacy) return copy + delete copy.theme + delete copy.keybinds + delete copy.tui + log.warn("tui keys in opencode config are deprecated; move them to tui.json", { path: source }) + return copy + })() - const fileMatches = text.match(/\{file:[^}]+\}/g) - if (fileMatches) { - const lines = text.split("\n") - - for (const match of fileMatches) { - const lineIndex = lines.findIndex((line) => line.includes(match)) - if (lineIndex !== -1 && lines[lineIndex].trim().startsWith("//")) { - continue - } - let filePath = match.replace(/^\{file:/, "").replace(/\}$/, "") - if (filePath.startsWith("~/")) { - filePath = path.join(os.homedir(), filePath.slice(2)) - } - const resolvedPath = path.isAbsolute(filePath) ? filePath : path.resolve(configDir, filePath) - const fileContent = ( - await Bun.file(resolvedPath) - .text() - .catch((error) => { - const errMsg = `bad file reference: "${match}"` - if (error.code === "ENOENT") { - throw new InvalidError( - { - path: source, - message: errMsg + ` ${resolvedPath} does not exist`, - }, - { cause: error }, - ) - } - throw new InvalidError({ path: source, message: errMsg }, { cause: error }) - }) - ).trim() - text = text.replace(match, () => JSON.stringify(fileContent).slice(1, -1)) - } - } - - const errors: JsoncParseError[] = [] - const data = parseJsonc(text, errors, { allowTrailingComma: true }) - if (errors.length) { - const lines = text.split("\n") - const errorDetails = errors - .map((e) => { - const beforeOffset = text.substring(0, e.offset).split("\n") - const line = beforeOffset.length - const column = beforeOffset[beforeOffset.length - 1].length + 1 - const problemLine = lines[line - 1] - - const error = `${printParseErrorCode(e.error)} at line ${line}, column ${column}` - if (!problemLine) return error - - return `${error}\n Line ${line}: ${problemLine}\n${"".padStart(column + 9)}^` - }) - .join("\n") - - throw new JsonError({ - path: source, - message: `\n--- JSONC Input ---\n${text}\n--- Errors ---\n${errorDetails}\n--- End ---`, - }) - } - - const parsed = Info.safeParse(data) + const parsed = Info.safeParse(normalized) if (parsed.success) { if (!parsed.data.$schema && isFile) { parsed.data.$schema = "https://opencode.ai/config.json" const updated = original.replace(/^\s*\{/, '{\n "$schema": "https://opencode.ai/config.json",') - await Bun.write(options.path, updated).catch(() => {}) + await Filesystem.write(options.path, updated).catch(() => {}) } const data = parsed.data if (data.plugin && isFile) { @@ -1332,7 +1248,16 @@ export namespace Config { const plugin = data.plugin[i] try { data.plugin[i] = import.meta.resolve!(plugin, options.path) - } catch (err) {} + } catch (e) { + try { + // import.meta.resolve sometimes fails with newly created node_modules + const require = createRequire(options.path) + const resolvedPath = require.resolve(plugin) + data.plugin[i] = pathToFileURL(resolvedPath).href + } catch { + // Ignore, plugin might be a generic string identifier like "mcp-server" + } + } } } return data @@ -1343,13 +1268,7 @@ export namespace Config { issues: parsed.error.issues, }) } - export const JsonError = NamedError.create( - "ConfigJsonError", - z.object({ - path: z.string(), - message: z.string().optional(), - }), - ) + export const { JsonError, InvalidError } = ConfigPaths export const ConfigDirectoryTypoError = NamedError.create( "ConfigDirectoryTypoError", @@ -1360,15 +1279,6 @@ export namespace Config { }), ) - export const InvalidError = NamedError.create( - "ConfigInvalidError", - z.object({ - path: z.string(), - issues: z.custom<z.core.$ZodIssue[]>().optional(), - message: z.string().optional(), - }), - ) - export async function get() { return state().then((x) => x.config) } @@ -1491,3 +1401,5 @@ export namespace Config { return state().then((x) => x.directories) } } +Filesystem.write +Filesystem.write diff --git a/packages/opencode/src/config/markdown.ts b/packages/opencode/src/config/markdown.ts index 5b4ccf0477..3c9709b5b3 100644 --- a/packages/opencode/src/config/markdown.ts +++ b/packages/opencode/src/config/markdown.ts @@ -22,7 +22,7 @@ export namespace ConfigMarkdown { if (!match) return content const frontmatter = match[1] - const lines = frontmatter.split("\n") + const lines = frontmatter.split(/\r?\n/) const result: string[] = [] for (const line of lines) { diff --git a/packages/opencode/src/config/migrate-tui-config.ts b/packages/opencode/src/config/migrate-tui-config.ts new file mode 100644 index 0000000000..dbe33ffb42 --- /dev/null +++ b/packages/opencode/src/config/migrate-tui-config.ts @@ -0,0 +1,155 @@ +import path from "path" +import { type ParseError as JsoncParseError, applyEdits, modify, parse as parseJsonc } from "jsonc-parser" +import { unique } from "remeda" +import z from "zod" +import { ConfigPaths } from "./paths" +import { TuiInfo, TuiOptions } from "./tui-schema" +import { Instance } from "@/project/instance" +import { Flag } from "@/flag/flag" +import { Log } from "@/util/log" +import { Filesystem } from "@/util/filesystem" +import { Global } from "@/global" + +const log = Log.create({ service: "tui.migrate" }) + +const TUI_SCHEMA_URL = "https://opencode.ai/tui.json" + +const LegacyTheme = TuiInfo.shape.theme.optional() +const LegacyRecord = z.record(z.string(), z.unknown()).optional() + +const TuiLegacy = z + .object({ + scroll_speed: TuiOptions.shape.scroll_speed.catch(undefined), + scroll_acceleration: TuiOptions.shape.scroll_acceleration.catch(undefined), + diff_style: TuiOptions.shape.diff_style.catch(undefined), + }) + .strip() + +interface MigrateInput { + directories: string[] + custom?: string + managed: string +} + +/** + * Migrates tui-specific keys (theme, keybinds, tui) from opencode.json files + * into dedicated tui.json files. Migration is performed per-directory and + * skips only locations where a tui.json already exists. + */ +export async function migrateTuiConfig(input: MigrateInput) { + const opencode = await opencodeFiles(input) + for (const file of opencode) { + const source = await Filesystem.readText(file).catch((error) => { + log.warn("failed to read config for tui migration", { path: file, error }) + return undefined + }) + if (!source) continue + const errors: JsoncParseError[] = [] + const data = parseJsonc(source, errors, { allowTrailingComma: true }) + if (errors.length || !data || typeof data !== "object" || Array.isArray(data)) continue + + const theme = LegacyTheme.safeParse("theme" in data ? data.theme : undefined) + const keybinds = LegacyRecord.safeParse("keybinds" in data ? data.keybinds : undefined) + const legacyTui = LegacyRecord.safeParse("tui" in data ? data.tui : undefined) + const extracted = { + theme: theme.success ? theme.data : undefined, + keybinds: keybinds.success ? keybinds.data : undefined, + tui: legacyTui.success ? legacyTui.data : undefined, + } + const tui = extracted.tui ? normalizeTui(extracted.tui) : undefined + if (extracted.theme === undefined && extracted.keybinds === undefined && !tui) continue + + const target = path.join(path.dirname(file), "tui.json") + const targetExists = await Filesystem.exists(target) + if (targetExists) continue + + const payload: Record<string, unknown> = { + $schema: TUI_SCHEMA_URL, + } + if (extracted.theme !== undefined) payload.theme = extracted.theme + if (extracted.keybinds !== undefined) payload.keybinds = extracted.keybinds + if (tui) Object.assign(payload, tui) + + const wrote = await Filesystem.write(target, JSON.stringify(payload, null, 2)) + .then(() => true) + .catch((error) => { + log.warn("failed to write tui migration target", { from: file, to: target, error }) + return false + }) + if (!wrote) continue + + const stripped = await backupAndStripLegacy(file, source) + if (!stripped) { + log.warn("tui config migrated but source file was not stripped", { from: file, to: target }) + continue + } + log.info("migrated tui config", { from: file, to: target }) + } +} + +function normalizeTui(data: Record<string, unknown>) { + const parsed = TuiLegacy.parse(data) + if ( + parsed.scroll_speed === undefined && + parsed.diff_style === undefined && + parsed.scroll_acceleration === undefined + ) { + return + } + return parsed +} + +async function backupAndStripLegacy(file: string, source: string) { + const backup = file + ".tui-migration.bak" + const hasBackup = await Filesystem.exists(backup) + const backed = hasBackup + ? true + : await Filesystem.write(backup, source) + .then(() => true) + .catch((error) => { + log.warn("failed to backup source config during tui migration", { path: file, backup, error }) + return false + }) + if (!backed) return false + + const text = ["theme", "keybinds", "tui"].reduce((acc, key) => { + const edits = modify(acc, [key], undefined, { + formattingOptions: { + insertSpaces: true, + tabSize: 2, + }, + }) + if (!edits.length) return acc + return applyEdits(acc, edits) + }, source) + + return Filesystem.write(file, text) + .then(() => { + log.info("stripped tui keys from server config", { path: file, backup }) + return true + }) + .catch((error) => { + log.warn("failed to strip legacy tui keys from server config", { path: file, backup, error }) + return false + }) +} + +async function opencodeFiles(input: { directories: string[]; managed: string }) { + const project = Flag.OPENCODE_DISABLE_PROJECT_CONFIG + ? [] + : await ConfigPaths.projectFiles("opencode", Instance.directory, Instance.worktree) + const files = [...project, ...ConfigPaths.fileInDirectory(Global.Path.config, "opencode")] + for (const dir of unique(input.directories)) { + files.push(...ConfigPaths.fileInDirectory(dir, "opencode")) + } + if (Flag.OPENCODE_CONFIG) files.push(Flag.OPENCODE_CONFIG) + files.push(...ConfigPaths.fileInDirectory(input.managed, "opencode")) + + const existing = await Promise.all( + unique(files).map(async (file) => { + const ok = await Filesystem.exists(file) + return ok ? file : undefined + }), + ) + return existing.filter((file): file is string => !!file) +} diff --git a/packages/opencode/src/config/paths.ts b/packages/opencode/src/config/paths.ts new file mode 100644 index 0000000000..396417e9a5 --- /dev/null +++ b/packages/opencode/src/config/paths.ts @@ -0,0 +1,174 @@ +import path from "path" +import os from "os" +import z from "zod" +import { type ParseError as JsoncParseError, parse as parseJsonc, printParseErrorCode } from "jsonc-parser" +import { NamedError } from "@opencode-ai/util/error" +import { Filesystem } from "@/util/filesystem" +import { Flag } from "@/flag/flag" +import { Global } from "@/global" + +export namespace ConfigPaths { + export async function projectFiles(name: string, directory: string, worktree: string) { + const files: string[] = [] + for (const file of [`${name}.jsonc`, `${name}.json`]) { + const found = await Filesystem.findUp(file, directory, worktree) + for (const resolved of found.toReversed()) { + files.push(resolved) + } + } + return files + } + + export async function directories(directory: string, worktree: string) { + return [ + Global.Path.config, + ...(!Flag.OPENCODE_DISABLE_PROJECT_CONFIG + ? await Array.fromAsync( + Filesystem.up({ + targets: [".opencode"], + start: directory, + stop: worktree, + }), + ) + : []), + ...(await Array.fromAsync( + Filesystem.up({ + targets: [".opencode"], + start: Global.Path.home, + stop: Global.Path.home, + }), + )), + ...(Flag.OPENCODE_CONFIG_DIR ? [Flag.OPENCODE_CONFIG_DIR] : []), + ] + } + + export function fileInDirectory(dir: string, name: string) { + return [path.join(dir, `${name}.jsonc`), path.join(dir, `${name}.json`)] + } + + export const JsonError = NamedError.create( + "ConfigJsonError", + z.object({ + path: z.string(), + message: z.string().optional(), + }), + ) + + export const InvalidError = NamedError.create( + "ConfigInvalidError", + z.object({ + path: z.string(), + issues: z.custom<z.core.$ZodIssue[]>().optional(), + message: z.string().optional(), + }), + ) + + /** Read a config file, returning undefined for missing files and throwing JsonError for other failures. */ + export async function readFile(filepath: string) { + return Filesystem.readText(filepath).catch((err: NodeJS.ErrnoException) => { + if (err.code === "ENOENT") return + throw new JsonError({ path: filepath }, { cause: err }) + }) + } + + type ParseSource = string | { source: string; dir: string } + + function source(input: ParseSource) { + return typeof input === "string" ? input : input.source + } + + function dir(input: ParseSource) { + return typeof input === "string" ? path.dirname(input) : input.dir + } + + /** Apply {env:VAR} and {file:path} substitutions to config text. */ + async function substitute(text: string, input: ParseSource, missing: "error" | "empty" = "error") { + text = text.replace(/\{env:([^}]+)\}/g, (_, varName) => { + return process.env[varName] || "" + }) + + const fileMatches = Array.from(text.matchAll(/\{file:[^}]+\}/g)) + if (!fileMatches.length) return text + + const configDir = dir(input) + const configSource = source(input) + let out = "" + let cursor = 0 + + for (const match of fileMatches) { + const token = match[0] + const index = match.index! + out += text.slice(cursor, index) + + const lineStart = text.lastIndexOf("\n", index - 1) + 1 + const prefix = text.slice(lineStart, index).trimStart() + if (prefix.startsWith("//")) { + out += token + cursor = index + token.length + continue + } + + let filePath = token.replace(/^\{file:/, "").replace(/\}$/, "") + if (filePath.startsWith("~/")) { + filePath = path.join(os.homedir(), filePath.slice(2)) + } + + const resolvedPath = path.isAbsolute(filePath) ? filePath : path.resolve(configDir, filePath) + const fileContent = ( + await Filesystem.readText(resolvedPath).catch((error: NodeJS.ErrnoException) => { + if (missing === "empty") return "" + + const errMsg = `bad file reference: "${token}"` + if (error.code === "ENOENT") { + throw new InvalidError( + { + path: configSource, + message: errMsg + ` ${resolvedPath} does not exist`, + }, + { cause: error }, + ) + } + throw new InvalidError({ path: configSource, message: errMsg }, { cause: error }) + }) + ).trim() + + out += JSON.stringify(fileContent).slice(1, -1) + cursor = index + token.length + } + + out += text.slice(cursor) + return out + } + + /** Substitute and parse JSONC text, throwing JsonError on syntax errors. */ + export async function parseText(text: string, input: ParseSource, missing: "error" | "empty" = "error") { + const configSource = source(input) + text = await substitute(text, input, missing) + + const errors: JsoncParseError[] = [] + const data = parseJsonc(text, errors, { allowTrailingComma: true }) + if (errors.length) { + const lines = text.split("\n") + const errorDetails = errors + .map((e) => { + const beforeOffset = text.substring(0, e.offset).split("\n") + const line = beforeOffset.length + const column = beforeOffset[beforeOffset.length - 1].length + 1 + const problemLine = lines[line - 1] + + const error = `${printParseErrorCode(e.error)} at line ${line}, column ${column}` + if (!problemLine) return error + + return `${error}\n Line ${line}: ${problemLine}\n${"".padStart(column + 9)}^` + }) + .join("\n") + + throw new JsonError({ + path: configSource, + message: `\n--- JSONC Input ---\n${text}\n--- Errors ---\n${errorDetails}\n--- End ---`, + }) + } + + return data + } +} diff --git a/packages/opencode/src/config/tui-schema.ts b/packages/opencode/src/config/tui-schema.ts new file mode 100644 index 0000000000..f9068e3f01 --- /dev/null +++ b/packages/opencode/src/config/tui-schema.ts @@ -0,0 +1,34 @@ +import z from "zod" +import { Config } from "./config" + +const KeybindOverride = z + .object( + Object.fromEntries(Object.keys(Config.Keybinds.shape).map((key) => [key, z.string().optional()])) as Record< + string, + z.ZodOptional<z.ZodString> + >, + ) + .strict() + +export const TuiOptions = z.object({ + scroll_speed: z.number().min(0.001).optional().describe("TUI scroll speed"), + scroll_acceleration: z + .object({ + enabled: z.boolean().describe("Enable scroll acceleration"), + }) + .optional() + .describe("Scroll acceleration settings"), + diff_style: z + .enum(["auto", "stacked"]) + .optional() + .describe("Control diff rendering style: 'auto' adapts to terminal width, 'stacked' always shows single column"), +}) + +export const TuiInfo = z + .object({ + $schema: z.string().optional(), + theme: z.string().optional(), + keybinds: KeybindOverride.optional(), + }) + .extend(TuiOptions.shape) + .strict() diff --git a/packages/opencode/src/config/tui.ts b/packages/opencode/src/config/tui.ts new file mode 100644 index 0000000000..f0964f63b3 --- /dev/null +++ b/packages/opencode/src/config/tui.ts @@ -0,0 +1,118 @@ +import { existsSync } from "fs" +import z from "zod" +import { mergeDeep, unique } from "remeda" +import { Config } from "./config" +import { ConfigPaths } from "./paths" +import { migrateTuiConfig } from "./migrate-tui-config" +import { TuiInfo } from "./tui-schema" +import { Instance } from "@/project/instance" +import { Flag } from "@/flag/flag" +import { Log } from "@/util/log" +import { Global } from "@/global" + +export namespace TuiConfig { + const log = Log.create({ service: "tui.config" }) + + export const Info = TuiInfo + + export type Info = z.output<typeof Info> + + function mergeInfo(target: Info, source: Info): Info { + return mergeDeep(target, source) + } + + function customPath() { + return Flag.OPENCODE_TUI_CONFIG + } + + const state = Instance.state(async () => { + let projectFiles = Flag.OPENCODE_DISABLE_PROJECT_CONFIG + ? [] + : await ConfigPaths.projectFiles("tui", Instance.directory, Instance.worktree) + const directories = await ConfigPaths.directories(Instance.directory, Instance.worktree) + const custom = customPath() + const managed = Config.managedConfigDir() + await migrateTuiConfig({ directories, custom, managed }) + // Re-compute after migration since migrateTuiConfig may have created new tui.json files + projectFiles = Flag.OPENCODE_DISABLE_PROJECT_CONFIG + ? [] + : await ConfigPaths.projectFiles("tui", Instance.directory, Instance.worktree) + + let result: Info = {} + + for (const file of ConfigPaths.fileInDirectory(Global.Path.config, "tui")) { + result = mergeInfo(result, await loadFile(file)) + } + + if (custom) { + result = mergeInfo(result, await loadFile(custom)) + log.debug("loaded custom tui config", { path: custom }) + } + + for (const file of projectFiles) { + result = mergeInfo(result, await loadFile(file)) + } + + for (const dir of unique(directories)) { + if (!dir.endsWith(".opencode") && dir !== Flag.OPENCODE_CONFIG_DIR) continue + for (const file of ConfigPaths.fileInDirectory(dir, "tui")) { + result = mergeInfo(result, await loadFile(file)) + } + } + + if (existsSync(managed)) { + for (const file of ConfigPaths.fileInDirectory(managed, "tui")) { + result = mergeInfo(result, await loadFile(file)) + } + } + + result.keybinds = Config.Keybinds.parse(result.keybinds ?? {}) + + return { + config: result, + } + }) + + export async function get() { + return state().then((x) => x.config) + } + + async function loadFile(filepath: string): Promise<Info> { + const text = await ConfigPaths.readFile(filepath) + if (!text) return {} + return load(text, filepath).catch((error) => { + log.warn("failed to load tui config", { path: filepath, error }) + return {} + }) + } + + async function load(text: string, configFilepath: string): Promise<Info> { + const data = await ConfigPaths.parseText(text, configFilepath, "empty") + if (!data || typeof data !== "object" || Array.isArray(data)) return {} + + // Flatten a nested "tui" key so users who wrote `{ "tui": { ... } }` inside tui.json + // (mirroring the old opencode.json shape) still get their settings applied. + const normalized = (() => { + const copy = { ...(data as Record<string, unknown>) } + if (!("tui" in copy)) return copy + if (!copy.tui || typeof copy.tui !== "object" || Array.isArray(copy.tui)) { + delete copy.tui + return copy + } + const tui = copy.tui as Record<string, unknown> + delete copy.tui + return { + ...tui, + ...copy, + } + })() + + const parsed = Info.safeParse(normalized) + if (!parsed.success) { + log.warn("invalid tui config", { path: configFilepath, issues: parsed.error.issues }) + return {} + } + + return parsed.data + } +} diff --git a/packages/opencode/src/control-plane/adaptors/index.ts b/packages/opencode/src/control-plane/adaptors/index.ts new file mode 100644 index 0000000000..a43fce2486 --- /dev/null +++ b/packages/opencode/src/control-plane/adaptors/index.ts @@ -0,0 +1,20 @@ +import { lazy } from "@/util/lazy" +import type { Adaptor } from "../types" + +const ADAPTORS: Record<string, () => Promise<Adaptor>> = { + worktree: lazy(async () => (await import("./worktree")).WorktreeAdaptor), +} + +export function getAdaptor(type: string): Promise<Adaptor> { + return ADAPTORS[type]() +} + +export function installAdaptor(type: string, adaptor: Adaptor) { + // This is experimental: mostly used for testing right now, but we + // will likely allow this in the future. Need to figure out the + // TypeScript story + + // @ts-expect-error we force the builtin types right now, but we + // will implement a way to extend the types for custom adaptors + ADAPTORS[type] = () => adaptor +} diff --git a/packages/opencode/src/control-plane/adaptors/worktree.ts b/packages/opencode/src/control-plane/adaptors/worktree.ts new file mode 100644 index 0000000000..f848909501 --- /dev/null +++ b/packages/opencode/src/control-plane/adaptors/worktree.ts @@ -0,0 +1,46 @@ +import z from "zod" +import { Worktree } from "@/worktree" +import { type Adaptor, WorkspaceInfo } from "../types" + +const Config = WorkspaceInfo.extend({ + name: WorkspaceInfo.shape.name.unwrap(), + branch: WorkspaceInfo.shape.branch.unwrap(), + directory: WorkspaceInfo.shape.directory.unwrap(), +}) + +type Config = z.infer<typeof Config> + +export const WorktreeAdaptor: Adaptor = { + async configure(info) { + const worktree = await Worktree.makeWorktreeInfo(info.name ?? undefined) + return { + ...info, + name: worktree.name, + branch: worktree.branch, + directory: worktree.directory, + } + }, + async create(info) { + const config = Config.parse(info) + const bootstrap = await Worktree.createFromInfo({ + name: config.name, + directory: config.directory, + branch: config.branch, + }) + return bootstrap() + }, + async remove(info) { + const config = Config.parse(info) + await Worktree.remove({ directory: config.directory }) + }, + async fetch(info, input: RequestInfo | URL, init?: RequestInit) { + const config = Config.parse(info) + const { WorkspaceServer } = await import("../workspace-server/server") + const url = input instanceof Request || input instanceof URL ? input : new URL(input, "http://opencode.internal") + const headers = new Headers(init?.headers ?? (input instanceof Request ? input.headers : undefined)) + headers.set("x-opencode-directory", config.directory) + + const request = new Request(url, { ...init, headers }) + return WorkspaceServer.App().fetch(request) + }, +} diff --git a/packages/opencode/src/control-plane/sse.ts b/packages/opencode/src/control-plane/sse.ts new file mode 100644 index 0000000000..003093a003 --- /dev/null +++ b/packages/opencode/src/control-plane/sse.ts @@ -0,0 +1,66 @@ +export async function parseSSE( + body: ReadableStream<Uint8Array>, + signal: AbortSignal, + onEvent: (event: unknown) => void, +) { + const reader = body.getReader() + const decoder = new TextDecoder() + let buf = "" + let last = "" + let retry = 1000 + + const abort = () => { + void reader.cancel().catch(() => undefined) + } + + signal.addEventListener("abort", abort) + + try { + while (!signal.aborted) { + const chunk = await reader.read().catch(() => ({ done: true, value: undefined as Uint8Array | undefined })) + if (chunk.done) break + + buf += decoder.decode(chunk.value, { stream: true }) + buf = buf.replace(/\r\n/g, "\n").replace(/\r/g, "\n") + + const chunks = buf.split("\n\n") + buf = chunks.pop() ?? "" + + chunks.forEach((chunk) => { + const data: string[] = [] + chunk.split("\n").forEach((line) => { + if (line.startsWith("data:")) { + data.push(line.replace(/^data:\s*/, "")) + return + } + if (line.startsWith("id:")) { + last = line.replace(/^id:\s*/, "") + return + } + if (line.startsWith("retry:")) { + const parsed = Number.parseInt(line.replace(/^retry:\s*/, ""), 10) + if (!Number.isNaN(parsed)) retry = parsed + } + }) + + if (!data.length) return + const raw = data.join("\n") + try { + onEvent(JSON.parse(raw)) + } catch { + onEvent({ + type: "sse.message", + properties: { + data: raw, + id: last || undefined, + retry, + }, + }) + } + }) + } + } finally { + signal.removeEventListener("abort", abort) + reader.releaseLock() + } +} diff --git a/packages/opencode/src/control-plane/types.ts b/packages/opencode/src/control-plane/types.ts new file mode 100644 index 0000000000..3d27757fd1 --- /dev/null +++ b/packages/opencode/src/control-plane/types.ts @@ -0,0 +1,20 @@ +import z from "zod" +import { Identifier } from "@/id/id" + +export const WorkspaceInfo = z.object({ + id: Identifier.schema("workspace"), + type: z.string(), + branch: z.string().nullable(), + name: z.string().nullable(), + directory: z.string().nullable(), + extra: z.unknown().nullable(), + projectID: z.string(), +}) +export type WorkspaceInfo = z.infer<typeof WorkspaceInfo> + +export type Adaptor = { + configure(input: WorkspaceInfo): WorkspaceInfo | Promise<WorkspaceInfo> + create(input: WorkspaceInfo, from?: WorkspaceInfo): Promise<void> + remove(config: WorkspaceInfo): Promise<void> + fetch(config: WorkspaceInfo, input: RequestInfo | URL, init?: RequestInit): Promise<Response> +} diff --git a/packages/opencode/src/control-plane/workspace-context.ts b/packages/opencode/src/control-plane/workspace-context.ts new file mode 100644 index 0000000000..f7297b3f4b --- /dev/null +++ b/packages/opencode/src/control-plane/workspace-context.ts @@ -0,0 +1,23 @@ +import { Context } from "../util/context" + +interface Context { + workspaceID?: string +} + +const context = Context.create<Context>("workspace") + +export const WorkspaceContext = { + async provide<R>(input: { workspaceID?: string; fn: () => R }): Promise<R> { + return context.provide({ workspaceID: input.workspaceID }, async () => { + return input.fn() + }) + }, + + get workspaceID() { + try { + return context.use().workspaceID + } catch (e) { + return undefined + } + }, +} diff --git a/packages/opencode/src/control-plane/workspace-router-middleware.ts b/packages/opencode/src/control-plane/workspace-router-middleware.ts new file mode 100644 index 0000000000..463a95ef2b --- /dev/null +++ b/packages/opencode/src/control-plane/workspace-router-middleware.ts @@ -0,0 +1,49 @@ +import type { MiddlewareHandler } from "hono" +import { Flag } from "../flag/flag" +import { getAdaptor } from "./adaptors" +import { Workspace } from "./workspace" +import { WorkspaceContext } from "./workspace-context" + +// This middleware forwards all non-GET requests if the workspace is a +// remote. The remote workspace needs to handle session mutations +async function routeRequest(req: Request) { + // Right now, we need to forward all requests to the workspace + // because we don't have syncing. In the future all GET requests + // which don't mutate anything will be handled locally + // + // if (req.method === "GET") return + + if (!WorkspaceContext.workspaceID) return + + const workspace = await Workspace.get(WorkspaceContext.workspaceID) + if (!workspace) { + return new Response(`Workspace not found: ${WorkspaceContext.workspaceID}`, { + status: 500, + headers: { + "content-type": "text/plain; charset=utf-8", + }, + }) + } + + const adaptor = await getAdaptor(workspace.type) + + return adaptor.fetch(workspace, `${new URL(req.url).pathname}${new URL(req.url).search}`, { + method: req.method, + body: req.method === "GET" || req.method === "HEAD" ? undefined : await req.arrayBuffer(), + signal: req.signal, + headers: req.headers, + }) +} + +export const WorkspaceRouterMiddleware: MiddlewareHandler = async (c, next) => { + // Only available in development for now + if (!Flag.OPENCODE_EXPERIMENTAL_WORKSPACES) { + return next() + } + + const response = await routeRequest(c.req.raw) + if (response) { + return response + } + return next() +} diff --git a/packages/opencode/src/control-plane/workspace-server/routes.ts b/packages/opencode/src/control-plane/workspace-server/routes.ts new file mode 100644 index 0000000000..353e5d50af --- /dev/null +++ b/packages/opencode/src/control-plane/workspace-server/routes.ts @@ -0,0 +1,33 @@ +import { GlobalBus } from "../../bus/global" +import { Hono } from "hono" +import { streamSSE } from "hono/streaming" + +export function WorkspaceServerRoutes() { + return new Hono().get("/event", async (c) => { + c.header("X-Accel-Buffering", "no") + c.header("X-Content-Type-Options", "nosniff") + return streamSSE(c, async (stream) => { + const send = async (event: unknown) => { + await stream.writeSSE({ + data: JSON.stringify(event), + }) + } + const handler = async (event: { directory?: string; payload: unknown }) => { + await send(event.payload) + } + GlobalBus.on("event", handler) + await send({ type: "server.connected", properties: {} }) + const heartbeat = setInterval(() => { + void send({ type: "server.heartbeat", properties: {} }) + }, 10_000) + + await new Promise<void>((resolve) => { + stream.onAbort(() => { + clearInterval(heartbeat) + GlobalBus.off("event", handler) + resolve() + }) + }) + }) + }) +} diff --git a/packages/opencode/src/control-plane/workspace-server/server.ts b/packages/opencode/src/control-plane/workspace-server/server.ts new file mode 100644 index 0000000000..fd7fd93086 --- /dev/null +++ b/packages/opencode/src/control-plane/workspace-server/server.ts @@ -0,0 +1,64 @@ +import { Hono } from "hono" +import { Instance } from "../../project/instance" +import { InstanceBootstrap } from "../../project/bootstrap" +import { SessionRoutes } from "../../server/routes/session" +import { WorkspaceServerRoutes } from "./routes" +import { WorkspaceContext } from "../workspace-context" + +export namespace WorkspaceServer { + export function App() { + const session = new Hono() + .use(async (c, next) => { + // Right now, we need handle all requests because we don't + // have syncing. In the future all GET requests will handled + // by the control plane + // + // if (c.req.method === "GET") return c.notFound() + await next() + }) + .route("/", SessionRoutes()) + + return new Hono() + .use(async (c, next) => { + const workspaceID = c.req.query("workspace") || c.req.header("x-opencode-workspace") + const raw = c.req.query("directory") || c.req.header("x-opencode-directory") + if (workspaceID == null) { + throw new Error("workspaceID parameter is required") + } + if (raw == null) { + throw new Error("directory parameter is required") + } + + const directory = (() => { + try { + return decodeURIComponent(raw) + } catch { + return raw + } + })() + + return WorkspaceContext.provide({ + workspaceID, + async fn() { + return Instance.provide({ + directory, + init: InstanceBootstrap, + async fn() { + return next() + }, + }) + }, + }) + }) + .route("/session", session) + .route("/", WorkspaceServerRoutes()) + } + + export function Listen(opts: { hostname: string; port: number }) { + return Bun.serve({ + hostname: opts.hostname, + port: opts.port, + fetch: App().fetch, + }) + } +} diff --git a/packages/opencode/src/control-plane/workspace.sql.ts b/packages/opencode/src/control-plane/workspace.sql.ts new file mode 100644 index 0000000000..1ba1605f8e --- /dev/null +++ b/packages/opencode/src/control-plane/workspace.sql.ts @@ -0,0 +1,14 @@ +import { sqliteTable, text } from "drizzle-orm/sqlite-core" +import { ProjectTable } from "@/project/project.sql" + +export const WorkspaceTable = sqliteTable("workspace", { + id: text().primaryKey(), + type: text().notNull(), + branch: text(), + name: text(), + directory: text(), + extra: text({ mode: "json" }), + project_id: text() + .notNull() + .references(() => ProjectTable.id, { onDelete: "cascade" }), +}) diff --git a/packages/opencode/src/control-plane/workspace.ts b/packages/opencode/src/control-plane/workspace.ts new file mode 100644 index 0000000000..8c76fbdab9 --- /dev/null +++ b/packages/opencode/src/control-plane/workspace.ts @@ -0,0 +1,152 @@ +import z from "zod" +import { Identifier } from "@/id/id" +import { fn } from "@/util/fn" +import { Database, eq } from "@/storage/db" +import { Project } from "@/project/project" +import { BusEvent } from "@/bus/bus-event" +import { GlobalBus } from "@/bus/global" +import { Log } from "@/util/log" +import { WorkspaceTable } from "./workspace.sql" +import { getAdaptor } from "./adaptors" +import { WorkspaceInfo } from "./types" +import { parseSSE } from "./sse" + +export namespace Workspace { + export const Event = { + Ready: BusEvent.define( + "workspace.ready", + z.object({ + name: z.string(), + }), + ), + Failed: BusEvent.define( + "workspace.failed", + z.object({ + message: z.string(), + }), + ), + } + + export const Info = WorkspaceInfo.meta({ + ref: "Workspace", + }) + export type Info = z.infer<typeof Info> + + function fromRow(row: typeof WorkspaceTable.$inferSelect): Info { + return { + id: row.id, + type: row.type, + branch: row.branch, + name: row.name, + directory: row.directory, + extra: row.extra, + projectID: row.project_id, + } + } + + const CreateInput = z.object({ + id: Identifier.schema("workspace").optional(), + type: Info.shape.type, + branch: Info.shape.branch, + projectID: Info.shape.projectID, + extra: Info.shape.extra, + }) + + export const create = fn(CreateInput, async (input) => { + const id = Identifier.ascending("workspace", input.id) + const adaptor = await getAdaptor(input.type) + + const config = await adaptor.configure({ ...input, id, name: null, directory: null }) + + const info: Info = { + id, + type: config.type, + branch: config.branch ?? null, + name: config.name ?? null, + directory: config.directory ?? null, + extra: config.extra ?? null, + projectID: input.projectID, + } + + Database.use((db) => { + db.insert(WorkspaceTable) + .values({ + id: info.id, + type: info.type, + branch: info.branch, + name: info.name, + directory: info.directory, + extra: info.extra, + project_id: info.projectID, + }) + .run() + }) + + await adaptor.create(config) + return info + }) + + export function list(project: Project.Info) { + const rows = Database.use((db) => + db.select().from(WorkspaceTable).where(eq(WorkspaceTable.project_id, project.id)).all(), + ) + return rows.map(fromRow).sort((a, b) => a.id.localeCompare(b.id)) + } + + export const get = fn(Identifier.schema("workspace"), async (id) => { + const row = Database.use((db) => db.select().from(WorkspaceTable).where(eq(WorkspaceTable.id, id)).get()) + if (!row) return + return fromRow(row) + }) + + export const remove = fn(Identifier.schema("workspace"), async (id) => { + const row = Database.use((db) => db.select().from(WorkspaceTable).where(eq(WorkspaceTable.id, id)).get()) + if (row) { + const info = fromRow(row) + const adaptor = await getAdaptor(row.type) + adaptor.remove(info) + Database.use((db) => db.delete(WorkspaceTable).where(eq(WorkspaceTable.id, id)).run()) + return info + } + }) + const log = Log.create({ service: "workspace-sync" }) + + async function workspaceEventLoop(space: Info, stop: AbortSignal) { + while (!stop.aborted) { + const adaptor = await getAdaptor(space.type) + const res = await adaptor.fetch(space, "/event", { method: "GET", signal: stop }).catch(() => undefined) + if (!res || !res.ok || !res.body) { + await Bun.sleep(1000) + continue + } + await parseSSE(res.body, stop, (event) => { + GlobalBus.emit("event", { + directory: space.id, + payload: event, + }) + }) + // Wait 250ms and retry if SSE connection fails + await Bun.sleep(250) + } + } + + export function startSyncing(project: Project.Info) { + const stop = new AbortController() + const spaces = list(project).filter((space) => space.type !== "worktree") + + spaces.forEach((space) => { + void workspaceEventLoop(space, stop.signal).catch((error) => { + log.warn("workspace sync listener failed", { + workspaceID: space.id, + error, + }) + }) + }) + + return { + async stop() { + stop.abort() + }, + } + } +} diff --git a/packages/opencode/src/file/ignore.ts b/packages/opencode/src/file/ignore.ts index 94ffaf5ce0..b9731040c7 100644 --- a/packages/opencode/src/file/ignore.ts +++ b/packages/opencode/src/file/ignore.ts @@ -67,7 +67,7 @@ export namespace FileIgnore { if (Glob.match(pattern, filepath)) return false } - const parts = filepath.split(sep) + const parts = filepath.split(/[/\\]/) for (let i = 0; i < parts.length; i++) { if (FOLDERS.has(parts[i])) return true } diff --git a/packages/opencode/src/file/index.ts b/packages/opencode/src/file/index.ts index b7daddc5fb..7a51ca36c7 100644 --- a/packages/opencode/src/file/index.ts +++ b/packages/opencode/src/file/index.ts @@ -1,6 +1,5 @@ import { BusEvent } from "@/bus/bus-event" import z from "zod" -import { $ } from "bun" import { formatPatch, structuredPatch } from "diff" import path from "path" import fs from "fs" @@ -11,6 +10,7 @@ import { Instance } from "../project/instance" import { Ripgrep } from "./ripgrep" import fuzzysort from "fuzzysort" import { Global } from "../global" +import { git } from "@/util/git" export namespace File { const log = Log.create({ service: "file" }) @@ -418,11 +418,11 @@ export namespace File { const project = Instance.project if (project.vcs !== "git") return [] - const diffOutput = await $`git -c core.quotepath=false diff --numstat HEAD` - .cwd(Instance.directory) - .quiet() - .nothrow() - .text() + const diffOutput = ( + await git(["-c", "core.fsmonitor=false", "-c", "core.quotepath=false", "diff", "--numstat", "HEAD"], { + cwd: Instance.directory, + }) + ).text() const changedFiles: Info[] = [] @@ -439,11 +439,14 @@ export namespace File { } } - const untrackedOutput = await $`git -c core.quotepath=false ls-files --others --exclude-standard` - .cwd(Instance.directory) - .quiet() - .nothrow() - .text() + const untrackedOutput = ( + await git( + ["-c", "core.fsmonitor=false", "-c", "core.quotepath=false", "ls-files", "--others", "--exclude-standard"], + { + cwd: Instance.directory, + }, + ) + ).text() if (untrackedOutput.trim()) { const untrackedFiles = untrackedOutput.trim().split("\n") @@ -464,11 +467,14 @@ export namespace File { } // Get deleted files - const deletedOutput = await $`git -c core.quotepath=false diff --name-only --diff-filter=D HEAD` - .cwd(Instance.directory) - .quiet() - .nothrow() - .text() + const deletedOutput = ( + await git( + ["-c", "core.fsmonitor=false", "-c", "core.quotepath=false", "diff", "--name-only", "--diff-filter=D", "HEAD"], + { + cwd: Instance.directory, + }, + ) + ).text() if (deletedOutput.trim()) { const deletedFiles = deletedOutput.trim().split("\n") @@ -539,10 +545,14 @@ export namespace File { const content = (await Filesystem.readText(full).catch(() => "")).trim() if (project.vcs === "git") { - let diff = await $`git diff ${file}`.cwd(Instance.directory).quiet().nothrow().text() - if (!diff.trim()) diff = await $`git diff --staged ${file}`.cwd(Instance.directory).quiet().nothrow().text() + let diff = (await git(["-c", "core.fsmonitor=false", "diff", "--", file], { cwd: Instance.directory })).text() + if (!diff.trim()) { + diff = ( + await git(["-c", "core.fsmonitor=false", "diff", "--staged", "--", file], { cwd: Instance.directory }) + ).text() + } if (diff.trim()) { - const original = await $`git show HEAD:${file}`.cwd(Instance.directory).quiet().nothrow().text() + const original = (await git(["show", `HEAD:${file}`], { cwd: Instance.directory })).text() const patch = structuredPatch(file, file, original, content, "old", "new", { context: Infinity, ignoreWhitespace: true, diff --git a/packages/opencode/src/file/ripgrep.ts b/packages/opencode/src/file/ripgrep.ts index ca1eadae8e..b1068f5d8e 100644 --- a/packages/opencode/src/file/ripgrep.ts +++ b/packages/opencode/src/file/ripgrep.ts @@ -5,8 +5,11 @@ import fs from "fs/promises" import z from "zod" import { NamedError } from "@opencode-ai/util/error" import { lazy } from "../util/lazy" -import { $ } from "bun" + import { Filesystem } from "../util/filesystem" +import { Process } from "../util/process" +import { which } from "../util/which" +import { text } from "node:stream/consumers" import { ZipReader, BlobReader, BlobWriter } from "@zip.js/zip.js" import { Log } from "@/util/log" @@ -124,7 +127,7 @@ export namespace Ripgrep { ) const state = lazy(async () => { - const system = Bun.which("rg") + const system = which("rg") if (system) { const stat = await fs.stat(system).catch(() => undefined) if (stat?.isFile()) return { filepath: system } @@ -153,17 +156,19 @@ export namespace Ripgrep { if (platformKey.endsWith("-darwin")) args.push("--include=*/rg") if (platformKey.endsWith("-linux")) args.push("--wildcards", "*/rg") - const proc = Bun.spawn(args, { + const proc = Process.spawn(args, { cwd: Global.Path.bin, stderr: "pipe", stdout: "pipe", }) - await proc.exited - if (proc.exitCode !== 0) + const exit = await proc.exited + if (exit !== 0) { + const stderr = proc.stderr ? await text(proc.stderr) : "" throw new ExtractionFailedError({ filepath, - stderr: await Bun.readableStreamToText(proc.stderr), + stderr, }) + } } if (config.extension === "zip") { const zipFileReader = new ZipReader(new BlobReader(new Blob([arrayBuffer]))) @@ -227,8 +232,7 @@ export namespace Ripgrep { } } - // Bun.spawn should throw this, but it incorrectly reports that the executable does not exist. - // See https://github.com/oven-sh/bun/issues/24012 + // Guard against invalid cwd to provide a consistent ENOENT error. if (!(await fs.stat(input.cwd).catch(() => undefined))?.isDirectory()) { throw Object.assign(new Error(`No such file or directory: '${input.cwd}'`), { code: "ENOENT", @@ -237,41 +241,35 @@ export namespace Ripgrep { }) } - const proc = Bun.spawn(args, { + const proc = Process.spawn(args, { cwd: input.cwd, stdout: "pipe", stderr: "ignore", - maxBuffer: 1024 * 1024 * 20, - signal: input.signal, + abort: input.signal, }) - const reader = proc.stdout.getReader() - const decoder = new TextDecoder() - let buffer = "" - - try { - while (true) { - input.signal?.throwIfAborted() - - const { done, value } = await reader.read() - if (done) break - - buffer += decoder.decode(value, { stream: true }) - // Handle both Unix (\n) and Windows (\r\n) line endings - const lines = buffer.split(/\r?\n/) - buffer = lines.pop() || "" - - for (const line of lines) { - if (line) yield line - } - } - - if (buffer) yield buffer - } finally { - reader.releaseLock() - await proc.exited + if (!proc.stdout) { + throw new Error("Process output not available") } + let buffer = "" + const stream = proc.stdout as AsyncIterable<Buffer | string> + for await (const chunk of stream) { + input.signal?.throwIfAborted() + + buffer += typeof chunk === "string" ? chunk : chunk.toString() + // Handle both Unix (\n) and Windows (\r\n) line endings + const lines = buffer.split(/\r?\n/) + buffer = lines.pop() || "" + + for (const line of lines) { + if (line) yield line + } + } + + if (buffer) yield buffer + await proc.exited + input.signal?.throwIfAborted() } @@ -340,7 +338,7 @@ export namespace Ripgrep { limit?: number follow?: boolean }) { - const args = [`${await filepath()}`, "--json", "--hidden", "--glob='!.git/*'"] + const args = [`${await filepath()}`, "--json", "--hidden", "--glob=!.git/*"] if (input.follow) args.push("--follow") if (input.glob) { @@ -356,14 +354,16 @@ export namespace Ripgrep { args.push("--") args.push(input.pattern) - const command = args.join(" ") - const result = await $`${{ raw: command }}`.cwd(input.cwd).quiet().nothrow() - if (result.exitCode !== 0) { + const result = await Process.text(args, { + cwd: input.cwd, + nothrow: true, + }) + if (result.code !== 0) { return [] } // Handle both Unix (\n) and Windows (\r\n) line endings - const lines = result.text().trim().split(/\r?\n/).filter(Boolean) + const lines = result.text.trim().split(/\r?\n/).filter(Boolean) // Parse JSON lines from ripgrep output return lines diff --git a/packages/opencode/src/file/time.ts b/packages/opencode/src/file/time.ts index c85781eb41..efb1c43764 100644 --- a/packages/opencode/src/file/time.ts +++ b/packages/opencode/src/file/time.ts @@ -61,7 +61,8 @@ export namespace FileTime { const time = get(sessionID, filepath) if (!time) throw new Error(`You must read file ${filepath} before overwriting it. Use the Read tool first`) const mtime = Filesystem.stat(filepath)?.mtime - if (mtime && mtime.getTime() > time.getTime()) { + // Allow a 50ms tolerance for Windows NTFS timestamp fuzziness / async flushing + if (mtime && mtime.getTime() > time.getTime() + 50) { throw new Error( `File ${filepath} has been modified since it was last read.\nLast modification: ${mtime.toISOString()}\nLast read: ${time.toISOString()}\n\nPlease read the file again before modifying it.`, ) diff --git a/packages/opencode/src/file/watcher.ts b/packages/opencode/src/file/watcher.ts index c4a4747777..537f526463 100644 --- a/packages/opencode/src/file/watcher.ts +++ b/packages/opencode/src/file/watcher.ts @@ -11,9 +11,9 @@ import { createWrapper } from "@parcel/watcher/wrapper" import { lazy } from "@/util/lazy" import { withTimeout } from "@/util/timeout" import type ParcelWatcher from "@parcel/watcher" -import { $ } from "bun" import { Flag } from "@/flag/flag" import { readdir } from "fs/promises" +import { git } from "@/util/git" const SUBSCRIBE_TIMEOUT_MS = 10_000 @@ -46,7 +46,6 @@ export namespace FileWatcher { const state = Instance.state( async () => { - if (Instance.project.vcs !== "git") return {} log.info("init") const cfg = await Config.get() const backend = (() => { @@ -88,26 +87,25 @@ export namespace FileWatcher { if (sub) subs.push(sub) } - const vcsDir = await $`git rev-parse --git-dir` - .quiet() - .nothrow() - .cwd(Instance.worktree) - .text() - .then((x) => path.resolve(Instance.worktree, x.trim())) - .catch(() => undefined) - if (vcsDir && !cfgIgnores.includes(".git") && !cfgIgnores.includes(vcsDir)) { - const gitDirContents = await readdir(vcsDir).catch(() => []) - const ignoreList = gitDirContents.filter((entry) => entry !== "HEAD") - const pending = w.subscribe(vcsDir, subscribe, { - ignore: ignoreList, - backend, + if (Instance.project.vcs === "git") { + const result = await git(["rev-parse", "--git-dir"], { + cwd: Instance.worktree, }) - const sub = await withTimeout(pending, SUBSCRIBE_TIMEOUT_MS).catch((err) => { - log.error("failed to subscribe to vcsDir", { error: err }) - pending.then((s) => s.unsubscribe()).catch(() => {}) - return undefined - }) - if (sub) subs.push(sub) + const vcsDir = result.exitCode === 0 ? path.resolve(Instance.worktree, result.text().trim()) : undefined + if (vcsDir && !cfgIgnores.includes(".git") && !cfgIgnores.includes(vcsDir)) { + const gitDirContents = await readdir(vcsDir).catch(() => []) + const ignoreList = gitDirContents.filter((entry) => entry !== "HEAD") + const pending = w.subscribe(vcsDir, subscribe, { + ignore: ignoreList, + backend, + }) + const sub = await withTimeout(pending, SUBSCRIBE_TIMEOUT_MS).catch((err) => { + log.error("failed to subscribe to vcsDir", { error: err }) + pending.then((s) => s.unsubscribe()).catch(() => {}) + return undefined + }) + if (sub) subs.push(sub) + } } return { subs } diff --git a/packages/opencode/src/flag/flag.ts b/packages/opencode/src/flag/flag.ts index 0049d716d0..30929bd926 100644 --- a/packages/opencode/src/flag/flag.ts +++ b/packages/opencode/src/flag/flag.ts @@ -3,10 +3,16 @@ function truthy(key: string) { return value === "true" || value === "1" } +function falsy(key: string) { + const value = process.env[key]?.toLowerCase() + return value === "false" || value === "0" +} + export namespace Flag { export const OPENCODE_AUTO_SHARE = truthy("OPENCODE_AUTO_SHARE") export const OPENCODE_GIT_BASH_PATH = process.env["OPENCODE_GIT_BASH_PATH"] export const OPENCODE_CONFIG = process.env["OPENCODE_CONFIG"] + export declare const OPENCODE_TUI_CONFIG: string | undefined export declare const OPENCODE_CONFIG_DIR: string | undefined export const OPENCODE_CONFIG_CONTENT = process.env["OPENCODE_CONFIG_CONTENT"] export const OPENCODE_DISABLE_AUTOUPDATE = truthy("OPENCODE_DISABLE_AUTOUPDATE") @@ -51,9 +57,12 @@ export namespace Flag { export const OPENCODE_EXPERIMENTAL_LSP_TOOL = OPENCODE_EXPERIMENTAL || truthy("OPENCODE_EXPERIMENTAL_LSP_TOOL") export const OPENCODE_DISABLE_FILETIME_CHECK = truthy("OPENCODE_DISABLE_FILETIME_CHECK") export const OPENCODE_EXPERIMENTAL_PLAN_MODE = OPENCODE_EXPERIMENTAL || truthy("OPENCODE_EXPERIMENTAL_PLAN_MODE") - export const OPENCODE_EXPERIMENTAL_MARKDOWN = truthy("OPENCODE_EXPERIMENTAL_MARKDOWN") + export const OPENCODE_EXPERIMENTAL_WORKSPACES = OPENCODE_EXPERIMENTAL || truthy("OPENCODE_EXPERIMENTAL_WORKSPACES") + export const OPENCODE_EXPERIMENTAL_MARKDOWN = !falsy("OPENCODE_EXPERIMENTAL_MARKDOWN") export const OPENCODE_MODELS_URL = process.env["OPENCODE_MODELS_URL"] export const OPENCODE_MODELS_PATH = process.env["OPENCODE_MODELS_PATH"] + export const OPENCODE_DISABLE_CHANNEL_DB = truthy("OPENCODE_DISABLE_CHANNEL_DB") + export const OPENCODE_SKIP_MIGRATIONS = truthy("OPENCODE_SKIP_MIGRATIONS") function number(key: string) { const value = process.env[key] @@ -74,6 +83,17 @@ Object.defineProperty(Flag, "OPENCODE_DISABLE_PROJECT_CONFIG", { configurable: false, }) +// Dynamic getter for OPENCODE_TUI_CONFIG +// This must be evaluated at access time, not module load time, +// because tests and external tooling may set this env var at runtime +Object.defineProperty(Flag, "OPENCODE_TUI_CONFIG", { + get() { + return process.env["OPENCODE_TUI_CONFIG"] + }, + enumerable: true, + configurable: false, +}) + // Dynamic getter for OPENCODE_CONFIG_DIR // This must be evaluated at access time, not module load time, // because external tooling may set this env var at runtime diff --git a/packages/opencode/src/format/formatter.ts b/packages/opencode/src/format/formatter.ts index 47b2d6a12d..9e96b2305c 100644 --- a/packages/opencode/src/format/formatter.ts +++ b/packages/opencode/src/format/formatter.ts @@ -1,7 +1,9 @@ -import { readableStreamToText } from "bun" +import { text } from "node:stream/consumers" import { BunProc } from "../bun" import { Instance } from "../project/instance" import { Filesystem } from "../util/filesystem" +import { Process } from "../util/process" +import { which } from "../util/which" import { Flag } from "@/flag/flag" export interface Info { @@ -17,7 +19,7 @@ export const gofmt: Info = { command: ["gofmt", "-w", "$FILE"], extensions: [".go"], async enabled() { - return Bun.which("gofmt") !== null + return which("gofmt") !== null }, } @@ -26,7 +28,7 @@ export const mix: Info = { command: ["mix", "format", "$FILE"], extensions: [".ex", ".exs", ".eex", ".heex", ".leex", ".neex", ".sface"], async enabled() { - return Bun.which("mix") !== null + return which("mix") !== null }, } @@ -151,7 +153,7 @@ export const zig: Info = { command: ["zig", "fmt", "$FILE"], extensions: [".zig", ".zon"], async enabled() { - return Bun.which("zig") !== null + return which("zig") !== null }, } @@ -170,7 +172,7 @@ export const ktlint: Info = { command: ["ktlint", "-F", "$FILE"], extensions: [".kt", ".kts"], async enabled() { - return Bun.which("ktlint") !== null + return which("ktlint") !== null }, } @@ -179,7 +181,7 @@ export const ruff: Info = { command: ["ruff", "format", "$FILE"], extensions: [".py", ".pyi"], async enabled() { - if (!Bun.which("ruff")) return false + if (!which("ruff")) return false const configs = ["pyproject.toml", "ruff.toml", ".ruff.toml"] for (const config of configs) { const found = await Filesystem.findUp(config, Instance.directory, Instance.worktree) @@ -209,16 +211,17 @@ export const rlang: Info = { command: ["air", "format", "$FILE"], extensions: [".R"], async enabled() { - const airPath = Bun.which("air") + const airPath = which("air") if (airPath == null) return false try { - const proc = Bun.spawn(["air", "--help"], { + const proc = Process.spawn(["air", "--help"], { stdout: "pipe", stderr: "pipe", }) await proc.exited - const output = await readableStreamToText(proc.stdout) + if (!proc.stdout) return false + const output = await text(proc.stdout) // Check for "Air: An R language server and formatter" const firstLine = output.split("\n")[0] @@ -237,8 +240,8 @@ export const uvformat: Info = { extensions: [".py", ".pyi"], async enabled() { if (await ruff.enabled()) return false - if (Bun.which("uv") !== null) { - const proc = Bun.spawn(["uv", "format", "--help"], { stderr: "pipe", stdout: "pipe" }) + if (which("uv") !== null) { + const proc = Process.spawn(["uv", "format", "--help"], { stderr: "pipe", stdout: "pipe" }) const code = await proc.exited return code === 0 } @@ -251,7 +254,7 @@ export const rubocop: Info = { command: ["rubocop", "--autocorrect", "$FILE"], extensions: [".rb", ".rake", ".gemspec", ".ru"], async enabled() { - return Bun.which("rubocop") !== null + return which("rubocop") !== null }, } @@ -260,7 +263,7 @@ export const standardrb: Info = { command: ["standardrb", "--fix", "$FILE"], extensions: [".rb", ".rake", ".gemspec", ".ru"], async enabled() { - return Bun.which("standardrb") !== null + return which("standardrb") !== null }, } @@ -269,7 +272,7 @@ export const htmlbeautifier: Info = { command: ["htmlbeautifier", "$FILE"], extensions: [".erb", ".html.erb"], async enabled() { - return Bun.which("htmlbeautifier") !== null + return which("htmlbeautifier") !== null }, } @@ -278,7 +281,7 @@ export const dart: Info = { command: ["dart", "format", "$FILE"], extensions: [".dart"], async enabled() { - return Bun.which("dart") !== null + return which("dart") !== null }, } @@ -287,7 +290,7 @@ export const ocamlformat: Info = { command: ["ocamlformat", "-i", "$FILE"], extensions: [".ml", ".mli"], async enabled() { - if (!Bun.which("ocamlformat")) return false + if (!which("ocamlformat")) return false const items = await Filesystem.findUp(".ocamlformat", Instance.directory, Instance.worktree) return items.length > 0 }, @@ -298,7 +301,7 @@ export const terraform: Info = { command: ["terraform", "fmt", "$FILE"], extensions: [".tf", ".tfvars"], async enabled() { - return Bun.which("terraform") !== null + return which("terraform") !== null }, } @@ -307,7 +310,7 @@ export const latexindent: Info = { command: ["latexindent", "-w", "-s", "$FILE"], extensions: [".tex"], async enabled() { - return Bun.which("latexindent") !== null + return which("latexindent") !== null }, } @@ -316,7 +319,7 @@ export const gleam: Info = { command: ["gleam", "format", "$FILE"], extensions: [".gleam"], async enabled() { - return Bun.which("gleam") !== null + return which("gleam") !== null }, } @@ -325,7 +328,7 @@ export const shfmt: Info = { command: ["shfmt", "-w", "$FILE"], extensions: [".sh", ".bash"], async enabled() { - return Bun.which("shfmt") !== null + return which("shfmt") !== null }, } @@ -334,7 +337,7 @@ export const nixfmt: Info = { command: ["nixfmt", "$FILE"], extensions: [".nix"], async enabled() { - return Bun.which("nixfmt") !== null + return which("nixfmt") !== null }, } @@ -343,7 +346,7 @@ export const rustfmt: Info = { command: ["rustfmt", "$FILE"], extensions: [".rs"], async enabled() { - return Bun.which("rustfmt") !== null + return which("rustfmt") !== null }, } @@ -370,7 +373,7 @@ export const ormolu: Info = { command: ["ormolu", "-i", "$FILE"], extensions: [".hs"], async enabled() { - return Bun.which("ormolu") !== null + return which("ormolu") !== null }, } @@ -379,7 +382,7 @@ export const cljfmt: Info = { command: ["cljfmt", "fix", "--quiet", "$FILE"], extensions: [".clj", ".cljs", ".cljc", ".edn"], async enabled() { - return Bun.which("cljfmt") !== null + return which("cljfmt") !== null }, } @@ -388,6 +391,6 @@ export const dfmt: Info = { command: ["dfmt", "-i", "$FILE"], extensions: [".d"], async enabled() { - return Bun.which("dfmt") !== null + return which("dfmt") !== null }, } diff --git a/packages/opencode/src/format/index.ts b/packages/opencode/src/format/index.ts index bab758030b..b849f778ec 100644 --- a/packages/opencode/src/format/index.ts +++ b/packages/opencode/src/format/index.ts @@ -8,6 +8,7 @@ import * as Formatter from "./formatter" import { Config } from "../config/config" import { mergeDeep } from "remeda" import { Instance } from "../project/instance" +import { Process } from "../util/process" export namespace Format { const log = Log.create({ service: "format" }) @@ -110,13 +111,15 @@ export namespace Format { for (const item of await getFormatter(ext)) { log.info("running", { command: item.command }) try { - const proc = Bun.spawn({ - cmd: item.command.map((x) => x.replace("$FILE", file)), - cwd: Instance.directory, - env: { ...process.env, ...item.environment }, - stdout: "ignore", - stderr: "ignore", - }) + const proc = Process.spawn( + item.command.map((x) => x.replace("$FILE", file)), + { + cwd: Instance.directory, + env: { ...process.env, ...item.environment }, + stdout: "ignore", + stderr: "ignore", + }, + ) const exit = await proc.exited if (exit !== 0) log.error("failed", { diff --git a/packages/opencode/src/id/id.ts b/packages/opencode/src/id/id.ts index db2920b0a4..6673297cbf 100644 --- a/packages/opencode/src/id/id.ts +++ b/packages/opencode/src/id/id.ts @@ -11,6 +11,7 @@ export namespace Identifier { part: "prt", pty: "pty", tool: "tool", + workspace: "wrk", } as const export function schema(prefix: keyof typeof prefixes) { diff --git a/packages/opencode/src/index.ts b/packages/opencode/src/index.ts index 6551565886..4fd5f0e67b 100644 --- a/packages/opencode/src/index.ts +++ b/packages/opencode/src/index.ts @@ -13,6 +13,7 @@ import { Installation } from "./installation" import { NamedError } from "@opencode-ai/util/error" import { FormatError } from "./cli/error" import { ServeCommand } from "./cli/cmd/serve" +import { WorkspaceServeCommand } from "./cli/cmd/workspace-serve" import { Filesystem } from "./util/filesystem" import { DebugCommand } from "./cli/cmd/debug" import { StatsCommand } from "./cli/cmd/stats" @@ -45,7 +46,12 @@ process.on("uncaughtException", (e) => { }) }) -const cli = yargs(hideBin(process.argv)) +// Ensure the process exits on terminal hangup (eg. closing the terminal tab). +// Without this, long-running commands like `serve` block on a never-resolving +// promise and survive as orphaned processes. +process.on("SIGHUP", () => process.exit()) + +let cli = yargs(hideBin(process.argv)) .parserConfiguration({ "populate--": true }) .scriptName("opencode") .wrap(100) @@ -75,6 +81,7 @@ const cli = yargs(hideBin(process.argv)) process.env.AGENT = "1" process.env.OPENCODE = "1" + process.env.OPENCODE_PID = String(process.pid) Log.Default.info("opencode", { version: Installation.VERSION, @@ -141,6 +148,12 @@ const cli = yargs(hideBin(process.argv)) .command(PrCommand) .command(SessionCommand) .command(DbCommand) + +if (Installation.isLocal()) { + cli = cli.command(WorkspaceServeCommand) +} + +cli = cli .fail((msg, err) => { if ( msg?.startsWith("Unknown argument") || diff --git a/packages/opencode/src/installation/index.ts b/packages/opencode/src/installation/index.ts index 47278bd562..92a3bfc796 100644 --- a/packages/opencode/src/installation/index.ts +++ b/packages/opencode/src/installation/index.ts @@ -1,11 +1,12 @@ import { BusEvent } from "@/bus/bus-event" import path from "path" -import { $ } from "bun" import z from "zod" import { NamedError } from "@opencode-ai/util/error" import { Log } from "../util/log" import { iife } from "@/util/iife" import { Flag } from "../flag/flag" +import { Process } from "@/util/process" +import { buffer } from "node:stream/consumers" declare global { const OPENCODE_VERSION: string @@ -15,6 +16,38 @@ declare global { export namespace Installation { const log = Log.create({ service: "installation" }) + async function text(cmd: string[], opts: { cwd?: string; env?: NodeJS.ProcessEnv } = {}) { + return Process.text(cmd, { + cwd: opts.cwd, + env: opts.env, + nothrow: true, + }).then((x) => x.text) + } + + async function upgradeCurl(target: string) { + const body = await fetch("https://opencode.ai/install").then((res) => { + if (!res.ok) throw new Error(res.statusText) + return res.text() + }) + const proc = Process.spawn(["bash"], { + stdin: "pipe", + stdout: "pipe", + stderr: "pipe", + env: { + ...process.env, + VERSION: target, + }, + }) + if (!proc.stdin || !proc.stdout || !proc.stderr) throw new Error("Process output not available") + proc.stdin.end(body) + const [code, stdout, stderr] = await Promise.all([proc.exited, buffer(proc.stdout), buffer(proc.stderr)]) + return { + code, + stdout, + stderr, + } + } + export type Method = Awaited<ReturnType<typeof method>> export const Event = { @@ -65,31 +98,31 @@ export namespace Installation { const checks = [ { name: "npm" as const, - command: () => $`npm list -g --depth=0`.throws(false).quiet().text(), + command: () => text(["npm", "list", "-g", "--depth=0"]), }, { name: "yarn" as const, - command: () => $`yarn global list`.throws(false).quiet().text(), + command: () => text(["yarn", "global", "list"]), }, { name: "pnpm" as const, - command: () => $`pnpm list -g --depth=0`.throws(false).quiet().text(), + command: () => text(["pnpm", "list", "-g", "--depth=0"]), }, { name: "bun" as const, - command: () => $`bun pm ls -g`.throws(false).quiet().text(), + command: () => text(["bun", "pm", "ls", "-g"]), }, { name: "brew" as const, - command: () => $`brew list --formula opencode`.throws(false).quiet().text(), + command: () => text(["brew", "list", "--formula", "opencode"]), }, { name: "scoop" as const, - command: () => $`scoop list opencode`.throws(false).quiet().text(), + command: () => text(["scoop", "list", "opencode"]), }, { name: "choco" as const, - command: () => $`choco list --limit-output opencode`.throws(false).quiet().text(), + command: () => text(["choco", "list", "--limit-output", "opencode"]), }, ] @@ -121,61 +154,70 @@ export namespace Installation { ) async function getBrewFormula() { - const tapFormula = await $`brew list --formula anomalyco/tap/opencode`.throws(false).quiet().text() + const tapFormula = await text(["brew", "list", "--formula", "anomalyco/tap/opencode"]) if (tapFormula.includes("opencode")) return "anomalyco/tap/opencode" - const coreFormula = await $`brew list --formula opencode`.throws(false).quiet().text() + const coreFormula = await text(["brew", "list", "--formula", "opencode"]) if (coreFormula.includes("opencode")) return "opencode" return "opencode" } export async function upgrade(method: Method, target: string) { - let cmd + let result: Awaited<ReturnType<typeof upgradeCurl>> | undefined switch (method) { case "curl": - cmd = $`curl -fsSL https://opencode.ai/install | bash`.env({ - ...process.env, - VERSION: target, - }) + result = await upgradeCurl(target) break case "npm": - cmd = $`npm install -g opencode-ai@${target}` + result = await Process.run(["npm", "install", "-g", `opencode-ai@${target}`], { nothrow: true }) break case "pnpm": - cmd = $`pnpm install -g opencode-ai@${target}` + result = await Process.run(["pnpm", "install", "-g", `opencode-ai@${target}`], { nothrow: true }) break case "bun": - cmd = $`bun install -g opencode-ai@${target}` + result = await Process.run(["bun", "install", "-g", `opencode-ai@${target}`], { nothrow: true }) break case "brew": { const formula = await getBrewFormula() - if (formula.includes("/")) { - cmd = - $`brew tap anomalyco/tap && cd "$(brew --repo anomalyco/tap)" && git pull --ff-only && brew upgrade ${formula}`.env( - { - HOMEBREW_NO_AUTO_UPDATE: "1", - ...process.env, - }, - ) - break - } - cmd = $`brew upgrade ${formula}`.env({ + const env = { HOMEBREW_NO_AUTO_UPDATE: "1", ...process.env, - }) + } + if (formula.includes("/")) { + const tap = await Process.run(["brew", "tap", "anomalyco/tap"], { env, nothrow: true }) + if (tap.code !== 0) { + result = tap + break + } + const repo = await Process.text(["brew", "--repo", "anomalyco/tap"], { env, nothrow: true }) + if (repo.code !== 0) { + result = repo + break + } + const dir = repo.text.trim() + if (dir) { + const pull = await Process.run(["git", "pull", "--ff-only"], { cwd: dir, env, nothrow: true }) + if (pull.code !== 0) { + result = pull + break + } + } + } + result = await Process.run(["brew", "upgrade", formula], { env, nothrow: true }) break } + case "choco": - cmd = $`echo Y | choco upgrade opencode --version=${target}` + result = await Process.run(["choco", "upgrade", "opencode", `--version=${target}`, "-y"], { nothrow: true }) break case "scoop": - cmd = $`scoop install opencode@${target}` + result = await Process.run(["scoop", "install", `opencode@${target}`], { nothrow: true }) break default: throw new Error(`Unknown method: ${method}`) } - const result = await cmd.quiet().throws(false) - if (result.exitCode !== 0) { - const stderr = method === "choco" ? "not running from an elevated command shell" : result.stderr.toString("utf8") + if (!result || result.code !== 0) { + const stderr = + method === "choco" ? "not running from an elevated command shell" : result?.stderr.toString("utf8") || "" throw new UpgradeFailedError({ stderr: stderr, }) @@ -186,7 +228,7 @@ export namespace Installation { stdout: result.stdout.toString(), stderr: result.stderr.toString(), }) - await $`${process.execPath} --version`.nothrow().quiet().text() + await Process.text([process.execPath, "--version"], { nothrow: true }) } export const VERSION = typeof OPENCODE_VERSION === "string" ? OPENCODE_VERSION : "local" @@ -199,7 +241,7 @@ export namespace Installation { if (detectedMethod === "brew") { const formula = await getBrewFormula() if (formula.includes("/")) { - const infoJson = await $`brew info --json=v2 ${formula}`.quiet().text() + const infoJson = await text(["brew", "info", "--json=v2", formula]) const info = JSON.parse(infoJson) const version = info.formulae?.[0]?.versions?.stable if (!version) throw new Error(`Could not detect version for tap formula: ${formula}`) @@ -215,7 +257,7 @@ export namespace Installation { if (detectedMethod === "npm" || detectedMethod === "bun" || detectedMethod === "pnpm") { const registry = await iife(async () => { - const r = (await $`npm config get registry`.quiet().nothrow().text()).trim() + const r = (await text(["npm", "config", "get", "registry"])).trim() const reg = r || "https://registry.npmjs.org" return reg.endsWith("/") ? reg.slice(0, -1) : reg }) diff --git a/packages/opencode/src/lsp/server.ts b/packages/opencode/src/lsp/server.ts index a4ebeb5a25..71f50c94b1 100644 --- a/packages/opencode/src/lsp/server.ts +++ b/packages/opencode/src/lsp/server.ts @@ -4,12 +4,15 @@ import os from "os" import { Global } from "../global" import { Log } from "../util/log" import { BunProc } from "../bun" -import { $, readableStreamToText } from "bun" +import { text } from "node:stream/consumers" import fs from "fs/promises" import { Filesystem } from "../util/filesystem" import { Instance } from "../project/instance" import { Flag } from "../flag/flag" import { Archive } from "../util/archive" +import { Process } from "../util/process" +import { which } from "../util/which" +import { Module } from "@opencode-ai/util/module" export namespace LSPServer { const log = Log.create({ service: "lsp.server" }) @@ -18,6 +21,8 @@ export namespace LSPServer { .stat(p) .then(() => true) .catch(() => false) + const run = (cmd: string[], opts: Process.RunOptions = {}) => Process.run(cmd, { ...opts, nothrow: true }) + const output = (cmd: string[], opts: Process.RunOptions = {}) => Process.text(cmd, { ...opts, nothrow: true }) export interface Handle { process: ChildProcessWithoutNullStreams @@ -73,7 +78,7 @@ export namespace LSPServer { }, extensions: [".ts", ".tsx", ".js", ".jsx", ".mjs"], async spawn(root) { - const deno = Bun.which("deno") + const deno = which("deno") if (!deno) { log.info("deno not found, please install deno first") return @@ -94,7 +99,7 @@ export namespace LSPServer { ), extensions: [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".mts", ".cts"], async spawn(root) { - const tsserver = await Bun.resolve("typescript/lib/tsserver.js", Instance.directory).catch(() => {}) + const tsserver = Module.resolve("typescript/lib/tsserver.js", Instance.directory) log.info("typescript server", { tsserver }) if (!tsserver) return const proc = spawn(BunProc.which(), ["x", "typescript-language-server", "--stdio"], { @@ -120,7 +125,7 @@ export namespace LSPServer { extensions: [".vue"], root: NearestRoot(["package-lock.json", "bun.lockb", "bun.lock", "pnpm-lock.yaml", "yarn.lock"]), async spawn(root) { - let binary = Bun.which("vue-language-server") + let binary = which("vue-language-server") const args: string[] = [] if (!binary) { const js = path.join( @@ -133,7 +138,7 @@ export namespace LSPServer { ) if (!(await Filesystem.exists(js))) { if (Flag.OPENCODE_DISABLE_LSP_DOWNLOAD) return - await Bun.spawn([BunProc.which(), "install", "@vue/language-server"], { + await Process.spawn([BunProc.which(), "install", "@vue/language-server"], { cwd: Global.Path.bin, env: { ...process.env, @@ -169,7 +174,7 @@ export namespace LSPServer { root: NearestRoot(["package-lock.json", "bun.lockb", "bun.lock", "pnpm-lock.yaml", "yarn.lock"]), extensions: [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".mts", ".cts", ".vue"], async spawn(root) { - const eslint = await Bun.resolve("eslint", Instance.directory).catch(() => {}) + const eslint = Module.resolve("eslint", Instance.directory) if (!eslint) return log.info("spawning eslint server") const serverPath = path.join(Global.Path.bin, "vscode-eslint", "server", "out", "eslintServer.js") @@ -202,8 +207,8 @@ export namespace LSPServer { await fs.rename(extractedPath, finalPath) const npmCmd = process.platform === "win32" ? "npm.cmd" : "npm" - await $`${npmCmd} install`.cwd(finalPath).quiet() - await $`${npmCmd} run compile`.cwd(finalPath).quiet() + await Process.run([npmCmd, "install"], { cwd: finalPath }) + await Process.run([npmCmd, "run", "compile"], { cwd: finalPath }) log.info("installed VS Code ESLint server", { serverPath }) } @@ -258,26 +263,28 @@ export namespace LSPServer { let lintBin = await resolveBin(lintTarget) if (!lintBin) { - const found = Bun.which("oxlint") + const found = which("oxlint") if (found) lintBin = found } if (lintBin) { - const proc = Bun.spawn([lintBin, "--help"], { stdout: "pipe" }) + const proc = Process.spawn([lintBin, "--help"], { stdout: "pipe" }) await proc.exited - const help = await readableStreamToText(proc.stdout) - if (help.includes("--lsp")) { - return { - process: spawn(lintBin, ["--lsp"], { - cwd: root, - }), + if (proc.stdout) { + const help = await text(proc.stdout) + if (help.includes("--lsp")) { + return { + process: spawn(lintBin, ["--lsp"], { + cwd: root, + }), + } } } } let serverBin = await resolveBin(serverTarget) if (!serverBin) { - const found = Bun.which("oxc_language_server") + const found = which("oxc_language_server") if (found) serverBin = found } if (serverBin) { @@ -328,14 +335,14 @@ export namespace LSPServer { let bin: string | undefined if (await Filesystem.exists(localBin)) bin = localBin if (!bin) { - const found = Bun.which("biome") + const found = which("biome") if (found) bin = found } let args = ["lsp-proxy", "--stdio"] if (!bin) { - const resolved = await Bun.resolve("biome", root).catch(() => undefined) + const resolved = Module.resolve("biome", root) if (!resolved) return bin = BunProc.which() args = ["x", "biome", "lsp-proxy", "--stdio"] @@ -364,16 +371,15 @@ export namespace LSPServer { }, extensions: [".go"], async spawn(root) { - let bin = Bun.which("gopls", { + let bin = which("gopls", { PATH: process.env["PATH"] + path.delimiter + Global.Path.bin, }) if (!bin) { - if (!Bun.which("go")) return + if (!which("go")) return if (Flag.OPENCODE_DISABLE_LSP_DOWNLOAD) return log.info("installing gopls") - const proc = Bun.spawn({ - cmd: ["go", "install", "golang.org/x/tools/gopls@latest"], + const proc = Process.spawn(["go", "install", "golang.org/x/tools/gopls@latest"], { env: { ...process.env, GOBIN: Global.Path.bin }, stdout: "pipe", stderr: "pipe", @@ -402,20 +408,19 @@ export namespace LSPServer { root: NearestRoot(["Gemfile"]), extensions: [".rb", ".rake", ".gemspec", ".ru"], async spawn(root) { - let bin = Bun.which("rubocop", { + let bin = which("rubocop", { PATH: process.env["PATH"] + path.delimiter + Global.Path.bin, }) if (!bin) { - const ruby = Bun.which("ruby") - const gem = Bun.which("gem") + const ruby = which("ruby") + const gem = which("gem") if (!ruby || !gem) { log.info("Ruby not found, please install Ruby first") return } if (Flag.OPENCODE_DISABLE_LSP_DOWNLOAD) return log.info("installing rubocop") - const proc = Bun.spawn({ - cmd: ["gem", "install", "rubocop", "--bindir", Global.Path.bin], + const proc = Process.spawn(["gem", "install", "rubocop", "--bindir", Global.Path.bin], { stdout: "pipe", stderr: "pipe", stdin: "pipe", @@ -455,7 +460,7 @@ export namespace LSPServer { return undefined } - let binary = Bun.which("ty") + let binary = which("ty") const initialization: Record<string, string> = {} @@ -507,13 +512,13 @@ export namespace LSPServer { extensions: [".py", ".pyi"], root: NearestRoot(["pyproject.toml", "setup.py", "setup.cfg", "requirements.txt", "Pipfile", "pyrightconfig.json"]), async spawn(root) { - let binary = Bun.which("pyright-langserver") + let binary = which("pyright-langserver") const args = [] if (!binary) { const js = path.join(Global.Path.bin, "node_modules", "pyright", "dist", "pyright-langserver.js") if (!(await Filesystem.exists(js))) { if (Flag.OPENCODE_DISABLE_LSP_DOWNLOAD) return - await Bun.spawn([BunProc.which(), "install", "pyright"], { + await Process.spawn([BunProc.which(), "install", "pyright"], { cwd: Global.Path.bin, env: { ...process.env, @@ -561,7 +566,7 @@ export namespace LSPServer { extensions: [".ex", ".exs"], root: NearestRoot(["mix.exs", "mix.lock"]), async spawn(root) { - let binary = Bun.which("elixir-ls") + let binary = which("elixir-ls") if (!binary) { const elixirLsPath = path.join(Global.Path.bin, "elixir-ls") binary = path.join( @@ -572,7 +577,7 @@ export namespace LSPServer { ) if (!(await Filesystem.exists(binary))) { - const elixir = Bun.which("elixir") + const elixir = which("elixir") if (!elixir) { log.error("elixir is required to run elixir-ls") return @@ -599,10 +604,11 @@ export namespace LSPServer { recursive: true, }) - await $`mix deps.get && mix compile && mix elixir_ls.release2 -o release` - .quiet() - .cwd(path.join(Global.Path.bin, "elixir-ls-master")) - .env({ MIX_ENV: "prod", ...process.env }) + const cwd = path.join(Global.Path.bin, "elixir-ls-master") + const env = { MIX_ENV: "prod", ...process.env } + await Process.run(["mix", "deps.get"], { cwd, env }) + await Process.run(["mix", "compile"], { cwd, env }) + await Process.run(["mix", "elixir_ls.release2", "-o", "release"], { cwd, env }) log.info(`installed elixir-ls`, { path: elixirLsPath, @@ -623,12 +629,12 @@ export namespace LSPServer { extensions: [".zig", ".zon"], root: NearestRoot(["build.zig"]), async spawn(root) { - let bin = Bun.which("zls", { + let bin = which("zls", { PATH: process.env["PATH"] + path.delimiter + Global.Path.bin, }) if (!bin) { - const zig = Bun.which("zig") + const zig = which("zig") if (!zig) { log.error("Zig is required to use zls. Please install Zig first.") return @@ -703,7 +709,7 @@ export namespace LSPServer { }) if (!ok) return } else { - await $`tar -xf ${tempPath}`.cwd(Global.Path.bin).quiet().nothrow() + await run(["tar", "-xf", tempPath], { cwd: Global.Path.bin }) } await fs.rm(tempPath, { force: true }) @@ -716,7 +722,7 @@ export namespace LSPServer { } if (platform !== "win32") { - await $`chmod +x ${bin}`.quiet().nothrow() + await fs.chmod(bin, 0o755).catch(() => {}) } log.info(`installed zls`, { bin }) @@ -735,19 +741,18 @@ export namespace LSPServer { root: NearestRoot([".slnx", ".sln", ".csproj", "global.json"]), extensions: [".cs"], async spawn(root) { - let bin = Bun.which("csharp-ls", { + let bin = which("csharp-ls", { PATH: process.env["PATH"] + path.delimiter + Global.Path.bin, }) if (!bin) { - if (!Bun.which("dotnet")) { + if (!which("dotnet")) { log.error(".NET SDK is required to install csharp-ls") return } if (Flag.OPENCODE_DISABLE_LSP_DOWNLOAD) return log.info("installing csharp-ls via dotnet tool") - const proc = Bun.spawn({ - cmd: ["dotnet", "tool", "install", "csharp-ls", "--tool-path", Global.Path.bin], + const proc = Process.spawn(["dotnet", "tool", "install", "csharp-ls", "--tool-path", Global.Path.bin], { stdout: "pipe", stderr: "pipe", stdin: "pipe", @@ -775,19 +780,18 @@ export namespace LSPServer { root: NearestRoot([".slnx", ".sln", ".fsproj", "global.json"]), extensions: [".fs", ".fsi", ".fsx", ".fsscript"], async spawn(root) { - let bin = Bun.which("fsautocomplete", { + let bin = which("fsautocomplete", { PATH: process.env["PATH"] + path.delimiter + Global.Path.bin, }) if (!bin) { - if (!Bun.which("dotnet")) { + if (!which("dotnet")) { log.error(".NET SDK is required to install fsautocomplete") return } if (Flag.OPENCODE_DISABLE_LSP_DOWNLOAD) return log.info("installing fsautocomplete via dotnet tool") - const proc = Bun.spawn({ - cmd: ["dotnet", "tool", "install", "fsautocomplete", "--tool-path", Global.Path.bin], + const proc = Process.spawn(["dotnet", "tool", "install", "fsautocomplete", "--tool-path", Global.Path.bin], { stdout: "pipe", stderr: "pipe", stdin: "pipe", @@ -817,7 +821,7 @@ export namespace LSPServer { async spawn(root) { // Check if sourcekit-lsp is available in the PATH // This is installed with the Swift toolchain - const sourcekit = Bun.which("sourcekit-lsp") + const sourcekit = which("sourcekit-lsp") if (sourcekit) { return { process: spawn(sourcekit, { @@ -828,13 +832,13 @@ export namespace LSPServer { // If sourcekit-lsp not found, check if xcrun is available // This is specific to macOS where sourcekit-lsp is typically installed with Xcode - if (!Bun.which("xcrun")) return + if (!which("xcrun")) return - const lspLoc = await $`xcrun --find sourcekit-lsp`.quiet().nothrow() + const lspLoc = await output(["xcrun", "--find", "sourcekit-lsp"]) - if (lspLoc.exitCode !== 0) return + if (lspLoc.code !== 0) return - const bin = lspLoc.text().trim() + const bin = lspLoc.text.trim() return { process: spawn(bin, { @@ -877,7 +881,7 @@ export namespace LSPServer { }, extensions: [".rs"], async spawn(root) { - const bin = Bun.which("rust-analyzer") + const bin = which("rust-analyzer") if (!bin) { log.info("rust-analyzer not found in path, please install it") return @@ -896,7 +900,7 @@ export namespace LSPServer { extensions: [".c", ".cpp", ".cc", ".cxx", ".c++", ".h", ".hpp", ".hh", ".hxx", ".h++"], async spawn(root) { const args = ["--background-index", "--clang-tidy"] - const fromPath = Bun.which("clangd") + const fromPath = which("clangd") if (fromPath) { return { process: spawn(fromPath, args, { @@ -1009,7 +1013,7 @@ export namespace LSPServer { if (!ok) return } if (tar) { - await $`tar -xf ${archive}`.cwd(Global.Path.bin).quiet().nothrow() + await run(["tar", "-xf", archive], { cwd: Global.Path.bin }) } await fs.rm(archive, { force: true }) @@ -1020,7 +1024,7 @@ export namespace LSPServer { } if (platform !== "win32") { - await $`chmod +x ${bin}`.quiet().nothrow() + await fs.chmod(bin, 0o755).catch(() => {}) } await fs.unlink(path.join(Global.Path.bin, "clangd")).catch(() => {}) @@ -1041,13 +1045,13 @@ export namespace LSPServer { extensions: [".svelte"], root: NearestRoot(["package-lock.json", "bun.lockb", "bun.lock", "pnpm-lock.yaml", "yarn.lock"]), async spawn(root) { - let binary = Bun.which("svelteserver") + let binary = which("svelteserver") const args: string[] = [] if (!binary) { const js = path.join(Global.Path.bin, "node_modules", "svelte-language-server", "bin", "server.js") if (!(await Filesystem.exists(js))) { if (Flag.OPENCODE_DISABLE_LSP_DOWNLOAD) return - await Bun.spawn([BunProc.which(), "install", "svelte-language-server"], { + await Process.spawn([BunProc.which(), "install", "svelte-language-server"], { cwd: Global.Path.bin, env: { ...process.env, @@ -1081,20 +1085,20 @@ export namespace LSPServer { extensions: [".astro"], root: NearestRoot(["package-lock.json", "bun.lockb", "bun.lock", "pnpm-lock.yaml", "yarn.lock"]), async spawn(root) { - const tsserver = await Bun.resolve("typescript/lib/tsserver.js", Instance.directory).catch(() => {}) + const tsserver = Module.resolve("typescript/lib/tsserver.js", Instance.directory) if (!tsserver) { log.info("typescript not found, required for Astro language server") return } const tsdk = path.dirname(tsserver) - let binary = Bun.which("astro-ls") + let binary = which("astro-ls") const args: string[] = [] if (!binary) { const js = path.join(Global.Path.bin, "node_modules", "@astrojs", "language-server", "bin", "nodeServer.js") if (!(await Filesystem.exists(js))) { if (Flag.OPENCODE_DISABLE_LSP_DOWNLOAD) return - await Bun.spawn([BunProc.which(), "install", "@astrojs/language-server"], { + await Process.spawn([BunProc.which(), "install", "@astrojs/language-server"], { cwd: Global.Path.bin, env: { ...process.env, @@ -1129,21 +1133,41 @@ export namespace LSPServer { export const JDTLS: Info = { id: "jdtls", - root: NearestRoot(["pom.xml", "build.gradle", "build.gradle.kts", ".project", ".classpath"]), + root: async (file) => { + // Without exclusions, NearestRoot defaults to instance directory so we can't + // distinguish between a) no project found and b) project found at instance dir. + // So we can't choose the root from (potential) monorepo markers first. + // Look for potential subproject markers first while excluding potential monorepo markers. + const settingsMarkers = ["settings.gradle", "settings.gradle.kts"] + const gradleMarkers = ["gradlew", "gradlew.bat"] + const exclusionsForMonorepos = gradleMarkers.concat(settingsMarkers) + + const [projectRoot, wrapperRoot, settingsRoot] = await Promise.all([ + NearestRoot( + ["pom.xml", "build.gradle", "build.gradle.kts", ".project", ".classpath"], + exclusionsForMonorepos, + )(file), + NearestRoot(gradleMarkers, settingsMarkers)(file), + NearestRoot(settingsMarkers)(file), + ]) + + // If projectRoot is undefined we know we are in a monorepo or no project at all. + // So can safely fall through to the other roots + if (projectRoot) return projectRoot + if (wrapperRoot) return wrapperRoot + if (settingsRoot) return settingsRoot + }, extensions: [".java"], async spawn(root) { - const java = Bun.which("java") + const java = which("java") if (!java) { log.error("Java 21 or newer is required to run the JDTLS. Please install it first.") return } - const javaMajorVersion = await $`java -version` - .quiet() - .nothrow() - .then(({ stderr }) => { - const m = /"(\d+)\.\d+\.\d+"/.exec(stderr.toString()) - return !m ? undefined : parseInt(m[1]) - }) + const javaMajorVersion = await run(["java", "-version"]).then((result) => { + const m = /"(\d+)\.\d+\.\d+"/.exec(result.stderr.toString()) + return !m ? undefined : parseInt(m[1]) + }) if (javaMajorVersion == null || javaMajorVersion < 21) { log.error("JDTLS requires at least Java 21.") return @@ -1160,27 +1184,27 @@ export namespace LSPServer { const archiveName = "release.tar.gz" log.info("Downloading JDTLS archive", { url: releaseURL, dest: distPath }) - const curlResult = await $`curl -L -o ${archiveName} '${releaseURL}'`.cwd(distPath).quiet().nothrow() - if (curlResult.exitCode !== 0) { - log.error("Failed to download JDTLS", { exitCode: curlResult.exitCode, stderr: curlResult.stderr.toString() }) + const download = await fetch(releaseURL) + if (!download.ok || !download.body) { + log.error("Failed to download JDTLS", { status: download.status, statusText: download.statusText }) return } + await Filesystem.writeStream(path.join(distPath, archiveName), download.body) log.info("Extracting JDTLS archive") - const tarResult = await $`tar -xzf ${archiveName}`.cwd(distPath).quiet().nothrow() - if (tarResult.exitCode !== 0) { - log.error("Failed to extract JDTLS", { exitCode: tarResult.exitCode, stderr: tarResult.stderr.toString() }) + const tarResult = await run(["tar", "-xzf", archiveName], { cwd: distPath }) + if (tarResult.code !== 0) { + log.error("Failed to extract JDTLS", { exitCode: tarResult.code, stderr: tarResult.stderr.toString() }) return } await fs.rm(path.join(distPath, archiveName), { force: true }) log.info("JDTLS download and extraction completed") } - const jarFileName = await $`ls org.eclipse.equinox.launcher_*.jar` - .cwd(launcherDir) - .quiet() - .nothrow() - .then(({ stdout }) => stdout.toString().trim()) + const jarFileName = + (await fs.readdir(launcherDir).catch(() => [])) + .find((item) => /^org\.eclipse\.equinox\.launcher_.*\.jar$/.test(item)) + ?.trim() ?? "" const launcherJar = path.join(launcherDir, jarFileName) if (!(await pathExists(launcherJar))) { log.error(`Failed to locate the JDTLS launcher module in the installed directory: ${distPath}.`) @@ -1293,7 +1317,15 @@ export namespace LSPServer { await fs.mkdir(distPath, { recursive: true }) const archivePath = path.join(distPath, "kotlin-ls.zip") - await $`curl -L -o '${archivePath}' '${releaseURL}'`.quiet().nothrow() + const download = await fetch(releaseURL) + if (!download.ok || !download.body) { + log.error("Failed to download Kotlin Language Server", { + status: download.status, + statusText: download.statusText, + }) + return + } + await Filesystem.writeStream(archivePath, download.body) const ok = await Archive.extractZip(archivePath, distPath) .then(() => true) .catch((error) => { @@ -1303,7 +1335,7 @@ export namespace LSPServer { if (!ok) return await fs.rm(archivePath, { force: true }) if (process.platform !== "win32") { - await $`chmod +x ${launcherScript}`.quiet().nothrow() + await fs.chmod(launcherScript, 0o755).catch(() => {}) } log.info("Installed Kotlin Language Server", { path: launcherScript }) } @@ -1324,7 +1356,7 @@ export namespace LSPServer { extensions: [".yaml", ".yml"], root: NearestRoot(["package-lock.json", "bun.lockb", "bun.lock", "pnpm-lock.yaml", "yarn.lock"]), async spawn(root) { - let binary = Bun.which("yaml-language-server") + let binary = which("yaml-language-server") const args: string[] = [] if (!binary) { const js = path.join( @@ -1339,7 +1371,7 @@ export namespace LSPServer { const exists = await Filesystem.exists(js) if (!exists) { if (Flag.OPENCODE_DISABLE_LSP_DOWNLOAD) return - await Bun.spawn([BunProc.which(), "install", "yaml-language-server"], { + await Process.spawn([BunProc.which(), "install", "yaml-language-server"], { cwd: Global.Path.bin, env: { ...process.env, @@ -1380,7 +1412,7 @@ export namespace LSPServer { ]), extensions: [".lua"], async spawn(root) { - let bin = Bun.which("lua-language-server", { + let bin = which("lua-language-server", { PATH: process.env["PATH"] + path.delimiter + Global.Path.bin, }) @@ -1467,10 +1499,9 @@ export namespace LSPServer { }) if (!ok) return } else { - const ok = await $`tar -xzf ${tempPath} -C ${installDir}` - .quiet() - .then(() => true) - .catch((error) => { + const ok = await run(["tar", "-xzf", tempPath, "-C", installDir]) + .then((result) => result.code === 0) + .catch((error: unknown) => { log.error("Failed to extract lua-language-server archive", { error }) return false }) @@ -1488,11 +1519,15 @@ export namespace LSPServer { } if (platform !== "win32") { - const ok = await $`chmod +x ${bin}`.quiet().catch((error) => { - log.error("Failed to set executable permission for lua-language-server binary", { - error, + const ok = await fs + .chmod(bin, 0o755) + .then(() => true) + .catch((error: unknown) => { + log.error("Failed to set executable permission for lua-language-server binary", { + error, + }) + return false }) - }) if (!ok) return } @@ -1512,13 +1547,13 @@ export namespace LSPServer { extensions: [".php"], root: NearestRoot(["composer.json", "composer.lock", ".php-version"]), async spawn(root) { - let binary = Bun.which("intelephense") + let binary = which("intelephense") const args: string[] = [] if (!binary) { const js = path.join(Global.Path.bin, "node_modules", "intelephense", "lib", "intelephense.js") if (!(await Filesystem.exists(js))) { if (Flag.OPENCODE_DISABLE_LSP_DOWNLOAD) return - await Bun.spawn([BunProc.which(), "install", "intelephense"], { + await Process.spawn([BunProc.which(), "install", "intelephense"], { cwd: Global.Path.bin, env: { ...process.env, @@ -1556,7 +1591,7 @@ export namespace LSPServer { extensions: [".prisma"], root: NearestRoot(["schema.prisma", "prisma/schema.prisma", "prisma"], ["package.json"]), async spawn(root) { - const prisma = Bun.which("prisma") + const prisma = which("prisma") if (!prisma) { log.info("prisma not found, please install prisma") return @@ -1574,7 +1609,7 @@ export namespace LSPServer { extensions: [".dart"], root: NearestRoot(["pubspec.yaml", "analysis_options.yaml"]), async spawn(root) { - const dart = Bun.which("dart") + const dart = which("dart") if (!dart) { log.info("dart not found, please install dart first") return @@ -1592,7 +1627,7 @@ export namespace LSPServer { extensions: [".ml", ".mli"], root: NearestRoot(["dune-project", "dune-workspace", ".merlin", "opam"]), async spawn(root) { - const bin = Bun.which("ocamllsp") + const bin = which("ocamllsp") if (!bin) { log.info("ocamllsp not found, please install ocaml-lsp-server") return @@ -1609,13 +1644,13 @@ export namespace LSPServer { extensions: [".sh", ".bash", ".zsh", ".ksh"], root: async () => Instance.directory, async spawn(root) { - let binary = Bun.which("bash-language-server") + let binary = which("bash-language-server") const args: string[] = [] if (!binary) { const js = path.join(Global.Path.bin, "node_modules", "bash-language-server", "out", "cli.js") if (!(await Filesystem.exists(js))) { if (Flag.OPENCODE_DISABLE_LSP_DOWNLOAD) return - await Bun.spawn([BunProc.which(), "install", "bash-language-server"], { + await Process.spawn([BunProc.which(), "install", "bash-language-server"], { cwd: Global.Path.bin, env: { ...process.env, @@ -1648,7 +1683,7 @@ export namespace LSPServer { extensions: [".tf", ".tfvars"], root: NearestRoot([".terraform.lock.hcl", "terraform.tfstate", "*.tf"]), async spawn(root) { - let bin = Bun.which("terraform-ls", { + let bin = which("terraform-ls", { PATH: process.env["PATH"] + path.delimiter + Global.Path.bin, }) @@ -1706,7 +1741,7 @@ export namespace LSPServer { } if (platform !== "win32") { - await $`chmod +x ${bin}`.quiet().nothrow() + await fs.chmod(bin, 0o755).catch(() => {}) } log.info(`installed terraform-ls`, { bin }) @@ -1731,7 +1766,7 @@ export namespace LSPServer { extensions: [".tex", ".bib"], root: NearestRoot([".latexmkrc", "latexmkrc", ".texlabroot", "texlabroot"]), async spawn(root) { - let bin = Bun.which("texlab", { + let bin = which("texlab", { PATH: process.env["PATH"] + path.delimiter + Global.Path.bin, }) @@ -1789,7 +1824,7 @@ export namespace LSPServer { if (!ok) return } if (ext === "tar.gz") { - await $`tar -xzf ${tempPath}`.cwd(Global.Path.bin).quiet().nothrow() + await run(["tar", "-xzf", tempPath], { cwd: Global.Path.bin }) } await fs.rm(tempPath, { force: true }) @@ -1802,7 +1837,7 @@ export namespace LSPServer { } if (platform !== "win32") { - await $`chmod +x ${bin}`.quiet().nothrow() + await fs.chmod(bin, 0o755).catch(() => {}) } log.info("installed texlab", { bin }) @@ -1821,13 +1856,13 @@ export namespace LSPServer { extensions: [".dockerfile", "Dockerfile"], root: async () => Instance.directory, async spawn(root) { - let binary = Bun.which("docker-langserver") + let binary = which("docker-langserver") const args: string[] = [] if (!binary) { const js = path.join(Global.Path.bin, "node_modules", "dockerfile-language-server-nodejs", "lib", "server.js") if (!(await Filesystem.exists(js))) { if (Flag.OPENCODE_DISABLE_LSP_DOWNLOAD) return - await Bun.spawn([BunProc.which(), "install", "dockerfile-language-server-nodejs"], { + await Process.spawn([BunProc.which(), "install", "dockerfile-language-server-nodejs"], { cwd: Global.Path.bin, env: { ...process.env, @@ -1860,7 +1895,7 @@ export namespace LSPServer { extensions: [".gleam"], root: NearestRoot(["gleam.toml"]), async spawn(root) { - const gleam = Bun.which("gleam") + const gleam = which("gleam") if (!gleam) { log.info("gleam not found, please install gleam first") return @@ -1878,9 +1913,9 @@ export namespace LSPServer { extensions: [".clj", ".cljs", ".cljc", ".edn"], root: NearestRoot(["deps.edn", "project.clj", "shadow-cljs.edn", "bb.edn", "build.boot"]), async spawn(root) { - let bin = Bun.which("clojure-lsp") + let bin = which("clojure-lsp") if (!bin && process.platform === "win32") { - bin = Bun.which("clojure-lsp.exe") + bin = which("clojure-lsp.exe") } if (!bin) { log.info("clojure-lsp not found, please install clojure-lsp first") @@ -1909,7 +1944,7 @@ export namespace LSPServer { return Instance.directory }, async spawn(root) { - const nixd = Bun.which("nixd") + const nixd = which("nixd") if (!nixd) { log.info("nixd not found, please install nixd first") return @@ -1930,7 +1965,7 @@ export namespace LSPServer { extensions: [".typ", ".typc"], root: NearestRoot(["typst.toml"]), async spawn(root) { - let bin = Bun.which("tinymist", { + let bin = which("tinymist", { PATH: process.env["PATH"] + path.delimiter + Global.Path.bin, }) @@ -1994,7 +2029,7 @@ export namespace LSPServer { }) if (!ok) return } else { - await $`tar -xzf ${tempPath} --strip-components=1`.cwd(Global.Path.bin).quiet().nothrow() + await run(["tar", "-xzf", tempPath, "--strip-components=1"], { cwd: Global.Path.bin }) } await fs.rm(tempPath, { force: true }) @@ -2007,7 +2042,7 @@ export namespace LSPServer { } if (platform !== "win32") { - await $`chmod +x ${bin}`.quiet().nothrow() + await fs.chmod(bin, 0o755).catch(() => {}) } log.info("installed tinymist", { bin }) @@ -2024,7 +2059,7 @@ export namespace LSPServer { extensions: [".hs", ".lhs"], root: NearestRoot(["stack.yaml", "cabal.project", "hie.yaml", "*.cabal"]), async spawn(root) { - const bin = Bun.which("haskell-language-server-wrapper") + const bin = which("haskell-language-server-wrapper") if (!bin) { log.info("haskell-language-server-wrapper not found, please install haskell-language-server") return @@ -2042,7 +2077,7 @@ export namespace LSPServer { extensions: [".jl"], root: NearestRoot(["Project.toml", "Manifest.toml", "*.jl"]), async spawn(root) { - const julia = Bun.which("julia") + const julia = which("julia") if (!julia) { log.info("julia not found, please install julia first (https://julialang.org/downloads/)") return diff --git a/packages/opencode/src/mcp/index.ts b/packages/opencode/src/mcp/index.ts index 3c29fe03d3..e48a42a8b3 100644 --- a/packages/opencode/src/mcp/index.ts +++ b/packages/opencode/src/mcp/index.ts @@ -160,6 +160,28 @@ export namespace MCP { return typeof entry === "object" && entry !== null && "type" in entry } + async function descendants(pid: number): Promise<number[]> { + if (process.platform === "win32") return [] + const pids: number[] = [] + const queue = [pid] + while (queue.length > 0) { + const current = queue.shift()! + const proc = Bun.spawn(["pgrep", "-P", String(current)], { stdout: "pipe", stderr: "pipe" }) + const [code, out] = await Promise.all([proc.exited, new Response(proc.stdout).text()]).catch( + () => [-1, ""] as const, + ) + if (code !== 0) continue + for (const tok of out.trim().split(/\s+/)) { + const cpid = parseInt(tok, 10) + if (!isNaN(cpid) && pids.indexOf(cpid) === -1) { + pids.push(cpid) + queue.push(cpid) + } + } + } + return pids + } + const state = Instance.state( async () => { const cfg = await Config.get() @@ -196,6 +218,21 @@ export namespace MCP { } }, async (state) => { + // The MCP SDK only signals the direct child process on close. + // Servers like chrome-devtools-mcp spawn grandchild processes + // (e.g. Chrome) that the SDK never reaches, leaving them orphaned. + // Kill the full descendant tree first so the server exits promptly + // and no processes are left behind. + for (const client of Object.values(state.clients)) { + const pid = (client.transport as any)?.pid + if (typeof pid !== "number") continue + for (const dpid of await descendants(pid)) { + try { + process.kill(dpid, "SIGTERM") + } catch {} + } + } + await Promise.all( Object.values(state.clients).map((client) => client.close().catch((error) => { @@ -359,8 +396,14 @@ export namespace MCP { } catch (error) { lastError = error instanceof Error ? error : new Error(String(error)) - // Handle OAuth-specific errors - if (error instanceof UnauthorizedError) { + // Handle OAuth-specific errors. + // The SDK throws UnauthorizedError when auth() returns 'REDIRECT', + // but may also throw plain Errors when auth() fails internally + // (e.g. during discovery, registration, or state generation). + // When an authProvider is attached, treat both cases as auth-related. + const isAuthError = + error instanceof UnauthorizedError || (authProvider && lastError.message.includes("OAuth")) + if (isAuthError) { log.info("mcp server requires authentication", { key, transport: name }) // Check if this is a "needs registration" error diff --git a/packages/opencode/src/mcp/oauth-callback.ts b/packages/opencode/src/mcp/oauth-callback.ts index bb3b56f2e9..db8e621d6c 100644 --- a/packages/opencode/src/mcp/oauth-callback.ts +++ b/packages/opencode/src/mcp/oauth-callback.ts @@ -1,3 +1,4 @@ +import { createConnection } from "net" import { Log } from "../util/log" import { OAUTH_CALLBACK_PORT, OAUTH_CALLBACK_PATH } from "./oauth-provider" @@ -160,21 +161,12 @@ export namespace McpOAuthCallback { export async function isPortInUse(): Promise<boolean> { return new Promise((resolve) => { - Bun.connect({ - hostname: "127.0.0.1", - port: OAUTH_CALLBACK_PORT, - socket: { - open(socket) { - socket.end() - resolve(true) - }, - error() { - resolve(false) - }, - data() {}, - close() {}, - }, - }).catch(() => { + const socket = createConnection(OAUTH_CALLBACK_PORT, "127.0.0.1") + socket.on("connect", () => { + socket.destroy() + resolve(true) + }) + socket.on("error", () => { resolve(false) }) }) diff --git a/packages/opencode/src/mcp/oauth-provider.ts b/packages/opencode/src/mcp/oauth-provider.ts index 164b1d1f14..b4da73169e 100644 --- a/packages/opencode/src/mcp/oauth-provider.ts +++ b/packages/opencode/src/mcp/oauth-provider.ts @@ -144,10 +144,19 @@ export class McpOAuthProvider implements OAuthClientProvider { async state(): Promise<string> { const entry = await McpAuth.get(this.mcpName) - if (!entry?.oauthState) { - throw new Error(`No OAuth state saved for MCP server: ${this.mcpName}`) + if (entry?.oauthState) { + return entry.oauthState } - return entry.oauthState + + // Generate a new state if none exists — the SDK calls state() as a + // generator, not just a reader, so we need to produce a value even when + // startAuth() hasn't pre-saved one (e.g. during automatic auth on first + // connect). + const newState = Array.from(crypto.getRandomValues(new Uint8Array(32))) + .map((b) => b.toString(16).padStart(2, "0")) + .join("") + await McpAuth.updateOAuthState(this.mcpName, newState) + return newState } async invalidateCredentials(type: "all" | "client" | "tokens"): Promise<void> { diff --git a/packages/opencode/src/patch/index.ts b/packages/opencode/src/patch/index.ts index 0efeff544f..b87ad55528 100644 --- a/packages/opencode/src/patch/index.ts +++ b/packages/opencode/src/patch/index.ts @@ -79,23 +79,23 @@ export namespace Patch { const line = lines[startIdx] if (line.startsWith("*** Add File:")) { - const filePath = line.split(":", 2)[1]?.trim() + const filePath = line.slice("*** Add File:".length).trim() return filePath ? { filePath, nextIdx: startIdx + 1 } : null } if (line.startsWith("*** Delete File:")) { - const filePath = line.split(":", 2)[1]?.trim() + const filePath = line.slice("*** Delete File:".length).trim() return filePath ? { filePath, nextIdx: startIdx + 1 } : null } if (line.startsWith("*** Update File:")) { - const filePath = line.split(":", 2)[1]?.trim() + const filePath = line.slice("*** Update File:".length).trim() let movePath: string | undefined let nextIdx = startIdx + 1 // Check for move directive if (nextIdx < lines.length && lines[nextIdx].startsWith("*** Move to:")) { - movePath = lines[nextIdx].split(":", 2)[1]?.trim() + movePath = lines[nextIdx].slice("*** Move to:".length).trim() nextIdx++ } diff --git a/packages/opencode/src/plugin/codex.ts b/packages/opencode/src/plugin/codex.ts index 56931b2ed6..5c0140e570 100644 --- a/packages/opencode/src/plugin/codex.ts +++ b/packages/opencode/src/plugin/codex.ts @@ -4,6 +4,7 @@ import { Installation } from "../installation" import { Auth, OAUTH_DUMMY_KEY } from "../auth" import os from "os" import { ProviderTransform } from "@/provider/transform" +import { setTimeout as sleep } from "node:timers/promises" const log = Log.create({ service: "plugin.codex" }) @@ -361,6 +362,7 @@ export async function CodexAuthPlugin(input: PluginInput): Promise<Hooks> { "gpt-5.1-codex-max", "gpt-5.1-codex-mini", "gpt-5.2", + "gpt-5.4", "gpt-5.2-codex", "gpt-5.3-codex", "gpt-5.1-codex", @@ -602,7 +604,7 @@ export async function CodexAuthPlugin(input: PluginInput): Promise<Hooks> { return { type: "failed" as const } } - await Bun.sleep(interval + OAUTH_POLLING_SAFETY_MARGIN_MS) + await sleep(interval + OAUTH_POLLING_SAFETY_MARGIN_MS) } }, } diff --git a/packages/opencode/src/plugin/copilot.ts b/packages/opencode/src/plugin/copilot.ts index 39ea0d00d2..3945c63ce2 100644 --- a/packages/opencode/src/plugin/copilot.ts +++ b/packages/opencode/src/plugin/copilot.ts @@ -1,6 +1,7 @@ import type { Hooks, PluginInput } from "@opencode-ai/plugin" import { Installation } from "@/installation" import { iife } from "@/util/iife" +import { setTimeout as sleep } from "node:timers/promises" const CLIENT_ID = "Ov23li8tweQw6odWQebz" // Add a small safety buffer when polling to avoid hitting the server @@ -270,7 +271,7 @@ export async function CopilotAuthPlugin(input: PluginInput): Promise<Hooks> { } if (data.error === "authorization_pending") { - await Bun.sleep(deviceData.interval * 1000 + OAUTH_POLLING_SAFETY_MARGIN_MS) + await sleep(deviceData.interval * 1000 + OAUTH_POLLING_SAFETY_MARGIN_MS) continue } @@ -286,13 +287,13 @@ export async function CopilotAuthPlugin(input: PluginInput): Promise<Hooks> { newInterval = serverInterval * 1000 } - await Bun.sleep(newInterval + OAUTH_POLLING_SAFETY_MARGIN_MS) + await sleep(newInterval + OAUTH_POLLING_SAFETY_MARGIN_MS) continue } if (data.error) return { type: "failed" as const } - await Bun.sleep(deviceData.interval * 1000 + OAUTH_POLLING_SAFETY_MARGIN_MS) + await sleep(deviceData.interval * 1000 + OAUTH_POLLING_SAFETY_MARGIN_MS) continue } }, diff --git a/packages/opencode/src/plugin/index.ts b/packages/opencode/src/plugin/index.ts index e65d21bfd6..1c129f6082 100644 --- a/packages/opencode/src/plugin/index.ts +++ b/packages/opencode/src/plugin/index.ts @@ -25,8 +25,7 @@ export namespace Plugin { const client = createOpencodeClient({ baseUrl: "http://localhost:4096", directory: Instance.directory, - // @ts-ignore - fetch type incompatibility - fetch: async (...args) => Server.App().fetch(...args), + fetch: async (...args) => Server.Default().fetch(...args), }) const config = await Config.get() const hooks: Hooks[] = [] @@ -35,7 +34,9 @@ export namespace Plugin { project: Instance.project, worktree: Instance.worktree, directory: Instance.directory, - serverUrl: Server.url(), + get serverUrl(): URL { + throw new Error("Server URL is no longer supported in plugins") + }, $: Bun.$, } diff --git a/packages/opencode/src/project/instance.ts b/packages/opencode/src/project/instance.ts index 98031f18d3..df44a3a229 100644 --- a/packages/opencode/src/project/instance.ts +++ b/packages/opencode/src/project/instance.ts @@ -18,24 +18,61 @@ const disposal = { all: undefined as Promise<void> | undefined, } +function emit(directory: string) { + GlobalBus.emit("event", { + directory, + payload: { + type: "server.instance.disposed", + properties: { + directory, + }, + }, + }) +} + +function boot(input: { directory: string; init?: () => Promise<any>; project?: Project.Info; worktree?: string }) { + return iife(async () => { + const ctx = + input.project && input.worktree + ? { + directory: input.directory, + worktree: input.worktree, + project: input.project, + } + : await Project.fromDirectory(input.directory).then(({ project, sandbox }) => ({ + directory: input.directory, + worktree: sandbox, + project, + })) + await context.provide(ctx, async () => { + await input.init?.() + }) + return ctx + }) +} + +function track(directory: string, next: Promise<Context>) { + const task = next.catch((error) => { + if (cache.get(directory) === task) cache.delete(directory) + throw error + }) + cache.set(directory, task) + return task +} + export const Instance = { async provide<R>(input: { directory: string; init?: () => Promise<any>; fn: () => R }): Promise<R> { - let existing = cache.get(input.directory) + const directory = Filesystem.resolve(input.directory) + let existing = cache.get(directory) if (!existing) { - Log.Default.info("creating instance", { directory: input.directory }) - existing = iife(async () => { - const { project, sandbox } = await Project.fromDirectory(input.directory) - const ctx = { - directory: input.directory, - worktree: sandbox, - project, - } - await context.provide(ctx, async () => { - await input.init?.() - }) - return ctx - }) - cache.set(input.directory, existing) + Log.Default.info("creating instance", { directory }) + existing = track( + directory, + boot({ + directory, + init: input.init, + }), + ) } const ctx = await existing return context.provide(ctx, async () => { @@ -66,19 +103,20 @@ export const Instance = { state<S>(init: () => S, dispose?: (state: Awaited<S>) => Promise<void>): () => S { return State.create(() => Instance.directory, init, dispose) }, + async reload(input: { directory: string; init?: () => Promise<any>; project?: Project.Info; worktree?: string }) { + const directory = Filesystem.resolve(input.directory) + Log.Default.info("reloading instance", { directory }) + await State.dispose(directory) + cache.delete(directory) + const next = track(directory, boot({ ...input, directory })) + emit(directory) + return await next + }, async dispose() { Log.Default.info("disposing instance", { directory: Instance.directory }) await State.dispose(Instance.directory) cache.delete(Instance.directory) - GlobalBus.emit("event", { - directory: Instance.directory, - payload: { - type: "server.instance.disposed", - properties: { - directory: Instance.directory, - }, - }, - }) + emit(Instance.directory) }, async disposeAll() { if (disposal.all) return disposal.all diff --git a/packages/opencode/src/project/project.ts b/packages/opencode/src/project/project.ts index e49d968613..e1fff1a147 100644 --- a/packages/opencode/src/project/project.ts +++ b/packages/opencode/src/project/project.ts @@ -14,9 +14,23 @@ import { GlobalBus } from "@/bus/global" import { existsSync } from "fs" import { git } from "../util/git" import { Glob } from "../util/glob" +import { which } from "../util/which" export namespace Project { const log = Log.create({ service: "project" }) + + function gitpath(cwd: string, name: string) { + if (!name) return cwd + // git output includes trailing newlines; keep path whitespace intact. + name = name.replace(/[\r\n]+$/, "") + if (!name) return cwd + + name = Filesystem.windowsPath(name) + + if (path.isAbsolute(name)) return path.normalize(name) + return path.resolve(cwd, name) + } + export const Info = z .object({ id: z.string(), @@ -84,7 +98,7 @@ export namespace Project { if (dotgit) { let sandbox = path.dirname(dotgit) - const gitBinary = Bun.which("git") + const gitBinary = which("git") // cached id calculation let id = await Filesystem.readText(path.join(dotgit, "opencode")) @@ -125,7 +139,7 @@ export namespace Project { id = roots[0] if (id) { - void Filesystem.write(path.join(dotgit, "opencode"), id).catch(() => undefined) + await Filesystem.write(path.join(dotgit, "opencode"), id).catch(() => undefined) } } @@ -141,7 +155,7 @@ export namespace Project { const top = await git(["rev-parse", "--show-toplevel"], { cwd: sandbox, }) - .then(async (result) => path.resolve(sandbox, (await result.text()).trim())) + .then(async (result) => gitpath(sandbox, await result.text())) .catch(() => undefined) if (!top) { @@ -159,9 +173,9 @@ export namespace Project { cwd: sandbox, }) .then(async (result) => { - const dirname = path.dirname((await result.text()).trim()) - if (dirname === ".") return sandbox - return dirname + const common = gitpath(sandbox, await result.text()) + // Avoid going to parent of sandbox when git-common-dir is empty. + return common === sandbox ? sandbox : path.dirname(common) }) .catch(() => undefined) @@ -333,6 +347,21 @@ export namespace Project { return fromRow(row) } + export async function initGit(input: { directory: string; project: Info }) { + if (input.project.vcs === "git") return input.project + if (!which("git")) throw new Error("Git is not installed") + + const result = await git(["init", "--quiet"], { + cwd: input.directory, + }) + if (result.exitCode !== 0) { + const text = result.stderr.toString().trim() || result.text().trim() + throw new Error(text || "Failed to initialize git repository") + } + + return (await fromDirectory(input.directory)).project + } + export const update = fn( z.object({ projectID: z.string(), diff --git a/packages/opencode/src/project/vcs.ts b/packages/opencode/src/project/vcs.ts index e434b5f8c3..34d5905431 100644 --- a/packages/opencode/src/project/vcs.ts +++ b/packages/opencode/src/project/vcs.ts @@ -1,11 +1,11 @@ import { BusEvent } from "@/bus/bus-event" import { Bus } from "@/bus" -import { $ } from "bun" import path from "path" import z from "zod" import { Log } from "@/util/log" import { Instance } from "./instance" import { FileWatcher } from "@/file/watcher" +import { git } from "@/util/git" const log = Log.create({ service: "vcs" }) @@ -29,13 +29,13 @@ export namespace Vcs { export type Info = z.infer<typeof Info> async function currentBranch() { - return $`git rev-parse --abbrev-ref HEAD` - .quiet() - .nothrow() - .cwd(Instance.worktree) - .text() - .then((x) => x.trim()) - .catch(() => undefined) + const result = await git(["rev-parse", "--abbrev-ref", "HEAD"], { + cwd: Instance.worktree, + }) + if (result.exitCode !== 0) return + const text = result.text().trim() + if (!text) return + return text } const state = Instance.state( diff --git a/packages/opencode/src/provider/error.ts b/packages/opencode/src/provider/error.ts index 0db03576e9..945d29f97f 100644 --- a/packages/opencode/src/provider/error.ts +++ b/packages/opencode/src/provider/error.ts @@ -19,6 +19,7 @@ export namespace ProviderError { /context window exceeds limit/i, // MiniMax /exceeded model token limit/i, // Kimi For Coding, Moonshot /context[_ ]length[_ ]exceeded/i, // Generic fallback + /request entity too large/i, // HTTP 413 ] function isOpenAiErrorRetryable(e: APICallError) { @@ -76,6 +77,18 @@ export namespace ProviderError { } } catch {} + // If responseBody is HTML (e.g. from a gateway or proxy error page), + // provide a human-readable message instead of dumping raw markup + if (/^\s*<!doctype|^\s*<html/i.test(e.responseBody)) { + if (e.statusCode === 401) { + return "Unauthorized: request was blocked by a gateway or proxy. Your authentication token may be missing or expired — try running `opencode auth login <your provider URL>` to re-authenticate." + } + if (e.statusCode === 403) { + return "Forbidden: request was blocked by a gateway or proxy. You may not have permission to access this resource — check your account and provider settings." + } + return msg + } + return `${msg}: ${e.responseBody}` }).trim() } @@ -165,7 +178,7 @@ export namespace ProviderError { export function parseAPICallError(input: { providerID: string; error: APICallError }): ParsedAPICallError { const m = message(input.providerID, input.error) - if (isOverflow(m)) { + if (isOverflow(m) || input.error.statusCode === 413) { return { type: "context_overflow", message: m, diff --git a/packages/opencode/src/provider/provider.ts b/packages/opencode/src/provider/provider.ts index 9759bc316f..ea1b7863f8 100644 --- a/packages/opencode/src/provider/provider.ts +++ b/packages/opencode/src/provider/provider.ts @@ -6,9 +6,10 @@ import { mapValues, mergeDeep, omit, pickBy, sortBy } from "remeda" import { NoSuchModelError, type Provider as SDK } from "ai" import { Log } from "../util/log" import { BunProc } from "../bun" +import { Hash } from "../util/hash" import { Plugin } from "../plugin" -import { ModelsDev } from "./models" import { NamedError } from "@opencode-ai/util/error" +import { ModelsDev } from "./models" import { Auth } from "../auth" import { Env } from "../env" import { Instance } from "../project/instance" @@ -487,6 +488,7 @@ export namespace Provider { const aiGatewayHeaders = { "User-Agent": `opencode/${Installation.VERSION} gitlab-ai-provider/${GITLAB_PROVIDER_VERSION} (${os.platform()} ${os.release()}; ${os.arch()})`, + "anthropic-beta": "context-1m-2025-08-07", ...(providerConfig?.options?.aiGatewayHeaders || {}), } @@ -563,7 +565,28 @@ export namespace Provider { const { createAiGateway } = await import("ai-gateway-provider") const { createUnified } = await import("ai-gateway-provider/providers/unified") - const aigateway = createAiGateway({ accountId, gateway, apiKey: apiToken }) + const metadata = iife(() => { + if (input.options?.metadata) return input.options.metadata + try { + return JSON.parse(input.options?.headers?.["cf-aig-metadata"]) + } catch { + return undefined + } + }) + const opts = { + metadata, + cacheTtl: input.options?.cacheTtl, + cacheKey: input.options?.cacheKey, + skipCache: input.options?.skipCache, + collectLog: input.options?.collectLog, + } + + const aigateway = createAiGateway({ + accountId, + gateway, + apiKey: apiToken, + ...(Object.values(opts).some((v) => v !== undefined) ? { options: opts } : {}), + }) const unified = createUnified() return { @@ -784,7 +807,7 @@ export namespace Provider { const modelLoaders: { [providerID: string]: CustomModelLoader } = {} - const sdk = new Map<number, SDK>() + const sdk = new Map<string, SDK>() log.info("init") @@ -1075,7 +1098,7 @@ export namespace Provider { ...model.headers, } - const key = Bun.hash.xxHash32(JSON.stringify({ providerID: model.providerID, npm: model.api.npm, options })) + const key = Hash.fast(JSON.stringify({ providerID: model.providerID, npm: model.api.npm, options })) const existing = s.sdk.get(key) if (existing) return existing @@ -1277,12 +1300,6 @@ export namespace Provider { } } - // Check if opencode provider is available before using it - const opencodeProvider = await state().then((state) => state.providers["opencode"]) - if (opencodeProvider && opencodeProvider.models["gpt-5-nano"]) { - return getModel("opencode", "gpt-5-nano") - } - return undefined } diff --git a/packages/opencode/src/provider/transform.ts b/packages/opencode/src/provider/transform.ts index b659799c1b..471da03cbc 100644 --- a/packages/opencode/src/provider/transform.ts +++ b/packages/opencode/src/provider/transform.ts @@ -440,7 +440,9 @@ export namespace ProviderTransform { const copilotEfforts = iife(() => { if (id.includes("5.1-codex-max") || id.includes("5.2") || id.includes("5.3")) return [...WIDELY_SUPPORTED_EFFORTS, "xhigh"] - return WIDELY_SUPPORTED_EFFORTS + const arr = [...WIDELY_SUPPORTED_EFFORTS] + if (id.includes("gpt-5") && model.release_date >= "2025-12-04") arr.push("xhigh") + return arr }) return Object.fromEntries( copilotEfforts.map((effort) => [ @@ -897,6 +899,31 @@ export namespace ProviderTransform { // Convert integer enums to string enums for Google/Gemini if (model.providerID === "google" || model.api.id.includes("gemini")) { + const isPlainObject = (node: unknown): node is Record<string, any> => + typeof node === "object" && node !== null && !Array.isArray(node) + const hasCombiner = (node: unknown) => + isPlainObject(node) && (Array.isArray(node.anyOf) || Array.isArray(node.oneOf) || Array.isArray(node.allOf)) + const hasSchemaIntent = (node: unknown) => { + if (!isPlainObject(node)) return false + if (hasCombiner(node)) return true + return [ + "type", + "properties", + "items", + "prefixItems", + "enum", + "const", + "$ref", + "additionalProperties", + "patternProperties", + "required", + "not", + "if", + "then", + "else", + ].some((key) => key in node) + } + const sanitizeGemini = (obj: any): any => { if (obj === null || typeof obj !== "object") { return obj @@ -927,19 +954,18 @@ export namespace ProviderTransform { result.required = result.required.filter((field: any) => field in result.properties) } - if (result.type === "array") { + if (result.type === "array" && !hasCombiner(result)) { if (result.items == null) { result.items = {} } - // Ensure items has at least a type if it's an empty object - // This handles nested arrays like { type: "array", items: { type: "array", items: {} } } - if (typeof result.items === "object" && !Array.isArray(result.items) && !result.items.type) { + // Ensure items has a type only when it's still schema-empty. + if (isPlainObject(result.items) && !hasSchemaIntent(result.items)) { result.items.type = "string" } } // Remove properties/required from non-object types (Gemini rejects these) - if (result.type && result.type !== "object") { + if (result.type && result.type !== "object" && !hasCombiner(result)) { delete result.properties delete result.required } diff --git a/packages/opencode/src/pty/index.ts b/packages/opencode/src/pty/index.ts index 33083485b5..1c27d5b847 100644 --- a/packages/opencode/src/pty/index.ts +++ b/packages/opencode/src/pty/index.ts @@ -23,60 +23,6 @@ export namespace Pty { close: (code?: number, reason?: string) => void } - type Subscriber = { - id: number - token: unknown - } - - const sockets = new WeakMap<object, number>() - const owners = new WeakMap<object, string>() - let socketCounter = 0 - - const tagSocket = (ws: Socket) => { - if (!ws || typeof ws !== "object") return - const next = (socketCounter = (socketCounter + 1) % Number.MAX_SAFE_INTEGER) - sockets.set(ws, next) - return next - } - - const token = (ws: Socket) => { - const data = ws.data - if (data === undefined) return - if (data === null) return - if (typeof data !== "object") return data - - const id = (data as { connId?: unknown }).connId - if (typeof id === "number" || typeof id === "string") return id - - const href = (data as { href?: unknown }).href - if (typeof href === "string") return href - - const url = (data as { url?: unknown }).url - if (typeof url === "string") return url - if (url && typeof url === "object") { - const href = (url as { href?: unknown }).href - if (typeof href === "string") return href - return url - } - - const events = (data as { events?: unknown }).events - if (typeof events === "number" || typeof events === "string") return events - if (events && typeof events === "object") { - const id = (events as { connId?: unknown }).connId - if (typeof id === "number" || typeof id === "string") return id - - const id2 = (events as { connection?: unknown }).connection - if (typeof id2 === "number" || typeof id2 === "string") return id2 - - const id3 = (events as { id?: unknown }).id - if (typeof id3 === "number" || typeof id3 === "string") return id3 - - return events - } - - return data - } - // WebSocket control frame: 0x00 + UTF-8 JSON. const meta = (cursor: number) => { const json = JSON.stringify({ cursor }) @@ -141,7 +87,7 @@ export namespace Pty { buffer: string bufferCursor: number cursor: number - subscribers: Map<Socket, Subscriber> + subscribers: Map<unknown, Socket> } const state = Instance.state( @@ -151,9 +97,9 @@ export namespace Pty { try { session.process.kill() } catch {} - for (const ws of session.subscribers.keys()) { + for (const [key, ws] of session.subscribers.entries()) { try { - ws.close() + if (ws.data === key) ws.close() } catch { // ignore } @@ -224,26 +170,21 @@ export namespace Pty { ptyProcess.onData((chunk) => { session.cursor += chunk.length - for (const [ws, sub] of session.subscribers) { + for (const [key, ws] of session.subscribers.entries()) { if (ws.readyState !== 1) { - session.subscribers.delete(ws) + session.subscribers.delete(key) continue } - if (typeof ws === "object" && sockets.get(ws) !== sub.id) { - session.subscribers.delete(ws) - continue - } - - if (token(ws) !== sub.token) { - session.subscribers.delete(ws) + if (ws.data !== key) { + session.subscribers.delete(key) continue } try { ws.send(chunk) } catch { - session.subscribers.delete(ws) + session.subscribers.delete(key) } } @@ -254,18 +195,11 @@ export namespace Pty { session.bufferCursor += excess }) ptyProcess.onExit(({ exitCode }) => { + if (session.info.status === "exited") return log.info("session exited", { id, exitCode }) session.info.status = "exited" - for (const ws of session.subscribers.keys()) { - try { - ws.close() - } catch { - // ignore - } - } - session.subscribers.clear() Bus.publish(Event.Exited, { id, exitCode }) - state().delete(id) + remove(id) }) Bus.publish(Event.Created, { info }) return info @@ -287,19 +221,19 @@ export namespace Pty { export async function remove(id: string) { const session = state().get(id) if (!session) return + state().delete(id) log.info("removing session", { id }) try { session.process.kill() } catch {} - for (const ws of session.subscribers.keys()) { + for (const [key, ws] of session.subscribers.entries()) { try { - ws.close() + if (ws.data === key) ws.close() } catch { // ignore } } session.subscribers.clear() - state().delete(id) Bus.publish(Event.Deleted, { id }) } @@ -325,23 +259,16 @@ export namespace Pty { } log.info("client connected to session", { id }) - const socketId = tagSocket(ws) - if (socketId === undefined) { - ws.close() - return - } + // Use ws.data as the unique key for this connection lifecycle. + // If ws.data is undefined, fallback to ws object. + const connectionKey = ws.data && typeof ws.data === "object" ? ws.data : ws - const previous = owners.get(ws) - if (previous && previous !== id) { - state().get(previous)?.subscribers.delete(ws) - } - - owners.set(ws, id) - session.subscribers.set(ws, { id: socketId, token: token(ws) }) + // Optionally cleanup if the key somehow exists + session.subscribers.delete(connectionKey) + session.subscribers.set(connectionKey, ws) const cleanup = () => { - session.subscribers.delete(ws) - if (owners.get(ws) === id) owners.delete(ws) + session.subscribers.delete(connectionKey) } const start = session.bufferCursor diff --git a/packages/opencode/src/server/routes/experimental.ts b/packages/opencode/src/server/routes/experimental.ts index 8d156c03d8..98c7ece105 100644 --- a/packages/opencode/src/server/routes/experimental.ts +++ b/packages/opencode/src/server/routes/experimental.ts @@ -10,6 +10,7 @@ import { Session } from "../../session" import { zodToJsonSchema } from "zod-to-json-schema" import { errors } from "../error" import { lazy } from "../../util/lazy" +import { WorkspaceRoutes } from "./workspace" export const ExperimentalRoutes = lazy(() => new Hono() @@ -87,6 +88,7 @@ export const ExperimentalRoutes = lazy(() => ) }, ) + .route("/workspace", WorkspaceRoutes()) .post( "/worktree", describeRoute({ diff --git a/packages/opencode/src/server/routes/project.ts b/packages/opencode/src/server/routes/project.ts index 81092284de..85314df937 100644 --- a/packages/opencode/src/server/routes/project.ts +++ b/packages/opencode/src/server/routes/project.ts @@ -6,6 +6,7 @@ import { Project } from "../../project/project" import z from "zod" import { errors } from "../error" import { lazy } from "../../util/lazy" +import { InstanceBootstrap } from "../../project/bootstrap" export const ProjectRoutes = lazy(() => new Hono() @@ -52,6 +53,40 @@ export const ProjectRoutes = lazy(() => return c.json(Instance.project) }, ) + .post( + "/git/init", + describeRoute({ + summary: "Initialize git repository", + description: "Create a git repository for the current project and return the refreshed project info.", + operationId: "project.initGit", + responses: { + 200: { + description: "Project information after git initialization", + content: { + "application/json": { + schema: resolver(Project.Info), + }, + }, + }, + }, + }), + async (c) => { + const dir = Instance.directory + const prev = Instance.project + const next = await Project.initGit({ + directory: dir, + project: prev, + }) + if (next.id === prev.id && next.vcs === prev.vcs && next.worktree === prev.worktree) return c.json(next) + await Instance.reload({ + directory: dir, + worktree: dir, + project: next, + init: InstanceBootstrap, + }) + return c.json(next) + }, + ) .patch( "/:projectID", describeRoute({ diff --git a/packages/opencode/src/server/routes/session.ts b/packages/opencode/src/server/routes/session.ts index 1195529e06..12938aeaba 100644 --- a/packages/opencode/src/server/routes/session.ts +++ b/packages/opencode/src/server/routes/session.ts @@ -618,6 +618,42 @@ export const SessionRoutes = lazy(() => return c.json(message) }, ) + .delete( + "/:sessionID/message/:messageID", + describeRoute({ + summary: "Delete message", + description: + "Permanently delete a specific message (and all of its parts) from a session. This does not revert any file changes that may have been made while processing the message.", + operationId: "session.deleteMessage", + responses: { + 200: { + description: "Successfully deleted message", + content: { + "application/json": { + schema: resolver(z.boolean()), + }, + }, + }, + ...errors(400, 404), + }, + }), + validator( + "param", + z.object({ + sessionID: z.string().meta({ description: "Session ID" }), + messageID: z.string().meta({ description: "Message ID" }), + }), + ), + async (c) => { + const params = c.req.valid("param") + SessionPrompt.assertNotBusy(params.sessionID) + await Session.removeMessage({ + sessionID: params.sessionID, + messageID: params.messageID, + }) + return c.json(true) + }, + ) .delete( "/:sessionID/message/:messageID/part/:partID", describeRoute({ diff --git a/packages/opencode/src/server/routes/workspace.ts b/packages/opencode/src/server/routes/workspace.ts new file mode 100644 index 0000000000..cd2d844aed --- /dev/null +++ b/packages/opencode/src/server/routes/workspace.ts @@ -0,0 +1,94 @@ +import { Hono } from "hono" +import { describeRoute, resolver, validator } from "hono-openapi" +import z from "zod" +import { Workspace } from "../../control-plane/workspace" +import { Instance } from "../../project/instance" +import { errors } from "../error" +import { lazy } from "../../util/lazy" + +export const WorkspaceRoutes = lazy(() => + new Hono() + .post( + "/", + describeRoute({ + summary: "Create workspace", + description: "Create a workspace for the current project.", + operationId: "experimental.workspace.create", + responses: { + 200: { + description: "Workspace created", + content: { + "application/json": { + schema: resolver(Workspace.Info), + }, + }, + }, + ...errors(400), + }, + }), + validator( + "json", + Workspace.create.schema.omit({ + projectID: true, + }), + ), + async (c) => { + const body = c.req.valid("json") + const workspace = await Workspace.create({ + projectID: Instance.project.id, + ...body, + }) + return c.json(workspace) + }, + ) + .get( + "/", + describeRoute({ + summary: "List workspaces", + description: "List all workspaces.", + operationId: "experimental.workspace.list", + responses: { + 200: { + description: "Workspaces", + content: { + "application/json": { + schema: resolver(z.array(Workspace.Info)), + }, + }, + }, + }, + }), + async (c) => { + return c.json(Workspace.list(Instance.project)) + }, + ) + .delete( + "/:id", + describeRoute({ + summary: "Remove workspace", + description: "Remove an existing workspace.", + operationId: "experimental.workspace.remove", + responses: { + 200: { + description: "Workspace removed", + content: { + "application/json": { + schema: resolver(Workspace.Info.optional()), + }, + }, + }, + ...errors(400), + }, + }), + validator( + "param", + z.object({ + id: Workspace.Info.shape.id, + }), + ), + async (c) => { + const { id } = c.req.valid("param") + return c.json(await Workspace.remove(id)) + }, + ), +) diff --git a/packages/opencode/src/server/server.ts b/packages/opencode/src/server/server.ts index 9fba9c1fe1..3d435c8c99 100644 --- a/packages/opencode/src/server/server.ts +++ b/packages/opencode/src/server/server.ts @@ -21,6 +21,8 @@ import { Auth } from "../auth" import { Flag } from "../flag/flag" import { Command } from "../command" import { Global } from "../global" +import { WorkspaceContext } from "../control-plane/workspace-context" +import { WorkspaceRouterMiddleware } from "../control-plane/workspace-router-middleware" import { ProjectRoutes } from "./routes/project" import { SessionRoutes } from "./routes/session" import { PtyRoutes } from "./routes/pty" @@ -29,17 +31,18 @@ import { FileRoutes } from "./routes/file" import { ConfigRoutes } from "./routes/config" import { ExperimentalRoutes } from "./routes/experimental" import { ProviderRoutes } from "./routes/provider" -import { lazy } from "../util/lazy" import { InstanceBootstrap } from "../project/bootstrap" import { NotFoundError } from "../storage/db" import type { ContentfulStatusCode } from "hono/utils/http-status" import { websocket } from "hono/bun" import { HTTPException } from "hono/http-exception" import { errors } from "./error" +import { Filesystem } from "@/util/filesystem" import { QuestionRoutes } from "./routes/question" import { PermissionRoutes } from "./routes/permission" import { GlobalRoutes } from "./routes/global" import { MDNS } from "./mdns" +import { lazy } from "@/util/lazy" // @ts-ignore This global is needed to prevent ai-sdk from logging warnings to stdout https://github.com/vercel/ai/blob/2dc67e0ef538307f21368db32d5a12345d98831b/packages/ai/src/logger/log-warnings.ts#L85 globalThis.AI_SDK_LOG_WARNINGS = false @@ -47,520 +50,529 @@ globalThis.AI_SDK_LOG_WARNINGS = false export namespace Server { const log = Log.create({ service: "server" }) - let _url: URL | undefined - let _corsWhitelist: string[] = [] + export const Default = lazy(() => createApp({})) - export function url(): URL { - return _url ?? new URL("http://localhost:4096") - } - - const app = new Hono() - export const App: () => Hono = lazy( - () => - // TODO: Break server.ts into smaller route files to fix type inference - app - .onError((err, c) => { - log.error("failed", { - error: err, - }) - if (err instanceof NamedError) { - let status: ContentfulStatusCode - if (err instanceof NotFoundError) status = 404 - else if (err instanceof Provider.ModelNotFoundError) status = 400 - else if (err.name.startsWith("Worktree")) status = 400 - else status = 500 - return c.json(err.toObject(), { status }) - } - if (err instanceof HTTPException) return err.getResponse() - const message = err instanceof Error && err.stack ? err.stack : err.toString() - return c.json(new NamedError.Unknown({ message }).toObject(), { - status: 500, - }) + export const createApp = (opts: { cors?: string[] }): Hono => { + const app = new Hono() + return app + .onError((err, c) => { + log.error("failed", { + error: err, }) - .use((c, next) => { - // Allow CORS preflight requests to succeed without auth. - // Browser clients sending Authorization headers will preflight with OPTIONS. - if (c.req.method === "OPTIONS") return next() - const password = Flag.OPENCODE_SERVER_PASSWORD - if (!password) return next() - const username = Flag.OPENCODE_SERVER_USERNAME ?? "opencode" - return basicAuth({ username, password })(c, next) + if (err instanceof NamedError) { + let status: ContentfulStatusCode + if (err instanceof NotFoundError) status = 404 + else if (err instanceof Provider.ModelNotFoundError) status = 400 + else if (err.name.startsWith("Worktree")) status = 400 + else status = 500 + return c.json(err.toObject(), { status }) + } + if (err instanceof HTTPException) return err.getResponse() + const message = err instanceof Error && err.stack ? err.stack : err.toString() + return c.json(new NamedError.Unknown({ message }).toObject(), { + status: 500, }) - .use(async (c, next) => { - const skipLogging = c.req.path === "/log" - if (!skipLogging) { - log.info("request", { - method: c.req.method, - path: c.req.path, - }) - } - const timer = log.time("request", { + }) + .use((c, next) => { + // Allow CORS preflight requests to succeed without auth. + // Browser clients sending Authorization headers will preflight with OPTIONS. + if (c.req.method === "OPTIONS") return next() + const password = Flag.OPENCODE_SERVER_PASSWORD + if (!password) return next() + const username = Flag.OPENCODE_SERVER_USERNAME ?? "opencode" + return basicAuth({ username, password })(c, next) + }) + .use(async (c, next) => { + const skipLogging = c.req.path === "/log" + if (!skipLogging) { + log.info("request", { method: c.req.method, path: c.req.path, }) - await next() - if (!skipLogging) { - timer.stop() - } + } + const timer = log.time("request", { + method: c.req.method, + path: c.req.path, }) - .use( - cors({ - origin(input) { - if (!input) return + await next() + if (!skipLogging) { + timer.stop() + } + }) + .use( + cors({ + origin(input) { + if (!input) return - if (input.startsWith("http://localhost:")) return input - if (input.startsWith("http://127.0.0.1:")) return input - if ( - input === "tauri://localhost" || - input === "http://tauri.localhost" || - input === "https://tauri.localhost" - ) - return input + if (input.startsWith("http://localhost:")) return input + if (input.startsWith("http://127.0.0.1:")) return input + if ( + input === "tauri://localhost" || + input === "http://tauri.localhost" || + input === "https://tauri.localhost" + ) + return input - // *.opencode.ai (https only, adjust if needed) - if (/^https:\/\/([a-z0-9-]+\.)*opencode\.ai$/.test(input)) { - return input - } - if (_corsWhitelist.includes(input)) { - return input - } + // *.opencode.ai (https only, adjust if needed) + if (/^https:\/\/([a-z0-9-]+\.)*opencode\.ai$/.test(input)) { + return input + } + if (opts?.cors?.includes(input)) { + return input + } - return - }, - }), - ) - .route("/global", GlobalRoutes()) - .put( - "/auth/:providerID", - describeRoute({ - summary: "Set auth credentials", - description: "Set authentication credentials", - operationId: "auth.set", - responses: { - 200: { - description: "Successfully set authentication credentials", - content: { - "application/json": { - schema: resolver(z.boolean()), - }, + return + }, + }), + ) + .route("/global", GlobalRoutes()) + .put( + "/auth/:providerID", + describeRoute({ + summary: "Set auth credentials", + description: "Set authentication credentials", + operationId: "auth.set", + responses: { + 200: { + description: "Successfully set authentication credentials", + content: { + "application/json": { + schema: resolver(z.boolean()), }, }, - ...errors(400), }, - }), - validator( - "param", - z.object({ - providerID: z.string(), - }), - ), - validator("json", Auth.Info), - async (c) => { - const providerID = c.req.valid("param").providerID - const info = c.req.valid("json") - await Auth.set(providerID, info) - return c.json(true) + ...errors(400), }, - ) - .delete( - "/auth/:providerID", - describeRoute({ - summary: "Remove auth credentials", - description: "Remove authentication credentials", - operationId: "auth.remove", - responses: { - 200: { - description: "Successfully removed authentication credentials", - content: { - "application/json": { - schema: resolver(z.boolean()), - }, + }), + validator( + "param", + z.object({ + providerID: z.string(), + }), + ), + validator("json", Auth.Info), + async (c) => { + const providerID = c.req.valid("param").providerID + const info = c.req.valid("json") + await Auth.set(providerID, info) + return c.json(true) + }, + ) + .delete( + "/auth/:providerID", + describeRoute({ + summary: "Remove auth credentials", + description: "Remove authentication credentials", + operationId: "auth.remove", + responses: { + 200: { + description: "Successfully removed authentication credentials", + content: { + "application/json": { + schema: resolver(z.boolean()), }, }, - ...errors(400), }, - }), - validator( - "param", - z.object({ - providerID: z.string(), - }), - ), - async (c) => { - const providerID = c.req.valid("param").providerID - await Auth.remove(providerID) - return c.json(true) + ...errors(400), }, - ) - .use(async (c, next) => { - if (c.req.path === "/log") return next() - const raw = c.req.query("directory") || c.req.header("x-opencode-directory") || process.cwd() - const directory = (() => { + }), + validator( + "param", + z.object({ + providerID: z.string(), + }), + ), + async (c) => { + const providerID = c.req.valid("param").providerID + await Auth.remove(providerID) + return c.json(true) + }, + ) + .use(async (c, next) => { + if (c.req.path === "/log") return next() + const workspaceID = c.req.query("workspace") || c.req.header("x-opencode-workspace") + const raw = c.req.query("directory") || c.req.header("x-opencode-directory") || process.cwd() + const directory = Filesystem.resolve( + (() => { try { return decodeURIComponent(raw) } catch { return raw } - })() - return Instance.provide({ - directory, - init: InstanceBootstrap, - async fn() { - return next() - }, - }) + })(), + ) + + return WorkspaceContext.provide({ + workspaceID, + async fn() { + return Instance.provide({ + directory, + init: InstanceBootstrap, + async fn() { + return next() + }, + }) + }, }) - .get( - "/doc", - openAPIRouteHandler(app, { - documentation: { - info: { - title: "opencode", - version: "0.0.3", - description: "opencode api", - }, - openapi: "3.1.1", + }) + .use(WorkspaceRouterMiddleware) + .get( + "/doc", + openAPIRouteHandler(app, { + documentation: { + info: { + title: "opencode", + version: "0.0.3", + description: "opencode api", }, - }), - ) - .use(validator("query", z.object({ directory: z.string().optional() }))) - .route("/project", ProjectRoutes()) - .route("/pty", PtyRoutes()) - .route("/config", ConfigRoutes()) - .route("/experimental", ExperimentalRoutes()) - .route("/session", SessionRoutes()) - .route("/permission", PermissionRoutes()) - .route("/question", QuestionRoutes()) - .route("/provider", ProviderRoutes()) - .route("/", FileRoutes()) - .route("/mcp", McpRoutes()) - .route("/tui", TuiRoutes()) - .post( - "/instance/dispose", - describeRoute({ - summary: "Dispose instance", - description: "Clean up and dispose the current OpenCode instance, releasing all resources.", - operationId: "instance.dispose", - responses: { - 200: { - description: "Instance disposed", - content: { - "application/json": { - schema: resolver(z.boolean()), - }, - }, - }, - }, - }), - async (c) => { - await Instance.dispose() - return c.json(true) + openapi: "3.1.1", }, - ) - .get( - "/path", - describeRoute({ - summary: "Get paths", - description: - "Retrieve the current working directory and related path information for the OpenCode instance.", - operationId: "path.get", - responses: { - 200: { - description: "Path", - content: { - "application/json": { - schema: resolver( - z - .object({ - home: z.string(), - state: z.string(), - config: z.string(), - worktree: z.string(), - directory: z.string(), - }) - .meta({ - ref: "Path", - }), - ), - }, + }), + ) + .use( + validator( + "query", + z.object({ + directory: z.string().optional(), + workspace: z.string().optional(), + }), + ), + ) + .route("/project", ProjectRoutes()) + .route("/pty", PtyRoutes()) + .route("/config", ConfigRoutes()) + .route("/experimental", ExperimentalRoutes()) + .route("/session", SessionRoutes()) + .route("/permission", PermissionRoutes()) + .route("/question", QuestionRoutes()) + .route("/provider", ProviderRoutes()) + .route("/", FileRoutes()) + .route("/mcp", McpRoutes()) + .route("/tui", TuiRoutes()) + .post( + "/instance/dispose", + describeRoute({ + summary: "Dispose instance", + description: "Clean up and dispose the current OpenCode instance, releasing all resources.", + operationId: "instance.dispose", + responses: { + 200: { + description: "Instance disposed", + content: { + "application/json": { + schema: resolver(z.boolean()), }, }, }, - }), - async (c) => { - return c.json({ - home: Global.Path.home, - state: Global.Path.state, - config: Global.Path.config, - worktree: Instance.worktree, - directory: Instance.directory, - }) }, - ) - .get( - "/vcs", - describeRoute({ - summary: "Get VCS info", - description: - "Retrieve version control system (VCS) information for the current project, such as git branch.", - operationId: "vcs.get", - responses: { - 200: { - description: "VCS info", - content: { - "application/json": { - schema: resolver(Vcs.Info), - }, + }), + async (c) => { + await Instance.dispose() + return c.json(true) + }, + ) + .get( + "/path", + describeRoute({ + summary: "Get paths", + description: "Retrieve the current working directory and related path information for the OpenCode instance.", + operationId: "path.get", + responses: { + 200: { + description: "Path", + content: { + "application/json": { + schema: resolver( + z + .object({ + home: z.string(), + state: z.string(), + config: z.string(), + worktree: z.string(), + directory: z.string(), + }) + .meta({ + ref: "Path", + }), + ), }, }, }, - }), - async (c) => { - const branch = await Vcs.branch() - return c.json({ - branch, - }) }, - ) - .get( - "/command", - describeRoute({ - summary: "List commands", - description: "Get a list of all available commands in the OpenCode system.", - operationId: "command.list", - responses: { - 200: { - description: "List of commands", - content: { - "application/json": { - schema: resolver(Command.Info.array()), - }, + }), + async (c) => { + return c.json({ + home: Global.Path.home, + state: Global.Path.state, + config: Global.Path.config, + worktree: Instance.worktree, + directory: Instance.directory, + }) + }, + ) + .get( + "/vcs", + describeRoute({ + summary: "Get VCS info", + description: "Retrieve version control system (VCS) information for the current project, such as git branch.", + operationId: "vcs.get", + responses: { + 200: { + description: "VCS info", + content: { + "application/json": { + schema: resolver(Vcs.Info), }, }, }, - }), - async (c) => { - const commands = await Command.list() - return c.json(commands) }, - ) - .post( - "/log", - describeRoute({ - summary: "Write log", - description: "Write a log entry to the server logs with specified level and metadata.", - operationId: "app.log", - responses: { - 200: { - description: "Log entry written successfully", - content: { - "application/json": { - schema: resolver(z.boolean()), - }, + }), + async (c) => { + const branch = await Vcs.branch() + return c.json({ + branch, + }) + }, + ) + .get( + "/command", + describeRoute({ + summary: "List commands", + description: "Get a list of all available commands in the OpenCode system.", + operationId: "command.list", + responses: { + 200: { + description: "List of commands", + content: { + "application/json": { + schema: resolver(Command.Info.array()), }, }, - ...errors(400), }, + }, + }), + async (c) => { + const commands = await Command.list() + return c.json(commands) + }, + ) + .post( + "/log", + describeRoute({ + summary: "Write log", + description: "Write a log entry to the server logs with specified level and metadata.", + operationId: "app.log", + responses: { + 200: { + description: "Log entry written successfully", + content: { + "application/json": { + schema: resolver(z.boolean()), + }, + }, + }, + ...errors(400), + }, + }), + validator( + "json", + z.object({ + service: z.string().meta({ description: "Service name for the log entry" }), + level: z.enum(["debug", "info", "error", "warn"]).meta({ description: "Log level" }), + message: z.string().meta({ description: "Log message" }), + extra: z + .record(z.string(), z.any()) + .optional() + .meta({ description: "Additional metadata for the log entry" }), }), - validator( - "json", - z.object({ - service: z.string().meta({ description: "Service name for the log entry" }), - level: z.enum(["debug", "info", "error", "warn"]).meta({ description: "Log level" }), - message: z.string().meta({ description: "Log message" }), - extra: z - .record(z.string(), z.any()) - .optional() - .meta({ description: "Additional metadata for the log entry" }), - }), - ), - async (c) => { - const { service, level, message, extra } = c.req.valid("json") - const logger = Log.create({ service }) + ), + async (c) => { + const { service, level, message, extra } = c.req.valid("json") + const logger = Log.create({ service }) - switch (level) { - case "debug": - logger.debug(message, extra) - break - case "info": - logger.info(message, extra) - break - case "error": - logger.error(message, extra) - break - case "warn": - logger.warn(message, extra) - break - } + switch (level) { + case "debug": + logger.debug(message, extra) + break + case "info": + logger.info(message, extra) + break + case "error": + logger.error(message, extra) + break + case "warn": + logger.warn(message, extra) + break + } - return c.json(true) - }, - ) - .get( - "/agent", - describeRoute({ - summary: "List agents", - description: "Get a list of all available AI agents in the OpenCode system.", - operationId: "app.agents", - responses: { - 200: { - description: "List of agents", - content: { - "application/json": { - schema: resolver(Agent.Info.array()), - }, + return c.json(true) + }, + ) + .get( + "/agent", + describeRoute({ + summary: "List agents", + description: "Get a list of all available AI agents in the OpenCode system.", + operationId: "app.agents", + responses: { + 200: { + description: "List of agents", + content: { + "application/json": { + schema: resolver(Agent.Info.array()), }, }, }, - }), - async (c) => { - const modes = await Agent.list() - return c.json(modes) }, - ) - .get( - "/skill", - describeRoute({ - summary: "List skills", - description: "Get a list of all available skills in the OpenCode system.", - operationId: "app.skills", - responses: { - 200: { - description: "List of skills", - content: { - "application/json": { - schema: resolver(Skill.Info.array()), - }, + }), + async (c) => { + const modes = await Agent.list() + return c.json(modes) + }, + ) + .get( + "/skill", + describeRoute({ + summary: "List skills", + description: "Get a list of all available skills in the OpenCode system.", + operationId: "app.skills", + responses: { + 200: { + description: "List of skills", + content: { + "application/json": { + schema: resolver(Skill.Info.array()), }, }, }, - }), - async (c) => { - const skills = await Skill.all() - return c.json(skills) }, - ) - .get( - "/lsp", - describeRoute({ - summary: "Get LSP status", - description: "Get LSP server status", - operationId: "lsp.status", - responses: { - 200: { - description: "LSP server status", - content: { - "application/json": { - schema: resolver(LSP.Status.array()), - }, + }), + async (c) => { + const skills = await Skill.all() + return c.json(skills) + }, + ) + .get( + "/lsp", + describeRoute({ + summary: "Get LSP status", + description: "Get LSP server status", + operationId: "lsp.status", + responses: { + 200: { + description: "LSP server status", + content: { + "application/json": { + schema: resolver(LSP.Status.array()), }, }, }, - }), - async (c) => { - return c.json(await LSP.status()) }, - ) - .get( - "/formatter", - describeRoute({ - summary: "Get formatter status", - description: "Get formatter status", - operationId: "formatter.status", - responses: { - 200: { - description: "Formatter status", - content: { - "application/json": { - schema: resolver(Format.Status.array()), - }, + }), + async (c) => { + return c.json(await LSP.status()) + }, + ) + .get( + "/formatter", + describeRoute({ + summary: "Get formatter status", + description: "Get formatter status", + operationId: "formatter.status", + responses: { + 200: { + description: "Formatter status", + content: { + "application/json": { + schema: resolver(Format.Status.array()), }, }, }, - }), - async (c) => { - return c.json(await Format.status()) }, - ) - .get( - "/event", - describeRoute({ - summary: "Subscribe to events", - description: "Get events", - operationId: "event.subscribe", - responses: { - 200: { - description: "Event stream", - content: { - "text/event-stream": { - schema: resolver(BusEvent.payloads()), - }, + }), + async (c) => { + return c.json(await Format.status()) + }, + ) + .get( + "/event", + describeRoute({ + summary: "Subscribe to events", + description: "Get events", + operationId: "event.subscribe", + responses: { + 200: { + description: "Event stream", + content: { + "text/event-stream": { + schema: resolver(BusEvent.payloads()), }, }, }, - }), - async (c) => { - log.info("event connected") - c.header("X-Accel-Buffering", "no") - c.header("X-Content-Type-Options", "nosniff") - return streamSSE(c, async (stream) => { + }, + }), + async (c) => { + log.info("event connected") + c.header("X-Accel-Buffering", "no") + c.header("X-Content-Type-Options", "nosniff") + return streamSSE(c, async (stream) => { + stream.writeSSE({ + data: JSON.stringify({ + type: "server.connected", + properties: {}, + }), + }) + const unsub = Bus.subscribeAll(async (event) => { + await stream.writeSSE({ + data: JSON.stringify(event), + }) + if (event.type === Bus.InstanceDisposed.type) { + stream.close() + } + }) + + // Send heartbeat every 10s to prevent stalled proxy streams. + const heartbeat = setInterval(() => { stream.writeSSE({ data: JSON.stringify({ - type: "server.connected", + type: "server.heartbeat", properties: {}, }), }) - const unsub = Bus.subscribeAll(async (event) => { - await stream.writeSSE({ - data: JSON.stringify(event), - }) - if (event.type === Bus.InstanceDisposed.type) { - stream.close() - } - }) + }, 10_000) - // Send heartbeat every 10s to prevent stalled proxy streams. - const heartbeat = setInterval(() => { - stream.writeSSE({ - data: JSON.stringify({ - type: "server.heartbeat", - properties: {}, - }), - }) - }, 10_000) - - await new Promise<void>((resolve) => { - stream.onAbort(() => { - clearInterval(heartbeat) - unsub() - resolve() - log.info("event disconnected") - }) + await new Promise<void>((resolve) => { + stream.onAbort(() => { + clearInterval(heartbeat) + unsub() + resolve() + log.info("event disconnected") }) }) - }, - ) - .all("/*", async (c) => { - const path = c.req.path - - const response = await proxy(`https://app.opencode.ai${path}`, { - ...c.req, - headers: { - ...c.req.raw.headers, - host: "app.opencode.ai", - }, }) - response.headers.set( - "Content-Security-Policy", - "default-src 'self'; script-src 'self' 'wasm-unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; media-src 'self' data:; connect-src 'self' data:", - ) - return response - }) as unknown as Hono, - ) + }, + ) + .all("/*", async (c) => { + const path = c.req.path + + const response = await proxy(`https://app.opencode.ai${path}`, { + ...c.req, + headers: { + ...c.req.raw.headers, + host: "app.opencode.ai", + }, + }) + response.headers.set( + "Content-Security-Policy", + "default-src 'self'; script-src 'self' 'wasm-unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; media-src 'self' data:; connect-src 'self' data:", + ) + return response + }) + } export async function openapi() { // Cast to break excessive type recursion from long route chains - const result = await generateSpecs(App() as Hono, { + const result = await generateSpecs(Default(), { documentation: { info: { title: "opencode", @@ -580,12 +592,11 @@ export namespace Server { mdnsDomain?: string cors?: string[] }) { - _corsWhitelist = opts.cors ?? [] - + const app = createApp(opts) const args = { hostname: opts.hostname, idleTimeout: 0, - fetch: App().fetch, + fetch: app.fetch, websocket: websocket, } as const const tryServe = (port: number) => { @@ -598,8 +609,6 @@ export namespace Server { const server = opts.port === 0 ? (tryServe(4096) ?? tryServe(0)) : tryServe(opts.port) if (!server) throw new Error(`Failed to start server on port ${opts.port}`) - _url = server.url - const shouldPublishMDNS = opts.mdns && server.port && diff --git a/packages/opencode/src/session/compaction.ts b/packages/opencode/src/session/compaction.ts index 9245426057..79884d641e 100644 --- a/packages/opencode/src/session/compaction.ts +++ b/packages/opencode/src/session/compaction.ts @@ -104,8 +104,30 @@ export namespace SessionCompaction { sessionID: string abort: AbortSignal auto: boolean + overflow?: boolean }) { const userMessage = input.messages.findLast((m) => m.info.id === input.parentID)!.info as MessageV2.User + + let messages = input.messages + let replay: MessageV2.WithParts | undefined + if (input.overflow) { + const idx = input.messages.findIndex((m) => m.info.id === input.parentID) + for (let i = idx - 1; i >= 0; i--) { + const msg = input.messages[i] + if (msg.info.role === "user" && !msg.parts.some((p) => p.type === "compaction")) { + replay = msg + messages = input.messages.slice(0, i) + break + } + } + const hasContent = + replay && messages.some((m) => m.info.role === "user" && !m.parts.some((p) => p.type === "compaction")) + if (!hasContent) { + replay = undefined + messages = input.messages + } + } + const agent = await Agent.get("compaction") const model = agent.model ? await Provider.getModel(agent.model.providerID, agent.model.modelID) @@ -185,7 +207,7 @@ When constructing the summary, try to stick to this template: tools: {}, system: [], messages: [ - ...MessageV2.toModelMessages(input.messages, model), + ...MessageV2.toModelMessages(messages, model, { stripMedia: true }), { role: "user", content: [ @@ -199,29 +221,72 @@ When constructing the summary, try to stick to this template: model, }) + if (result === "compact") { + processor.message.error = new MessageV2.ContextOverflowError({ + message: replay + ? "Conversation history too large to compact - exceeds model context limit" + : "Session too large to compact - context exceeds model limit even after stripping media", + }).toObject() + processor.message.finish = "error" + await Session.updateMessage(processor.message) + return "stop" + } + if (result === "continue" && input.auto) { - const continueMsg = await Session.updateMessage({ - id: Identifier.ascending("message"), - role: "user", - sessionID: input.sessionID, - time: { - created: Date.now(), - }, - agent: userMessage.agent, - model: userMessage.model, - }) - await Session.updatePart({ - id: Identifier.ascending("part"), - messageID: continueMsg.id, - sessionID: input.sessionID, - type: "text", - synthetic: true, - text: "Continue if you have next steps, or stop and ask for clarification if you are unsure how to proceed.", - time: { - start: Date.now(), - end: Date.now(), - }, - }) + if (replay) { + const original = replay.info as MessageV2.User + const replayMsg = await Session.updateMessage({ + id: Identifier.ascending("message"), + role: "user", + sessionID: input.sessionID, + time: { created: Date.now() }, + agent: original.agent, + model: original.model, + format: original.format, + tools: original.tools, + system: original.system, + variant: original.variant, + }) + for (const part of replay.parts) { + if (part.type === "compaction") continue + const replayPart = + part.type === "file" && MessageV2.isMedia(part.mime) + ? { type: "text" as const, text: `[Attached ${part.mime}: ${part.filename ?? "file"}]` } + : part + await Session.updatePart({ + ...replayPart, + id: Identifier.ascending("part"), + messageID: replayMsg.id, + sessionID: input.sessionID, + }) + } + } else { + const continueMsg = await Session.updateMessage({ + id: Identifier.ascending("message"), + role: "user", + sessionID: input.sessionID, + time: { created: Date.now() }, + agent: userMessage.agent, + model: userMessage.model, + }) + const text = + (input.overflow + ? "The previous request exceeded the provider's size limit due to large media attachments. The conversation was compacted and media files were removed from context. If the user was asking about attached images or files, explain that the attachments were too large to process and suggest they try again with smaller or fewer files.\n\n" + : "") + + "Continue if you have next steps, or stop and ask for clarification if you are unsure how to proceed." + await Session.updatePart({ + id: Identifier.ascending("part"), + messageID: continueMsg.id, + sessionID: input.sessionID, + type: "text", + synthetic: true, + text, + time: { + start: Date.now(), + end: Date.now(), + }, + }) + } } if (processor.message.error) return "stop" Bus.publish(Event.Compacted, { sessionID: input.sessionID }) @@ -237,6 +302,7 @@ When constructing the summary, try to stick to this template: modelID: z.string(), }), auto: z.boolean(), + overflow: z.boolean().optional(), }), async (input) => { const msg = await Session.updateMessage({ @@ -255,6 +321,7 @@ When constructing the summary, try to stick to this template: sessionID: msg.sessionID, type: "compaction", auto: input.auto, + overflow: input.overflow, }) }, ) diff --git a/packages/opencode/src/session/index.ts b/packages/opencode/src/session/index.ts index 8454a9c3e9..b117632051 100644 --- a/packages/opencode/src/session/index.ts +++ b/packages/opencode/src/session/index.ts @@ -22,6 +22,7 @@ import { SessionPrompt } from "./prompt" import { fn } from "@/util/fn" import { Command } from "../command" import { Snapshot } from "@/snapshot" +import { WorkspaceContext } from "../control-plane/workspace-context" import type { Provider } from "@/provider/provider" import { PermissionNext } from "@/permission/next" @@ -63,6 +64,7 @@ export namespace Session { id: row.id, slug: row.slug, projectID: row.project_id, + workspaceID: row.workspace_id ?? undefined, directory: row.directory, parentID: row.parent_id ?? undefined, title: row.title, @@ -84,6 +86,7 @@ export namespace Session { return { id: info.id, project_id: info.projectID, + workspace_id: info.workspaceID, parent_id: info.parentID, slug: info.slug, directory: info.directory, @@ -118,6 +121,7 @@ export namespace Session { id: Identifier.schema("session"), slug: z.string(), projectID: z.string(), + workspaceID: z.string().optional(), directory: z.string(), parentID: Identifier.schema("session").optional(), summary: z @@ -297,6 +301,7 @@ export namespace Session { version: Installation.VERSION, projectID: Instance.project.id, directory: input.directory, + workspaceID: WorkspaceContext.workspaceID, parentID: input.parentID, title: input.title ?? createDefaultTitle(!!input.parentID), permission: input.permission, @@ -527,6 +532,7 @@ export namespace Session { export function* list(input?: { directory?: string + workspaceID?: string roots?: boolean start?: number search?: string @@ -535,6 +541,9 @@ export namespace Session { const project = Instance.project const conditions = [eq(SessionTable.project_id, project.id)] + if (WorkspaceContext.workspaceID) { + conditions.push(eq(SessionTable.workspace_id, WorkspaceContext.workspaceID)) + } if (input?.directory) { conditions.push(eq(SessionTable.directory, input.directory)) } @@ -697,7 +706,9 @@ export namespace Session { async (input) => { // CASCADE delete handles parts automatically Database.use((db) => { - db.delete(MessageTable).where(eq(MessageTable.id, input.messageID)).run() + db.delete(MessageTable) + .where(and(eq(MessageTable.id, input.messageID), eq(MessageTable.session_id, input.sessionID))) + .run() Database.effect(() => Bus.publish(MessageV2.Event.Removed, { sessionID: input.sessionID, @@ -717,7 +728,9 @@ export namespace Session { }), async (input) => { Database.use((db) => { - db.delete(PartTable).where(eq(PartTable.id, input.partID)).run() + db.delete(PartTable) + .where(and(eq(PartTable.id, input.partID), eq(PartTable.session_id, input.sessionID))) + .run() Database.effect(() => Bus.publish(MessageV2.Event.PartRemoved, { sessionID: input.sessionID, @@ -748,7 +761,7 @@ export namespace Session { .run() Database.effect(() => Bus.publish(MessageV2.Event.PartUpdated, { - part, + part: structuredClone(part), }), ) }) diff --git a/packages/opencode/src/session/message-v2.ts b/packages/opencode/src/session/message-v2.ts index 178751a222..5b4e7bdbc0 100644 --- a/packages/opencode/src/session/message-v2.ts +++ b/packages/opencode/src/session/message-v2.ts @@ -17,6 +17,10 @@ import { type SystemError } from "bun" import type { Provider } from "@/provider/provider" export namespace MessageV2 { + export function isMedia(mime: string) { + return mime.startsWith("image/") || mime === "application/pdf" + } + export const OutputLengthError = NamedError.create("MessageOutputLengthError", z.object({})) export const AbortedError = NamedError.create("MessageAbortedError", z.object({ message: z.string() })) export const StructuredOutputError = NamedError.create( @@ -196,6 +200,7 @@ export namespace MessageV2 { export const CompactionPart = PartBase.extend({ type: z.literal("compaction"), auto: z.boolean(), + overflow: z.boolean().optional(), }).meta({ ref: "CompactionPart", }) @@ -488,7 +493,11 @@ export namespace MessageV2 { }) export type WithParts = z.infer<typeof WithParts> - export function toModelMessages(input: WithParts[], model: Provider.Model): ModelMessage[] { + export function toModelMessages( + input: WithParts[], + model: Provider.Model, + options?: { stripMedia?: boolean }, + ): ModelMessage[] { const result: UIMessage[] = [] const toolNames = new Set<string>() // Track media from tool results that need to be injected as user messages @@ -562,13 +571,21 @@ export namespace MessageV2 { text: part.text, }) // text/plain and directory files are converted into text parts, ignore them - if (part.type === "file" && part.mime !== "text/plain" && part.mime !== "application/x-directory") - userMessage.parts.push({ - type: "file", - url: part.url, - mediaType: part.mime, - filename: part.filename, - }) + if (part.type === "file" && part.mime !== "text/plain" && part.mime !== "application/x-directory") { + if (options?.stripMedia && isMedia(part.mime)) { + userMessage.parts.push({ + type: "text", + text: `[Attached ${part.mime}: ${part.filename ?? "file"}]`, + }) + } else { + userMessage.parts.push({ + type: "file", + url: part.url, + mediaType: part.mime, + filename: part.filename, + }) + } + } if (part.type === "compaction") { userMessage.parts.push({ @@ -618,14 +635,12 @@ export namespace MessageV2 { toolNames.add(part.tool) if (part.state.status === "completed") { const outputText = part.state.time.compacted ? "[Old tool result content cleared]" : part.state.output - const attachments = part.state.time.compacted ? [] : (part.state.attachments ?? []) + const attachments = part.state.time.compacted || options?.stripMedia ? [] : (part.state.attachments ?? []) // For providers that don't support media in tool results, extract media files // (images, PDFs) to be sent as a separate user message - const isMediaAttachment = (a: { mime: string }) => - a.mime.startsWith("image/") || a.mime === "application/pdf" - const mediaAttachments = attachments.filter(isMediaAttachment) - const nonMediaAttachments = attachments.filter((a) => !isMediaAttachment(a)) + const mediaAttachments = attachments.filter((a) => isMedia(a.mime)) + const nonMediaAttachments = attachments.filter((a) => !isMedia(a.mime)) if (!supportsMediaInToolResults && mediaAttachments.length > 0) { media.push(...mediaAttachments) } @@ -802,7 +817,8 @@ export namespace MessageV2 { msg.parts.some((part) => part.type === "compaction") ) break - if (msg.info.role === "assistant" && msg.info.summary && msg.info.finish) completed.add(msg.info.parentID) + if (msg.info.role === "assistant" && msg.info.summary && msg.info.finish && !msg.info.error) + completed.add(msg.info.parentID) } result.reverse() return result diff --git a/packages/opencode/src/session/processor.ts b/packages/opencode/src/session/processor.ts index e7532d2007..67edc0ecfe 100644 --- a/packages/opencode/src/session/processor.ts +++ b/packages/opencode/src/session/processor.ts @@ -279,7 +279,10 @@ export namespace SessionProcessor { sessionID: input.sessionID, messageID: input.assistantMessage.parentID, }) - if (await SessionCompaction.isOverflow({ tokens: usage.tokens, model: input.model })) { + if ( + !input.assistantMessage.summary && + (await SessionCompaction.isOverflow({ tokens: usage.tokens, model: input.model })) + ) { needsCompaction = true } break @@ -354,27 +357,32 @@ export namespace SessionProcessor { }) const error = MessageV2.fromError(e, { providerID: input.model.providerID }) if (MessageV2.ContextOverflowError.isInstance(error)) { - // TODO: Handle context overflow error - } - const retry = SessionRetry.retryable(error) - if (retry !== undefined) { - attempt++ - const delay = SessionRetry.delay(attempt, error.name === "APIError" ? error : undefined) - SessionStatus.set(input.sessionID, { - type: "retry", - attempt, - message: retry, - next: Date.now() + delay, + needsCompaction = true + Bus.publish(Session.Event.Error, { + sessionID: input.sessionID, + error, }) - await SessionRetry.sleep(delay, input.abort).catch(() => {}) - continue + } else { + const retry = SessionRetry.retryable(error) + if (retry !== undefined) { + attempt++ + const delay = SessionRetry.delay(attempt, error.name === "APIError" ? error : undefined) + SessionStatus.set(input.sessionID, { + type: "retry", + attempt, + message: retry, + next: Date.now() + delay, + }) + await SessionRetry.sleep(delay, input.abort).catch(() => {}) + continue + } + input.assistantMessage.error = error + Bus.publish(Session.Event.Error, { + sessionID: input.assistantMessage.sessionID, + error: input.assistantMessage.error, + }) + SessionStatus.set(input.sessionID, { type: "idle" }) } - input.assistantMessage.error = error - Bus.publish(Session.Event.Error, { - sessionID: input.assistantMessage.sessionID, - error: input.assistantMessage.error, - }) - SessionStatus.set(input.sessionID, { type: "idle" }) } if (snapshot) { const patch = await Snapshot.patch(snapshot) diff --git a/packages/opencode/src/session/prompt.ts b/packages/opencode/src/session/prompt.ts index 75bd3c9dfa..7698b78bab 100644 --- a/packages/opencode/src/session/prompt.ts +++ b/packages/opencode/src/session/prompt.ts @@ -31,7 +31,8 @@ import { Flag } from "../flag/flag" import { ulid } from "ulid" import { spawn } from "child_process" import { Command } from "../command" -import { $, fileURLToPath, pathToFileURL } from "bun" +import { $ } from "bun" +import { pathToFileURL, fileURLToPath } from "url" import { ConfigMarkdown } from "../config/markdown" import { SessionSummary } from "./summary" import { NamedError } from "@opencode-ai/util/error" @@ -533,6 +534,7 @@ export namespace SessionPrompt { abort, sessionID, auto: task.auto, + overflow: task.overflow, }) if (result === "stop") break continue @@ -707,6 +709,7 @@ export namespace SessionPrompt { agent: lastUser.agent, model: lastUser.model, auto: true, + overflow: !processor.message.finish, }) } continue diff --git a/packages/opencode/src/session/session.sql.ts b/packages/opencode/src/session/session.sql.ts index 9c5c72c4c5..0630760f3b 100644 --- a/packages/opencode/src/session/session.sql.ts +++ b/packages/opencode/src/session/session.sql.ts @@ -15,6 +15,7 @@ export const SessionTable = sqliteTable( project_id: text() .notNull() .references(() => ProjectTable.id, { onDelete: "cascade" }), + workspace_id: text(), parent_id: text(), slug: text().notNull(), directory: text().notNull(), @@ -31,7 +32,11 @@ export const SessionTable = sqliteTable( time_compacting: integer(), time_archived: integer(), }, - (table) => [index("session_project_idx").on(table.project_id), index("session_parent_idx").on(table.parent_id)], + (table) => [ + index("session_project_idx").on(table.project_id), + index("session_workspace_idx").on(table.workspace_id), + index("session_parent_idx").on(table.parent_id), + ], ) export const MessageTable = sqliteTable( diff --git a/packages/opencode/src/share/share-next.ts b/packages/opencode/src/share/share-next.ts index c36616b7ef..5443762784 100644 --- a/packages/opencode/src/share/share-next.ts +++ b/packages/opencode/src/share/share-next.ts @@ -1,6 +1,5 @@ import { Bus } from "@/bus" import { Config } from "@/config/config" -import { ulid } from "ulid" import { Provider } from "@/provider/provider" import { Session } from "@/session" import { MessageV2 } from "@/session/message-v2" @@ -122,20 +121,35 @@ export namespace ShareNext { data: SDK.Model[] } + function key(item: Data) { + switch (item.type) { + case "session": + return "session" + case "message": + return `message/${item.data.id}` + case "part": + return `part/${item.data.messageID}/${item.data.id}` + case "session_diff": + return "session_diff" + case "model": + return "model" + } + } + const queue = new Map<string, { timeout: NodeJS.Timeout; data: Map<string, Data> }>() async function sync(sessionID: string, data: Data[]) { if (disabled) return const existing = queue.get(sessionID) if (existing) { for (const item of data) { - existing.data.set("id" in item ? (item.id as string) : ulid(), item) + existing.data.set(key(item), item) } return } const dataMap = new Map<string, Data>() for (const item of data) { - dataMap.set("id" in item ? (item.id as string) : ulid(), item) + dataMap.set(key(item), item) } const timeout = setTimeout(async () => { @@ -182,10 +196,14 @@ export namespace ShareNext { const diffs = await Session.diff(sessionID) const messages = await Array.fromAsync(MessageV2.stream(sessionID)) const models = await Promise.all( - messages - .filter((m) => m.info.role === "user") - .map((m) => (m.info as SDK.UserMessage).model) - .map((m) => Provider.getModel(m.providerID, m.modelID).then((m) => m)), + Array.from( + new Map( + messages + .filter((m) => m.info.role === "user") + .map((m) => (m.info as SDK.UserMessage).model) + .map((m) => [`${m.providerID}/${m.modelID}`, m] as const), + ).values(), + ).map((m) => Provider.getModel(m.providerID, m.modelID).then((item) => item)), ) await sync(sessionID, [ { diff --git a/packages/opencode/src/shell/shell.ts b/packages/opencode/src/shell/shell.ts index e7b7cdb3e4..60ae46f5ee 100644 --- a/packages/opencode/src/shell/shell.ts +++ b/packages/opencode/src/shell/shell.ts @@ -1,8 +1,10 @@ import { Flag } from "@/flag/flag" import { lazy } from "@/util/lazy" import { Filesystem } from "@/util/filesystem" +import { which } from "@/util/which" import path from "path" import { spawn, type ChildProcess } from "child_process" +import { setTimeout as sleep } from "node:timers/promises" const SIGKILL_TIMEOUT_MS = 200 @@ -22,13 +24,13 @@ export namespace Shell { try { process.kill(-pid, "SIGTERM") - await Bun.sleep(SIGKILL_TIMEOUT_MS) + await sleep(SIGKILL_TIMEOUT_MS) if (!opts?.exited?.()) { process.kill(-pid, "SIGKILL") } } catch (_e) { proc.kill("SIGTERM") - await Bun.sleep(SIGKILL_TIMEOUT_MS) + await sleep(SIGKILL_TIMEOUT_MS) if (!opts?.exited?.()) { proc.kill("SIGKILL") } @@ -39,7 +41,7 @@ export namespace Shell { function fallback() { if (process.platform === "win32") { if (Flag.OPENCODE_GIT_BASH_PATH) return Flag.OPENCODE_GIT_BASH_PATH - const git = Bun.which("git") + const git = which("git") if (git) { // git.exe is typically at: C:\Program Files\Git\cmd\git.exe // bash.exe is at: C:\Program Files\Git\bin\bash.exe @@ -49,7 +51,7 @@ export namespace Shell { return process.env.COMSPEC || "cmd.exe" } if (process.platform === "darwin") return "/bin/zsh" - const bash = Bun.which("bash") + const bash = which("bash") if (bash) return bash return "/bin/sh" } diff --git a/packages/opencode/src/snapshot/index.ts b/packages/opencode/src/snapshot/index.ts index 83cc467e42..848f2694e0 100644 --- a/packages/opencode/src/snapshot/index.ts +++ b/packages/opencode/src/snapshot/index.ts @@ -1,6 +1,6 @@ -import { $ } from "bun" import path from "path" import fs from "fs/promises" +import { Filesystem } from "../util/filesystem" import { Log } from "../util/log" import { Flag } from "../flag/flag" import { Global } from "../global" @@ -8,12 +8,17 @@ import z from "zod" import { Config } from "../config/config" import { Instance } from "../project/instance" import { Scheduler } from "../scheduler" +import { Process } from "@/util/process" export namespace Snapshot { const log = Log.create({ service: "snapshot" }) const hour = 60 * 60 * 1000 const prune = "7.days" + function args(git: string, cmd: string[]) { + return ["--git-dir", git, "--work-tree", Instance.worktree, ...cmd] + } + export function init() { Scheduler.register({ id: "snapshot.cleanup", @@ -33,13 +38,13 @@ export namespace Snapshot { .then(() => true) .catch(() => false) if (!exists) return - const result = await $`git --git-dir ${git} --work-tree ${Instance.worktree} gc --prune=${prune}` - .quiet() - .cwd(Instance.directory) - .nothrow() - if (result.exitCode !== 0) { + const result = await Process.run(["git", ...args(git, ["gc", `--prune=${prune}`])], { + cwd: Instance.directory, + nothrow: true, + }) + if (result.code !== 0) { log.warn("cleanup failed", { - exitCode: result.exitCode, + exitCode: result.code, stderr: result.stderr.toString(), stdout: result.stdout.toString(), }) @@ -54,24 +59,27 @@ export namespace Snapshot { if (cfg.snapshot === false) return const git = gitdir() if (await fs.mkdir(git, { recursive: true })) { - await $`git init` - .env({ + await Process.run(["git", "init"], { + env: { ...process.env, GIT_DIR: git, GIT_WORK_TREE: Instance.worktree, - }) - .quiet() - .nothrow() + }, + nothrow: true, + }) + // Configure git to not convert line endings on Windows - await $`git --git-dir ${git} config core.autocrlf false`.quiet().nothrow() + await Process.run(["git", "--git-dir", git, "config", "core.autocrlf", "false"], { nothrow: true }) + await Process.run(["git", "--git-dir", git, "config", "core.longpaths", "true"], { nothrow: true }) + await Process.run(["git", "--git-dir", git, "config", "core.symlinks", "true"], { nothrow: true }) + await Process.run(["git", "--git-dir", git, "config", "core.fsmonitor", "false"], { nothrow: true }) log.info("initialized") } await add(git) - const hash = await $`git --git-dir ${git} --work-tree ${Instance.worktree} write-tree` - .quiet() - .cwd(Instance.directory) - .nothrow() - .text() + const hash = await Process.text(["git", ...args(git, ["write-tree"])], { + cwd: Instance.directory, + nothrow: true, + }).then((x) => x.text) log.info("tracking", { hash, cwd: Instance.directory, git }) return hash.trim() } @@ -85,19 +93,32 @@ export namespace Snapshot { export async function patch(hash: string): Promise<Patch> { const git = gitdir() await add(git) - const result = - await $`git -c core.autocrlf=false -c core.quotepath=false --git-dir ${git} --work-tree ${Instance.worktree} diff --no-ext-diff --name-only ${hash} -- .` - .quiet() - .cwd(Instance.directory) - .nothrow() + const result = await Process.text( + [ + "git", + "-c", + "core.autocrlf=false", + "-c", + "core.longpaths=true", + "-c", + "core.symlinks=true", + "-c", + "core.quotepath=false", + ...args(git, ["diff", "--no-ext-diff", "--name-only", hash, "--", "."]), + ], + { + cwd: Instance.directory, + nothrow: true, + }, + ) // If git diff fails, return empty patch - if (result.exitCode !== 0) { - log.warn("failed to get diff", { hash, exitCode: result.exitCode }) + if (result.code !== 0) { + log.warn("failed to get diff", { hash, exitCode: result.code }) return { hash, files: [] } } - const files = result.text() + const files = result.text return { hash, files: files @@ -105,27 +126,44 @@ export namespace Snapshot { .split("\n") .map((x) => x.trim()) .filter(Boolean) - .map((x) => path.join(Instance.worktree, x)), + .map((x) => path.join(Instance.worktree, x).replaceAll("\\", "/")), } } export async function restore(snapshot: string) { log.info("restore", { commit: snapshot }) const git = gitdir() - const result = - await $`git --git-dir ${git} --work-tree ${Instance.worktree} read-tree ${snapshot} && git --git-dir ${git} --work-tree ${Instance.worktree} checkout-index -a -f` - .quiet() - .cwd(Instance.worktree) - .nothrow() - - if (result.exitCode !== 0) { + const result = await Process.run( + ["git", "-c", "core.longpaths=true", "-c", "core.symlinks=true", ...args(git, ["read-tree", snapshot])], + { + cwd: Instance.worktree, + nothrow: true, + }, + ) + if (result.code === 0) { + const checkout = await Process.run( + ["git", "-c", "core.longpaths=true", "-c", "core.symlinks=true", ...args(git, ["checkout-index", "-a", "-f"])], + { + cwd: Instance.worktree, + nothrow: true, + }, + ) + if (checkout.code === 0) return log.error("failed to restore snapshot", { snapshot, - exitCode: result.exitCode, - stderr: result.stderr.toString(), - stdout: result.stdout.toString(), + exitCode: checkout.code, + stderr: checkout.stderr.toString(), + stdout: checkout.stdout.toString(), }) + return } + + log.error("failed to restore snapshot", { + snapshot, + exitCode: result.code, + stderr: result.stderr.toString(), + stdout: result.stdout.toString(), + }) } export async function revert(patches: Patch[]) { @@ -135,18 +173,37 @@ export namespace Snapshot { for (const file of item.files) { if (files.has(file)) continue log.info("reverting", { file, hash: item.hash }) - const result = await $`git --git-dir ${git} --work-tree ${Instance.worktree} checkout ${item.hash} -- ${file}` - .quiet() - .cwd(Instance.worktree) - .nothrow() - if (result.exitCode !== 0) { + const result = await Process.run( + [ + "git", + "-c", + "core.longpaths=true", + "-c", + "core.symlinks=true", + ...args(git, ["checkout", item.hash, "--", file]), + ], + { + cwd: Instance.worktree, + nothrow: true, + }, + ) + if (result.code !== 0) { const relativePath = path.relative(Instance.worktree, file) - const checkTree = - await $`git --git-dir ${git} --work-tree ${Instance.worktree} ls-tree ${item.hash} -- ${relativePath}` - .quiet() - .cwd(Instance.worktree) - .nothrow() - if (checkTree.exitCode === 0 && checkTree.text().trim()) { + const checkTree = await Process.text( + [ + "git", + "-c", + "core.longpaths=true", + "-c", + "core.symlinks=true", + ...args(git, ["ls-tree", item.hash, "--", relativePath]), + ], + { + cwd: Instance.worktree, + nothrow: true, + }, + ) + if (checkTree.code === 0 && checkTree.text.trim()) { log.info("file existed in snapshot but checkout failed, keeping", { file, }) @@ -163,23 +220,36 @@ export namespace Snapshot { export async function diff(hash: string) { const git = gitdir() await add(git) - const result = - await $`git -c core.autocrlf=false -c core.quotepath=false --git-dir ${git} --work-tree ${Instance.worktree} diff --no-ext-diff ${hash} -- .` - .quiet() - .cwd(Instance.worktree) - .nothrow() + const result = await Process.text( + [ + "git", + "-c", + "core.autocrlf=false", + "-c", + "core.longpaths=true", + "-c", + "core.symlinks=true", + "-c", + "core.quotepath=false", + ...args(git, ["diff", "--no-ext-diff", hash, "--", "."]), + ], + { + cwd: Instance.worktree, + nothrow: true, + }, + ) - if (result.exitCode !== 0) { + if (result.code !== 0) { log.warn("failed to get diff", { hash, - exitCode: result.exitCode, + exitCode: result.code, stderr: result.stderr.toString(), stdout: result.stdout.toString(), }) return "" } - return result.text().trim() + return result.text.trim() } export const FileDiff = z @@ -200,12 +270,24 @@ export namespace Snapshot { const result: FileDiff[] = [] const status = new Map<string, "added" | "deleted" | "modified">() - const statuses = - await $`git -c core.autocrlf=false -c core.quotepath=false --git-dir ${git} --work-tree ${Instance.worktree} diff --no-ext-diff --name-status --no-renames ${from} ${to} -- .` - .quiet() - .cwd(Instance.directory) - .nothrow() - .text() + const statuses = await Process.text( + [ + "git", + "-c", + "core.autocrlf=false", + "-c", + "core.longpaths=true", + "-c", + "core.symlinks=true", + "-c", + "core.quotepath=false", + ...args(git, ["diff", "--no-ext-diff", "--name-status", "--no-renames", from, to, "--", "."]), + ], + { + cwd: Instance.directory, + nothrow: true, + }, + ).then((x) => x.text) for (const line of statuses.trim().split("\n")) { if (!line) continue @@ -215,26 +297,57 @@ export namespace Snapshot { status.set(file, kind) } - for await (const line of $`git -c core.autocrlf=false -c core.quotepath=false --git-dir ${git} --work-tree ${Instance.worktree} diff --no-ext-diff --no-renames --numstat ${from} ${to} -- .` - .quiet() - .cwd(Instance.directory) - .nothrow() - .lines()) { + for (const line of await Process.lines( + [ + "git", + "-c", + "core.autocrlf=false", + "-c", + "core.longpaths=true", + "-c", + "core.symlinks=true", + "-c", + "core.quotepath=false", + ...args(git, ["diff", "--no-ext-diff", "--no-renames", "--numstat", from, to, "--", "."]), + ], + { + cwd: Instance.directory, + nothrow: true, + }, + )) { if (!line) continue const [additions, deletions, file] = line.split("\t") const isBinaryFile = additions === "-" && deletions === "-" const before = isBinaryFile ? "" - : await $`git -c core.autocrlf=false --git-dir ${git} --work-tree ${Instance.worktree} show ${from}:${file}` - .quiet() - .nothrow() - .text() + : await Process.text( + [ + "git", + "-c", + "core.autocrlf=false", + "-c", + "core.longpaths=true", + "-c", + "core.symlinks=true", + ...args(git, ["show", `${from}:${file}`]), + ], + { nothrow: true }, + ).then((x) => x.text) const after = isBinaryFile ? "" - : await $`git -c core.autocrlf=false --git-dir ${git} --work-tree ${Instance.worktree} show ${to}:${file}` - .quiet() - .nothrow() - .text() + : await Process.text( + [ + "git", + "-c", + "core.autocrlf=false", + "-c", + "core.longpaths=true", + "-c", + "core.symlinks=true", + ...args(git, ["show", `${to}:${file}`]), + ], + { nothrow: true }, + ).then((x) => x.text) const added = isBinaryFile ? 0 : parseInt(additions) const deleted = isBinaryFile ? 0 : parseInt(deletions) result.push({ @@ -256,7 +369,22 @@ export namespace Snapshot { async function add(git: string) { await syncExclude(git) - await $`git --git-dir ${git} --work-tree ${Instance.worktree} add .`.quiet().cwd(Instance.directory).nothrow() + await Process.run( + [ + "git", + "-c", + "core.autocrlf=false", + "-c", + "core.longpaths=true", + "-c", + "core.symlinks=true", + ...args(git, ["add", "."]), + ], + { + cwd: Instance.directory, + nothrow: true, + }, + ) } async function syncExclude(git: string) { @@ -264,21 +392,19 @@ export namespace Snapshot { const target = path.join(git, "info", "exclude") await fs.mkdir(path.join(git, "info"), { recursive: true }) if (!file) { - await Bun.write(target, "") + await Filesystem.write(target, "") return } - const text = await Bun.file(file) - .text() - .catch(() => "") - await Bun.write(target, text) + const text = await Filesystem.readText(file).catch(() => "") + + await Filesystem.write(target, text) } async function excludes() { - const file = await $`git rev-parse --path-format=absolute --git-path info/exclude` - .quiet() - .cwd(Instance.worktree) - .nothrow() - .text() + const file = await Process.text(["git", "rev-parse", "--path-format=absolute", "--git-path", "info/exclude"], { + cwd: Instance.worktree, + nothrow: true, + }).then((x) => x.text) if (!file.trim()) return const exists = await fs .stat(file.trim()) diff --git a/packages/opencode/src/storage/db.ts b/packages/opencode/src/storage/db.ts index 6d7bfd7281..cd920a8907 100644 --- a/packages/opencode/src/storage/db.ts +++ b/packages/opencode/src/storage/db.ts @@ -12,8 +12,11 @@ import z from "zod" import path from "path" import { readFileSync, readdirSync, existsSync } from "fs" import * as schema from "./schema" +import { Installation } from "../installation" +import { Flag } from "../flag/flag" +import { iife } from "@/util/iife" -declare const OPENCODE_MIGRATIONS: { sql: string; timestamp: number }[] | undefined +declare const OPENCODE_MIGRATIONS: { sql: string; timestamp: number; name: string }[] | undefined export const NotFoundError = NamedError.create( "NotFoundError", @@ -25,13 +28,24 @@ export const NotFoundError = NamedError.create( const log = Log.create({ service: "db" }) export namespace Database { - export const Path = path.join(Global.Path.data, "opencode.db") + export const Path = iife(() => { + const channel = Installation.CHANNEL + if (["latest", "beta"].includes(channel) || Flag.OPENCODE_DISABLE_CHANNEL_DB) + return path.join(Global.Path.data, "opencode.db") + const safe = channel.replace(/[^a-zA-Z0-9._-]/g, "-") + return path.join(Global.Path.data, `opencode-${safe}.db`) + }) + type Schema = typeof schema export type Transaction = SQLiteTransaction<"sync", void, Schema> type Client = SQLiteBunDatabase<Schema> - type Journal = { sql: string; timestamp: number }[] + type Journal = { sql: string; timestamp: number; name: string }[] + + const state = { + sqlite: undefined as BunDatabase | undefined, + } function time(tag: string) { const match = /^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/.exec(tag) @@ -58,6 +72,7 @@ export namespace Database { return { sql: readFileSync(file, "utf-8"), timestamp: time(name), + name, } }) .filter(Boolean) as Journal @@ -66,9 +81,10 @@ export namespace Database { } export const Client = lazy(() => { - log.info("opening database", { path: path.join(Global.Path.data, "opencode.db") }) + log.info("opening database", { path: Path }) - const sqlite = new BunDatabase(path.join(Global.Path.data, "opencode.db"), { create: true }) + const sqlite = new BunDatabase(Path, { create: true }) + state.sqlite = sqlite sqlite.run("PRAGMA journal_mode = WAL") sqlite.run("PRAGMA synchronous = NORMAL") @@ -89,12 +105,25 @@ export namespace Database { count: entries.length, mode: typeof OPENCODE_MIGRATIONS !== "undefined" ? "bundled" : "dev", }) + if (Flag.OPENCODE_SKIP_MIGRATIONS) { + for (const item of entries) { + item.sql = "select 1;" + } + } migrate(db, entries) } return db }) + export function close() { + const sqlite = state.sqlite + if (!sqlite) return + sqlite.close() + state.sqlite = undefined + Client.reset() + } + export type TxOrDb = Transaction | Client const ctx = Context.create<{ @@ -130,7 +159,7 @@ export namespace Database { } catch (err) { if (err instanceof Context.NotFound) { const effects: (() => void | Promise<void>)[] = [] - const result = Client().transaction((tx) => { + const result = (Client().transaction as any)((tx: TxOrDb) => { return ctx.provide({ tx, effects }, () => callback(tx)) }) for (const effect of effects) effect() diff --git a/packages/opencode/src/storage/schema.ts b/packages/opencode/src/storage/schema.ts index 7961b0e380..4c1c2490e3 100644 --- a/packages/opencode/src/storage/schema.ts +++ b/packages/opencode/src/storage/schema.ts @@ -2,3 +2,4 @@ export { ControlAccountTable } from "../control/control.sql" export { SessionTable, MessageTable, PartTable, TodoTable, PermissionTable } from "../session/session.sql" export { SessionShareTable } from "../share/share.sql" export { ProjectTable } from "../project/project.sql" +export { WorkspaceTable } from "../control-plane/workspace.sql" diff --git a/packages/opencode/src/storage/storage.ts b/packages/opencode/src/storage/storage.ts index a78ff04f43..a78607cdfd 100644 --- a/packages/opencode/src/storage/storage.ts +++ b/packages/opencode/src/storage/storage.ts @@ -5,10 +5,10 @@ import { Global } from "../global" import { Filesystem } from "../util/filesystem" import { lazy } from "../util/lazy" import { Lock } from "../util/lock" -import { $ } from "bun" import { NamedError } from "@opencode-ai/util/error" import z from "zod" import { Glob } from "../util/glob" +import { git } from "@/util/git" export namespace Storage { const log = Log.create({ service: "storage" }) @@ -49,18 +49,15 @@ export namespace Storage { } if (!worktree) continue if (!(await Filesystem.isDir(worktree))) continue - const [id] = await $`git rev-list --max-parents=0 --all` - .quiet() - .nothrow() - .cwd(worktree) + const result = await git(["rev-list", "--max-parents=0", "--all"], { + cwd: worktree, + }) + const [id] = result .text() - .then((x) => - x - .split("\n") - .filter(Boolean) - .map((x) => x.trim()) - .toSorted(), - ) + .split("\n") + .filter(Boolean) + .map((x) => x.trim()) + .toSorted() if (!id) continue projectID = id diff --git a/packages/opencode/src/tool/apply_patch.ts b/packages/opencode/src/tool/apply_patch.ts index 1344467c71..06293b6eba 100644 --- a/packages/opencode/src/tool/apply_patch.ts +++ b/packages/opencode/src/tool/apply_patch.ts @@ -161,7 +161,7 @@ export const ApplyPatchTool = Tool.define("apply_patch", { // Build per-file metadata for UI rendering (used for both permission and result) const files = fileChanges.map((change) => ({ filePath: change.filePath, - relativePath: path.relative(Instance.worktree, change.movePath ?? change.filePath), + relativePath: path.relative(Instance.worktree, change.movePath ?? change.filePath).replaceAll("\\", "/"), type: change.type, diff: change.diff, before: change.oldContent, @@ -172,7 +172,7 @@ export const ApplyPatchTool = Tool.define("apply_patch", { })) // Check permissions if needed - const relativePaths = fileChanges.map((c) => path.relative(Instance.worktree, c.filePath)) + const relativePaths = fileChanges.map((c) => path.relative(Instance.worktree, c.filePath).replaceAll("\\", "/")) await ctx.ask({ permission: "edit", patterns: relativePaths, @@ -242,13 +242,13 @@ export const ApplyPatchTool = Tool.define("apply_patch", { // Generate output summary const summaryLines = fileChanges.map((change) => { if (change.type === "add") { - return `A ${path.relative(Instance.worktree, change.filePath)}` + return `A ${path.relative(Instance.worktree, change.filePath).replaceAll("\\", "/")}` } if (change.type === "delete") { - return `D ${path.relative(Instance.worktree, change.filePath)}` + return `D ${path.relative(Instance.worktree, change.filePath).replaceAll("\\", "/")}` } const target = change.movePath ?? change.filePath - return `M ${path.relative(Instance.worktree, target)}` + return `M ${path.relative(Instance.worktree, target).replaceAll("\\", "/")}` }) let output = `Success. Updated the following files:\n${summaryLines.join("\n")}` @@ -264,7 +264,7 @@ export const ApplyPatchTool = Tool.define("apply_patch", { const limited = errors.slice(0, MAX_DIAGNOSTICS_PER_FILE) const suffix = errors.length > MAX_DIAGNOSTICS_PER_FILE ? `\n... and ${errors.length - MAX_DIAGNOSTICS_PER_FILE} more` : "" - output += `\n\nLSP errors detected in ${path.relative(Instance.worktree, target)}, please fix:\n<diagnostics file="${target}">\n${limited.map(LSP.Diagnostic.pretty).join("\n")}${suffix}\n</diagnostics>` + output += `\n\nLSP errors detected in ${path.relative(Instance.worktree, target).replaceAll("\\", "/")}, please fix:\n<diagnostics file="${target}">\n${limited.map(LSP.Diagnostic.pretty).join("\n")}${suffix}\n</diagnostics>` } } diff --git a/packages/opencode/src/tool/bash.ts b/packages/opencode/src/tool/bash.ts index ee2279bbfb..3be2734863 100644 --- a/packages/opencode/src/tool/bash.ts +++ b/packages/opencode/src/tool/bash.ts @@ -7,8 +7,8 @@ import { Log } from "../util/log" import { Instance } from "../project/instance" import { lazy } from "@/util/lazy" import { Language } from "web-tree-sitter" +import fs from "fs/promises" -import { $ } from "bun" import { Filesystem } from "@/util/filesystem" import { fileURLToPath } from "url" import { Flag } from "@/flag/flag.ts" @@ -116,19 +116,11 @@ export const BashTool = Tool.define("bash", async () => { if (["cd", "rm", "cp", "mv", "mkdir", "touch", "chmod", "chown", "cat"].includes(command[0])) { for (const arg of command.slice(1)) { if (arg.startsWith("-") || (command[0] === "chmod" && arg.startsWith("+"))) continue - const resolved = await $`realpath ${arg}` - .cwd(cwd) - .quiet() - .nothrow() - .text() - .then((x) => x.trim()) + const resolved = await fs.realpath(path.resolve(cwd, arg)).catch(() => "") log.info("resolved path", { arg, resolved }) if (resolved) { - // Git Bash on Windows returns Unix-style paths like /c/Users/... const normalized = - process.platform === "win32" && resolved.match(/^\/[a-z]\//) - ? resolved.replace(/^\/([a-z])\//, (_, drive) => `${drive.toUpperCase()}:\\`).replace(/\//g, "\\") - : resolved + process.platform === "win32" ? Filesystem.windowsPath(resolved).replace(/\//g, "\\") : resolved if (!Instance.containsPath(normalized)) { const dir = (await Filesystem.isDir(normalized)) ? normalized : path.dirname(normalized) directories.add(dir) @@ -145,7 +137,11 @@ export const BashTool = Tool.define("bash", async () => { } if (directories.size > 0) { - const globs = Array.from(directories).map((dir) => path.join(dir, "*")) + const globs = Array.from(directories).map((dir) => { + // Preserve POSIX-looking paths with /s, even on Windows + if (dir.startsWith("/")) return `${dir.replace(/[\\/]+$/, "")}/*` + return path.join(dir, "*") + }) await ctx.ask({ permission: "external_directory", patterns: globs, diff --git a/packages/opencode/src/tool/bash.txt b/packages/opencode/src/tool/bash.txt index 47e9378e75..baafb00810 100644 --- a/packages/opencode/src/tool/bash.txt +++ b/packages/opencode/src/tool/bash.txt @@ -24,7 +24,7 @@ Usage notes: - The command argument is required. - You can specify an optional timeout in milliseconds. If not specified, commands will time out after 120000ms (2 minutes). - It is very helpful if you write a clear, concise description of what this command does in 5-10 words. - - If the output exceeds ${maxLines} lines or ${maxBytes} bytes, it will be truncated and the full output will be written to a file. You can use Read with offset/limit to read specific sections or Grep to search the full content. Because of this, you do NOT need to use `head`, `tail`, or other truncation commands to limit output - just run the command directly. + - If the output exceeds ${maxLines} lines or ${maxBytes} bytes, it will be truncated and the full output will be written to a file. You can use Read with offset/limit to read specific sections or Grep to search the full content. Do NOT use `head`, `tail`, or other truncation commands to limit output; the full output will already be captured to a file for more precise searching. - Avoid using Bash with the `find`, `grep`, `cat`, `head`, `tail`, `sed`, `awk`, or `echo` commands, unless explicitly instructed or when these commands are truly necessary for the task. Instead, always prefer using the dedicated tools for these commands: - File search: Use Glob (NOT find or ls) diff --git a/packages/opencode/src/tool/edit.ts b/packages/opencode/src/tool/edit.ts index 7a097d3fe1..c7b12378ed 100644 --- a/packages/opencode/src/tool/edit.ts +++ b/packages/opencode/src/tool/edit.ts @@ -24,6 +24,15 @@ function normalizeLineEndings(text: string): string { return text.replaceAll("\r\n", "\n") } +function detectLineEnding(text: string): "\n" | "\r\n" { + return text.includes("\r\n") ? "\r\n" : "\n" +} + +function convertToLineEnding(text: string, ending: "\n" | "\r\n"): string { + if (ending === "\n") return text + return text.replaceAll("\n", "\r\n") +} + export const EditTool = Tool.define("edit", { description: DESCRIPTION, parameters: z.object({ @@ -78,7 +87,12 @@ export const EditTool = Tool.define("edit", { if (stats.isDirectory()) throw new Error(`Path is a directory, not a file: ${filePath}`) await FileTime.assert(ctx.sessionID, filePath) contentOld = await Filesystem.readText(filePath) - contentNew = replace(contentOld, params.oldString, params.newString, params.replaceAll) + + const ending = detectLineEnding(contentOld) + const old = convertToLineEnding(normalizeLineEndings(params.oldString), ending) + const next = convertToLineEnding(normalizeLineEndings(params.newString), ending) + + contentNew = replace(contentOld, old, next, params.replaceAll) diff = trimDiff( createTwoFilesPatch(filePath, filePath, normalizeLineEndings(contentOld), normalizeLineEndings(contentNew)), diff --git a/packages/opencode/src/tool/external-directory.ts b/packages/opencode/src/tool/external-directory.ts index 1d3958fc46..5d8885b2ad 100644 --- a/packages/opencode/src/tool/external-directory.ts +++ b/packages/opencode/src/tool/external-directory.ts @@ -18,7 +18,7 @@ export async function assertExternalDirectory(ctx: Tool.Context, target?: string const kind = options?.kind ?? "file" const parentDir = kind === "directory" ? target : path.dirname(target) - const glob = path.join(parentDir, "*") + const glob = path.join(parentDir, "*").replaceAll("\\", "/") await ctx.ask({ permission: "external_directory", diff --git a/packages/opencode/src/tool/grep.ts b/packages/opencode/src/tool/grep.ts index 00497d4e3f..82e7ac1667 100644 --- a/packages/opencode/src/tool/grep.ts +++ b/packages/opencode/src/tool/grep.ts @@ -1,7 +1,9 @@ import z from "zod" +import { text } from "node:stream/consumers" import { Tool } from "./tool" import { Filesystem } from "../util/filesystem" import { Ripgrep } from "../file/ripgrep" +import { Process } from "../util/process" import DESCRIPTION from "./grep.txt" import { Instance } from "../project/instance" @@ -44,14 +46,18 @@ export const GrepTool = Tool.define("grep", { } args.push(searchPath) - const proc = Bun.spawn([rgPath, ...args], { + const proc = Process.spawn([rgPath, ...args], { stdout: "pipe", stderr: "pipe", - signal: ctx.abort, + abort: ctx.abort, }) - const output = await new Response(proc.stdout).text() - const errorOutput = await new Response(proc.stderr).text() + if (!proc.stdout || !proc.stderr) { + throw new Error("Process output not available") + } + + const output = await text(proc.stdout) + const errorOutput = await text(proc.stderr) const exitCode = await proc.exited // Exit codes: 0 = matches found, 1 = no matches, 2 = errors (but may still have matches) diff --git a/packages/opencode/src/tool/plan.ts b/packages/opencode/src/tool/plan.ts index 6cb7a691c8..ff84dccec4 100644 --- a/packages/opencode/src/tool/plan.ts +++ b/packages/opencode/src/tool/plan.ts @@ -8,7 +8,6 @@ import { Identifier } from "../id/id" import { Provider } from "../provider/provider" import { Instance } from "../project/instance" import EXIT_DESCRIPTION from "./plan-exit.txt" -import ENTER_DESCRIPTION from "./plan-enter.txt" async function getLastModel(sessionID: string) { for await (const item of MessageV2.stream(sessionID)) { @@ -72,6 +71,7 @@ export const PlanExitTool = Tool.define("plan_exit", { }, }) +/* export const PlanEnterTool = Tool.define("plan_enter", { description: ENTER_DESCRIPTION, parameters: z.object({}), @@ -128,3 +128,4 @@ export const PlanEnterTool = Tool.define("plan_enter", { } }, }) +*/ diff --git a/packages/opencode/src/tool/registry.ts b/packages/opencode/src/tool/registry.ts index ef0e78ffa8..c6d7fbc1e4 100644 --- a/packages/opencode/src/tool/registry.ts +++ b/packages/opencode/src/tool/registry.ts @@ -1,3 +1,4 @@ +import { PlanExitTool } from "./plan" import { QuestionTool } from "./question" import { BashTool } from "./bash" import { EditTool } from "./edit" @@ -25,9 +26,10 @@ import { Flag } from "@/flag/flag" import { Log } from "@/util/log" import { LspTool } from "./lsp" import { Truncate } from "./truncation" -import { PlanExitTool, PlanEnterTool } from "./plan" + import { ApplyPatchTool } from "./apply_patch" import { Glob } from "../util/glob" +import { pathToFileURL } from "url" export namespace ToolRegistry { const log = Log.create({ service: "tool.registry" }) @@ -43,7 +45,7 @@ export namespace ToolRegistry { if (matches.length) await Config.waitForDependencies() for (const match of matches) { const namespace = path.basename(match, path.extname(match)) - const mod = await import(match) + const mod = await import(pathToFileURL(match).href) for (const [id, def] of Object.entries<ToolDefinition>(mod)) { custom.push(fromPlugin(id === "default" ? namespace : `${namespace}_${id}`, def)) } @@ -117,7 +119,7 @@ export namespace ToolRegistry { ApplyPatchTool, ...(Flag.OPENCODE_EXPERIMENTAL_LSP_TOOL ? [LspTool] : []), ...(config.experimental?.batch_tool === true ? [BatchTool] : []), - ...(Flag.OPENCODE_EXPERIMENTAL_PLAN_MODE && Flag.OPENCODE_CLIENT === "cli" ? [PlanExitTool, PlanEnterTool] : []), + ...(Flag.OPENCODE_EXPERIMENTAL_PLAN_MODE && Flag.OPENCODE_CLIENT === "cli" ? [PlanExitTool] : []), ...custom, ] } diff --git a/packages/opencode/src/util/archive.ts b/packages/opencode/src/util/archive.ts index 34a1738a8c..f65ceba547 100644 --- a/packages/opencode/src/util/archive.ts +++ b/packages/opencode/src/util/archive.ts @@ -1,5 +1,5 @@ -import { $ } from "bun" import path from "path" +import { Process } from "./process" export namespace Archive { export async function extractZip(zipPath: string, destDir: string) { @@ -8,9 +8,10 @@ export namespace Archive { const winDestDir = path.resolve(destDir) // $global:ProgressPreference suppresses PowerShell's blue progress bar popup const cmd = `$global:ProgressPreference = 'SilentlyContinue'; Expand-Archive -Path '${winZipPath}' -DestinationPath '${winDestDir}' -Force` - await $`powershell -NoProfile -NonInteractive -Command ${cmd}`.quiet() - } else { - await $`unzip -o -q ${zipPath} -d ${destDir}`.quiet() + await Process.run(["powershell", "-NoProfile", "-NonInteractive", "-Command", cmd]) + return } + + await Process.run(["unzip", "-o", "-q", zipPath, "-d", destDir]) } } diff --git a/packages/opencode/src/util/filesystem.ts b/packages/opencode/src/util/filesystem.ts index 3a1e8b8ec1..fb1f5ab9e5 100644 --- a/packages/opencode/src/util/filesystem.ts +++ b/packages/opencode/src/util/filesystem.ts @@ -2,7 +2,7 @@ import { chmod, mkdir, readFile, writeFile } from "fs/promises" import { createWriteStream, existsSync, statSync } from "fs" import { lookup } from "mime-types" import { realpathSync } from "fs" -import { dirname, join, relative } from "path" +import { dirname, join, relative, resolve as pathResolve } from "path" import { Readable } from "stream" import { pipeline } from "stream/promises" import { Glob } from "./glob" @@ -113,6 +113,24 @@ export namespace Filesystem { } } + // We cannot rely on path.resolve() here because git.exe may come from Git Bash, Cygwin, or MSYS2, so we need to translate these paths at the boundary. + export function resolve(p: string): string { + return normalizePath(pathResolve(windowsPath(p))) + } + + export function windowsPath(p: string): string { + if (process.platform !== "win32") return p + return ( + p + .replace(/^\/([a-zA-Z]):(?:[\\/]|$)/, (_, drive) => `${drive.toUpperCase()}:/`) + // Git Bash for Windows paths are typically /<drive>/... + .replace(/^\/([a-zA-Z])(?:\/|$)/, (_, drive) => `${drive.toUpperCase()}:/`) + // Cygwin git paths are typically /cygdrive/<drive>/... + .replace(/^\/cygdrive\/([a-zA-Z])(?:\/|$)/, (_, drive) => `${drive.toUpperCase()}:/`) + // WSL paths are typically /mnt/<drive>/... + .replace(/^\/mnt\/([a-zA-Z])(?:\/|$)/, (_, drive) => `${drive.toUpperCase()}:/`) + ) + } export function overlaps(a: string, b: string) { const relA = relative(a, b) const relB = relative(b, a) diff --git a/packages/opencode/src/util/fn.ts b/packages/opencode/src/util/fn.ts index 9efe4622fc..19c60265bb 100644 --- a/packages/opencode/src/util/fn.ts +++ b/packages/opencode/src/util/fn.ts @@ -2,7 +2,14 @@ import { z } from "zod" export function fn<T extends z.ZodType, Result>(schema: T, cb: (input: z.infer<T>) => Result) { const result = (input: z.infer<T>) => { - const parsed = schema.parse(input) + let parsed + try { + parsed = schema.parse(input) + } catch (e) { + console.trace("schema validation failure stack trace:") + throw e + } + return cb(parsed) } result.force = (input: z.infer<T>) => cb(input) diff --git a/packages/opencode/src/util/git.ts b/packages/opencode/src/util/git.ts index 201def36a8..731131357f 100644 --- a/packages/opencode/src/util/git.ts +++ b/packages/opencode/src/util/git.ts @@ -1,64 +1,35 @@ -import { $ } from "bun" -import { Flag } from "../flag/flag" +import { Process } from "./process" export interface GitResult { exitCode: number - text(): string | Promise<string> - stdout: Buffer | ReadableStream<Uint8Array> - stderr: Buffer | ReadableStream<Uint8Array> + text(): string + stdout: Buffer + stderr: Buffer } /** * Run a git command. * - * Uses Bun's lightweight `$` shell by default. When the process is running - * as an ACP client, child processes inherit the parent's stdin pipe which - * carries protocol data – on Windows this causes git to deadlock. In that - * case we fall back to `Bun.spawn` with `stdin: "ignore"`. + * Uses Process helpers with stdin ignored to avoid protocol pipe inheritance + * issues in embedded/client environments. */ export async function git(args: string[], opts: { cwd: string; env?: Record<string, string> }): Promise<GitResult> { - if (Flag.OPENCODE_CLIENT === "acp") { - try { - const proc = Bun.spawn(["git", ...args], { - stdin: "ignore", - stdout: "pipe", - stderr: "pipe", - cwd: opts.cwd, - env: opts.env ? { ...process.env, ...opts.env } : process.env, - }) - // Read output concurrently with exit to avoid pipe buffer deadlock - const [exitCode, stdout, stderr] = await Promise.all([ - proc.exited, - new Response(proc.stdout).arrayBuffer(), - new Response(proc.stderr).arrayBuffer(), - ]) - const stdoutBuf = Buffer.from(stdout) - const stderrBuf = Buffer.from(stderr) - return { - exitCode, - text: () => stdoutBuf.toString(), - stdout: stdoutBuf, - stderr: stderrBuf, - } - } catch (error) { - const stderr = Buffer.from(error instanceof Error ? error.message : String(error)) - return { - exitCode: 1, - text: () => "", - stdout: Buffer.alloc(0), - stderr, - } - } - } - - const env = opts.env ? { ...process.env, ...opts.env } : undefined - let cmd = $`git ${args}`.quiet().nothrow().cwd(opts.cwd) - if (env) cmd = cmd.env(env) - const result = await cmd - return { - exitCode: result.exitCode, - text: () => result.text(), - stdout: result.stdout, - stderr: result.stderr, - } + return Process.run(["git", ...args], { + cwd: opts.cwd, + env: opts.env, + stdin: "ignore", + nothrow: true, + }) + .then((result) => ({ + exitCode: result.code, + text: () => result.stdout.toString(), + stdout: result.stdout, + stderr: result.stderr, + })) + .catch((error) => ({ + exitCode: 1, + text: () => "", + stdout: Buffer.alloc(0), + stderr: Buffer.from(error instanceof Error ? error.message : String(error)), + })) } diff --git a/packages/opencode/src/util/hash.ts b/packages/opencode/src/util/hash.ts new file mode 100644 index 0000000000..680e0f40bc --- /dev/null +++ b/packages/opencode/src/util/hash.ts @@ -0,0 +1,7 @@ +import { createHash } from "crypto" + +export namespace Hash { + export function fast(input: string | Buffer): string { + return createHash("sha1").update(input).digest("hex") + } +} diff --git a/packages/opencode/src/util/keybind.ts b/packages/opencode/src/util/keybind.ts index 59318a31b0..83c7945ae1 100644 --- a/packages/opencode/src/util/keybind.ts +++ b/packages/opencode/src/util/keybind.ts @@ -23,7 +23,7 @@ export namespace Keybind { */ export function fromParsedKey(key: ParsedKey, leader = false): Info { return { - name: key.name, + name: key.name === " " ? "space" : key.name, ctrl: key.ctrl, meta: key.meta, shift: key.shift, diff --git a/packages/opencode/src/util/process.ts b/packages/opencode/src/util/process.ts new file mode 100644 index 0000000000..473ee27dc9 --- /dev/null +++ b/packages/opencode/src/util/process.ts @@ -0,0 +1,150 @@ +import { spawn as launch, type ChildProcess } from "child_process" +import { buffer } from "node:stream/consumers" + +export namespace Process { + export type Stdio = "inherit" | "pipe" | "ignore" + + export interface Options { + cwd?: string + env?: NodeJS.ProcessEnv | null + stdin?: Stdio + stdout?: Stdio + stderr?: Stdio + abort?: AbortSignal + kill?: NodeJS.Signals | number + timeout?: number + } + + export interface RunOptions extends Omit<Options, "stdout" | "stderr"> { + nothrow?: boolean + } + + export interface Result { + code: number + stdout: Buffer + stderr: Buffer + } + + export interface TextResult extends Result { + text: string + } + + export class RunFailedError extends Error { + readonly cmd: string[] + readonly code: number + readonly stdout: Buffer + readonly stderr: Buffer + + constructor(cmd: string[], code: number, stdout: Buffer, stderr: Buffer) { + const text = stderr.toString().trim() + super( + text + ? `Command failed with code ${code}: ${cmd.join(" ")}\n${text}` + : `Command failed with code ${code}: ${cmd.join(" ")}`, + ) + this.name = "ProcessRunFailedError" + this.cmd = [...cmd] + this.code = code + this.stdout = stdout + this.stderr = stderr + } + } + + export type Child = ChildProcess & { exited: Promise<number> } + + export function spawn(cmd: string[], opts: Options = {}): Child { + if (cmd.length === 0) throw new Error("Command is required") + opts.abort?.throwIfAborted() + + const proc = launch(cmd[0], cmd.slice(1), { + cwd: opts.cwd, + env: opts.env === null ? {} : opts.env ? { ...process.env, ...opts.env } : undefined, + stdio: [opts.stdin ?? "ignore", opts.stdout ?? "ignore", opts.stderr ?? "ignore"], + }) + + let closed = false + let timer: ReturnType<typeof setTimeout> | undefined + + const abort = () => { + if (closed) return + if (proc.exitCode !== null || proc.signalCode !== null) return + closed = true + + proc.kill(opts.kill ?? "SIGTERM") + + const ms = opts.timeout ?? 5_000 + if (ms <= 0) return + timer = setTimeout(() => proc.kill("SIGKILL"), ms) + } + + const exited = new Promise<number>((resolve, reject) => { + const done = () => { + opts.abort?.removeEventListener("abort", abort) + if (timer) clearTimeout(timer) + } + + proc.once("exit", (code, signal) => { + done() + resolve(code ?? (signal ? 1 : 0)) + }) + + proc.once("error", (error) => { + done() + reject(error) + }) + }) + + if (opts.abort) { + opts.abort.addEventListener("abort", abort, { once: true }) + if (opts.abort.aborted) abort() + } + + const child = proc as Child + child.exited = exited + return child + } + + export async function run(cmd: string[], opts: RunOptions = {}): Promise<Result> { + const proc = spawn(cmd, { + cwd: opts.cwd, + env: opts.env, + stdin: opts.stdin, + abort: opts.abort, + kill: opts.kill, + timeout: opts.timeout, + stdout: "pipe", + stderr: "pipe", + }) + + if (!proc.stdout || !proc.stderr) throw new Error("Process output not available") + + const out = await Promise.all([proc.exited, buffer(proc.stdout), buffer(proc.stderr)]) + .then(([code, stdout, stderr]) => ({ + code, + stdout, + stderr, + })) + .catch((err: unknown) => { + if (!opts.nothrow) throw err + return { + code: 1, + stdout: Buffer.alloc(0), + stderr: Buffer.from(err instanceof Error ? err.message : String(err)), + } + }) + if (out.code === 0 || opts.nothrow) return out + throw new RunFailedError(cmd, out.code, out.stdout, out.stderr) + } + + export async function text(cmd: string[], opts: RunOptions = {}): Promise<TextResult> { + const out = await run(cmd, opts) + return { + ...out, + text: out.stdout.toString(), + } + } + + export async function lines(cmd: string[], opts: RunOptions = {}): Promise<string[]> { + return (await text(cmd, opts)).text.split(/\r?\n/).filter(Boolean) + } +} diff --git a/packages/opencode/src/util/which.ts b/packages/opencode/src/util/which.ts new file mode 100644 index 0000000000..81da257217 --- /dev/null +++ b/packages/opencode/src/util/which.ts @@ -0,0 +1,10 @@ +import whichPkg from "which" + +export function which(cmd: string, env?: NodeJS.ProcessEnv) { + const result = whichPkg.sync(cmd, { + nothrow: true, + path: env?.PATH ?? env?.Path ?? process.env.PATH ?? process.env.Path, + pathExt: env?.PATHEXT ?? env?.PathExt ?? process.env.PATHEXT ?? process.env.PathExt, + }) + return typeof result === "string" ? result : null +} diff --git a/packages/opencode/src/util/wildcard.ts b/packages/opencode/src/util/wildcard.ts index 4a6eba96ff..f54b6c85fd 100644 --- a/packages/opencode/src/util/wildcard.ts +++ b/packages/opencode/src/util/wildcard.ts @@ -2,6 +2,8 @@ import { sortBy, pipe } from "remeda" export namespace Wildcard { export function match(str: string, pattern: string) { + if (str) str = str.replaceAll("\\", "/") + if (pattern) pattern = pattern.replaceAll("\\", "/") let escaped = pattern .replace(/[.+^${}()|[\]\\]/g, "\\$&") // escape special regex chars .replace(/\*/g, ".*") // * becomes .* @@ -13,7 +15,8 @@ export namespace Wildcard { escaped = escaped.slice(0, -3) + "( .*)?" } - return new RegExp("^" + escaped + "$", "s").test(str) + const flags = process.platform === "win32" ? "si" : "s" + return new RegExp("^" + escaped + "$", flags).test(str) } export function all(input: string, patterns: Record<string, any>) { diff --git a/packages/opencode/src/worktree/index.ts b/packages/opencode/src/worktree/index.ts index d85a0843fb..8b5accc333 100644 --- a/packages/opencode/src/worktree/index.ts +++ b/packages/opencode/src/worktree/index.ts @@ -1,4 +1,3 @@ -import { $ } from "bun" import fs from "fs/promises" import path from "path" import z from "zod" @@ -11,6 +10,8 @@ import { Database, eq } from "../storage/db" import { ProjectTable } from "../project/project.sql" import { fn } from "../util/fn" import { Log } from "../util/log" +import { Process } from "../util/process" +import { git } from "../util/git" import { BusEvent } from "@/bus/bus-event" import { GlobalBus } from "@/bus/global" @@ -248,14 +249,14 @@ export namespace Worktree { } async function sweep(root: string) { - const first = await $`git clean -ffdx`.quiet().nothrow().cwd(root) + const first = await git(["clean", "-ffdx"], { cwd: root }) if (first.exitCode === 0) return first const entries = failed(first) if (!entries.length) return first await prune(root, entries) - return $`git clean -ffdx`.quiet().nothrow().cwd(root) + return git(["clean", "-ffdx"], { cwd: root }) } async function canonical(input: string) { @@ -274,7 +275,9 @@ export namespace Worktree { if (await exists(directory)) continue const ref = `refs/heads/${branch}` - const branchCheck = await $`git show-ref --verify --quiet ${ref}`.quiet().nothrow().cwd(Instance.worktree) + const branchCheck = await git(["show-ref", "--verify", "--quiet", ref], { + cwd: Instance.worktree, + }) if (branchCheck.exitCode === 0) continue return Info.parse({ name, branch, directory }) @@ -285,9 +288,9 @@ export namespace Worktree { async function runStartCommand(directory: string, cmd: string) { if (process.platform === "win32") { - return $`cmd /c ${cmd}`.nothrow().cwd(directory) + return Process.run(["cmd", "/c", cmd], { cwd: directory, nothrow: true }) } - return $`bash -lc ${cmd}`.nothrow().cwd(directory) + return Process.run(["bash", "-lc", cmd], { cwd: directory, nothrow: true }) } type StartKind = "project" | "worktree" @@ -297,7 +300,7 @@ export namespace Worktree { if (!text) return true const ran = await runStartCommand(directory, text) - if (ran.exitCode === 0) return true + if (ran.code === 0) return true log.error("worktree start command failed", { kind, @@ -331,7 +334,7 @@ export namespace Worktree { }, 0) } - export const create = fn(CreateInput.optional(), async (input) => { + export async function makeWorktreeInfo(name?: string): Promise<Info> { if (Instance.project.vcs !== "git") { throw new NotGitError({ message: "Worktrees are only supported for git projects" }) } @@ -339,13 +342,14 @@ export namespace Worktree { const root = path.join(Global.Path.data, "worktree", Instance.project.id) await fs.mkdir(root, { recursive: true }) - const base = input?.name ? slug(input.name) : "" - const info = await candidate(root, base || undefined) + const base = name ? slug(name) : "" + return candidate(root, base || undefined) + } - const created = await $`git worktree add --no-checkout -b ${info.branch} ${info.directory}` - .quiet() - .nothrow() - .cwd(Instance.worktree) + export async function createFromInfo(info: Info, startCommand?: string) { + const created = await git(["worktree", "add", "--no-checkout", "-b", info.branch, info.directory], { + cwd: Instance.worktree, + }) if (created.exitCode !== 0) { throw new CreateFailedError({ message: errorText(created) || "Failed to create git worktree" }) } @@ -353,10 +357,11 @@ export namespace Worktree { await Project.addSandbox(Instance.project.id, info.directory).catch(() => undefined) const projectID = Instance.project.id - const extra = input?.startCommand?.trim() - setTimeout(() => { + const extra = startCommand?.trim() + + return () => { const start = async () => { - const populated = await $`git reset --hard`.quiet().nothrow().cwd(info.directory) + const populated = await git(["reset", "--hard"], { cwd: info.directory }) if (populated.exitCode !== 0) { const message = errorText(populated) || "Failed to populate worktree" log.error("worktree checkout failed", { directory: info.directory, message }) @@ -411,8 +416,17 @@ export namespace Worktree { void start().catch((error) => { log.error("worktree start task failed", { directory: info.directory, error }) }) - }, 0) + } + } + export const create = fn(CreateInput.optional(), async (input) => { + const info = await makeWorktreeInfo(input?.name) + const bootstrap = await createFromInfo(info, input?.startCommand) + // This is needed due to how worktrees currently work in the + // desktop app + setTimeout(() => { + bootstrap() + }, 0) return info }) @@ -462,7 +476,12 @@ export namespace Worktree { throw new RemoveFailedError({ message: message || "Failed to remove git worktree directory" }) }) - const list = await $`git worktree list --porcelain`.quiet().nothrow().cwd(Instance.worktree) + const stop = async (target: string) => { + if (!(await exists(target))) return + await git(["fsmonitor--daemon", "stop"], { cwd: target }) + } + + const list = await git(["worktree", "list", "--porcelain"], { cwd: Instance.worktree }) if (list.exitCode !== 0) { throw new RemoveFailedError({ message: errorText(list) || "Failed to read git worktrees" }) } @@ -472,14 +491,18 @@ export namespace Worktree { if (!entry?.path) { const directoryExists = await exists(directory) if (directoryExists) { + await stop(directory) await clean(directory) } return true } - const removed = await $`git worktree remove --force ${entry.path}`.quiet().nothrow().cwd(Instance.worktree) + await stop(entry.path) + const removed = await git(["worktree", "remove", "--force", entry.path], { + cwd: Instance.worktree, + }) if (removed.exitCode !== 0) { - const next = await $`git worktree list --porcelain`.quiet().nothrow().cwd(Instance.worktree) + const next = await git(["worktree", "list", "--porcelain"], { cwd: Instance.worktree }) if (next.exitCode !== 0) { throw new RemoveFailedError({ message: errorText(removed) || errorText(next) || "Failed to remove git worktree", @@ -496,7 +519,7 @@ export namespace Worktree { const branch = entry.branch?.replace(/^refs\/heads\//, "") if (branch) { - const deleted = await $`git branch -D ${branch}`.quiet().nothrow().cwd(Instance.worktree) + const deleted = await git(["branch", "-D", branch], { cwd: Instance.worktree }) if (deleted.exitCode !== 0) { throw new RemoveFailedError({ message: errorText(deleted) || "Failed to delete worktree branch" }) } @@ -516,7 +539,7 @@ export namespace Worktree { throw new ResetFailedError({ message: "Cannot reset the primary workspace" }) } - const list = await $`git worktree list --porcelain`.quiet().nothrow().cwd(Instance.worktree) + const list = await git(["worktree", "list", "--porcelain"], { cwd: Instance.worktree }) if (list.exitCode !== 0) { throw new ResetFailedError({ message: errorText(list) || "Failed to read git worktrees" }) } @@ -549,7 +572,7 @@ export namespace Worktree { throw new ResetFailedError({ message: "Worktree not found" }) } - const remoteList = await $`git remote`.quiet().nothrow().cwd(Instance.worktree) + const remoteList = await git(["remote"], { cwd: Instance.worktree }) if (remoteList.exitCode !== 0) { throw new ResetFailedError({ message: errorText(remoteList) || "Failed to list git remotes" }) } @@ -568,18 +591,19 @@ export namespace Worktree { : "" const remoteHead = remote - ? await $`git symbolic-ref refs/remotes/${remote}/HEAD`.quiet().nothrow().cwd(Instance.worktree) + ? await git(["symbolic-ref", `refs/remotes/${remote}/HEAD`], { cwd: Instance.worktree }) : { exitCode: 1, stdout: undefined, stderr: undefined } const remoteRef = remoteHead.exitCode === 0 ? outputText(remoteHead.stdout) : "" const remoteTarget = remoteRef ? remoteRef.replace(/^refs\/remotes\//, "") : "" const remoteBranch = remote && remoteTarget.startsWith(`${remote}/`) ? remoteTarget.slice(`${remote}/`.length) : "" - const mainCheck = await $`git show-ref --verify --quiet refs/heads/main`.quiet().nothrow().cwd(Instance.worktree) - const masterCheck = await $`git show-ref --verify --quiet refs/heads/master` - .quiet() - .nothrow() - .cwd(Instance.worktree) + const mainCheck = await git(["show-ref", "--verify", "--quiet", "refs/heads/main"], { + cwd: Instance.worktree, + }) + const masterCheck = await git(["show-ref", "--verify", "--quiet", "refs/heads/master"], { + cwd: Instance.worktree, + }) const localBranch = mainCheck.exitCode === 0 ? "main" : masterCheck.exitCode === 0 ? "master" : "" const target = remoteBranch ? `${remote}/${remoteBranch}` : localBranch @@ -588,7 +612,7 @@ export namespace Worktree { } if (remoteBranch) { - const fetch = await $`git fetch ${remote} ${remoteBranch}`.quiet().nothrow().cwd(Instance.worktree) + const fetch = await git(["fetch", remote, remoteBranch], { cwd: Instance.worktree }) if (fetch.exitCode !== 0) { throw new ResetFailedError({ message: errorText(fetch) || `Failed to fetch ${target}` }) } @@ -600,7 +624,7 @@ export namespace Worktree { const worktreePath = entry.path - const resetToTarget = await $`git reset --hard ${target}`.quiet().nothrow().cwd(worktreePath) + const resetToTarget = await git(["reset", "--hard", target], { cwd: worktreePath }) if (resetToTarget.exitCode !== 0) { throw new ResetFailedError({ message: errorText(resetToTarget) || "Failed to reset worktree to target" }) } @@ -610,22 +634,26 @@ export namespace Worktree { throw new ResetFailedError({ message: errorText(clean) || "Failed to clean worktree" }) } - const update = await $`git submodule update --init --recursive --force`.quiet().nothrow().cwd(worktreePath) + const update = await git(["submodule", "update", "--init", "--recursive", "--force"], { cwd: worktreePath }) if (update.exitCode !== 0) { throw new ResetFailedError({ message: errorText(update) || "Failed to update submodules" }) } - const subReset = await $`git submodule foreach --recursive git reset --hard`.quiet().nothrow().cwd(worktreePath) + const subReset = await git(["submodule", "foreach", "--recursive", "git", "reset", "--hard"], { + cwd: worktreePath, + }) if (subReset.exitCode !== 0) { throw new ResetFailedError({ message: errorText(subReset) || "Failed to reset submodules" }) } - const subClean = await $`git submodule foreach --recursive git clean -fdx`.quiet().nothrow().cwd(worktreePath) + const subClean = await git(["submodule", "foreach", "--recursive", "git", "clean", "-fdx"], { + cwd: worktreePath, + }) if (subClean.exitCode !== 0) { throw new ResetFailedError({ message: errorText(subClean) || "Failed to clean submodules" }) } - const status = await $`git status --porcelain=v1`.quiet().nothrow().cwd(worktreePath) + const status = await git(["-c", "core.fsmonitor=false", "status", "--porcelain=v1"], { cwd: worktreePath }) if (status.exitCode !== 0) { throw new ResetFailedError({ message: errorText(status) || "Failed to read git status" }) } diff --git a/packages/opencode/test/acp/event-subscription.test.ts b/packages/opencode/test/acp/event-subscription.test.ts index 1145a1357d..1abf578281 100644 --- a/packages/opencode/test/acp/event-subscription.test.ts +++ b/packages/opencode/test/acp/event-subscription.test.ts @@ -1,7 +1,7 @@ import { describe, expect, test } from "bun:test" import { ACP } from "../../src/acp/agent" import type { AgentSideConnection } from "@agentclientprotocol/sdk" -import type { Event } from "@opencode-ai/sdk/v2" +import type { Event, EventMessagePartUpdated, ToolStatePending, ToolStateRunning } from "@opencode-ai/sdk/v2" import { Instance } from "../../src/project/instance" import { tmpdir } from "../fixture/fixture" @@ -19,6 +19,61 @@ type EventController = { close: () => void } +function inProgressText(update: SessionUpdateParams["update"]) { + if (update.sessionUpdate !== "tool_call_update") return undefined + if (update.status !== "in_progress") return undefined + if (!update.content || !Array.isArray(update.content)) return undefined + const first = update.content[0] + if (!first || first.type !== "content") return undefined + if (first.content.type !== "text") return undefined + return first.content.text +} + +function isToolCallUpdate( + update: SessionUpdateParams["update"], +): update is Extract<SessionUpdateParams["update"], { sessionUpdate: "tool_call_update" }> { + return update.sessionUpdate === "tool_call_update" +} + +function toolEvent( + sessionId: string, + cwd: string, + opts: { + callID: string + tool: string + input: Record<string, unknown> + } & ({ status: "running"; metadata?: Record<string, unknown> } | { status: "pending"; raw: string }), +): GlobalEventEnvelope { + const state: ToolStatePending | ToolStateRunning = + opts.status === "running" + ? { + status: "running", + input: opts.input, + ...(opts.metadata && { metadata: opts.metadata }), + time: { start: Date.now() }, + } + : { + status: "pending", + input: opts.input, + raw: opts.raw, + } + const payload: EventMessagePartUpdated = { + type: "message.part.updated", + properties: { + part: { + id: `part_${opts.callID}`, + sessionID: sessionId, + messageID: `msg_${opts.callID}`, + type: "tool", + callID: opts.callID, + tool: opts.tool, + state, + }, + }, + } + return { directory: cwd, payload } +} + function createEventStream() { const queue: GlobalEventEnvelope[] = [] const waiters: Array<(value: GlobalEventEnvelope | undefined) => void> = [] @@ -65,6 +120,7 @@ function createEventStream() { function createFakeAgent() { const updates = new Map<string, string[]>() const chunks = new Map<string, string>() + const sessionUpdates: SessionUpdateParams[] = [] const record = (sessionId: string, type: string) => { const list = updates.get(sessionId) ?? [] list.push(type) @@ -73,6 +129,7 @@ function createFakeAgent() { const connection = { async sessionUpdate(params: SessionUpdateParams) { + sessionUpdates.push(params) const update = params.update const type = update?.sessionUpdate ?? "unknown" record(params.sessionId, type) @@ -197,7 +254,7 @@ function createFakeAgent() { ;(agent as any).eventAbort.abort() } - return { agent, controller, calls, updates, chunks, stop, sdk, connection } + return { agent, controller, calls, updates, chunks, sessionUpdates, stop, sdk, connection } } describe("acp.agent event subscription", () => { @@ -435,4 +492,192 @@ describe("acp.agent event subscription", () => { }, }) }) + + test("streams running bash output snapshots and de-dupes identical snapshots", async () => { + await using tmp = await tmpdir() + await Instance.provide({ + directory: tmp.path, + fn: async () => { + const { agent, controller, sessionUpdates, stop } = createFakeAgent() + const cwd = "/tmp/opencode-acp-test" + const sessionId = await agent.newSession({ cwd, mcpServers: [] } as any).then((x) => x.sessionId) + const input = { command: "echo hello", description: "run command" } + + for (const output of ["a", "a", "ab"]) { + controller.push( + toolEvent(sessionId, cwd, { + callID: "call_1", + tool: "bash", + status: "running", + input, + metadata: { output }, + }), + ) + } + await new Promise((r) => setTimeout(r, 20)) + + const snapshots = sessionUpdates + .filter((u) => u.sessionId === sessionId) + .filter((u) => isToolCallUpdate(u.update)) + .map((u) => inProgressText(u.update)) + + expect(snapshots).toEqual(["a", undefined, "ab"]) + stop() + }, + }) + }) + + test("emits synthetic pending before first running update for any tool", async () => { + await using tmp = await tmpdir() + await Instance.provide({ + directory: tmp.path, + fn: async () => { + const { agent, controller, sessionUpdates, stop } = createFakeAgent() + const cwd = "/tmp/opencode-acp-test" + const sessionId = await agent.newSession({ cwd, mcpServers: [] } as any).then((x) => x.sessionId) + + controller.push( + toolEvent(sessionId, cwd, { + callID: "call_bash", + tool: "bash", + status: "running", + input: { command: "echo hi", description: "run command" }, + metadata: { output: "hi\n" }, + }), + ) + controller.push( + toolEvent(sessionId, cwd, { + callID: "call_read", + tool: "read", + status: "running", + input: { filePath: "/tmp/example.txt" }, + }), + ) + await new Promise((r) => setTimeout(r, 20)) + + const types = sessionUpdates + .filter((u) => u.sessionId === sessionId) + .map((u) => u.update.sessionUpdate) + .filter((u) => u === "tool_call" || u === "tool_call_update") + expect(types).toEqual(["tool_call", "tool_call_update", "tool_call", "tool_call_update"]) + + const pendings = sessionUpdates.filter( + (u) => u.sessionId === sessionId && u.update.sessionUpdate === "tool_call", + ) + expect(pendings.every((p) => p.update.sessionUpdate === "tool_call" && p.update.status === "pending")).toBe( + true, + ) + stop() + }, + }) + }) + + test("does not emit duplicate synthetic pending after replayed running tool", async () => { + await using tmp = await tmpdir() + await Instance.provide({ + directory: tmp.path, + fn: async () => { + const { agent, controller, sessionUpdates, stop, sdk } = createFakeAgent() + const cwd = "/tmp/opencode-acp-test" + const sessionId = await agent.newSession({ cwd, mcpServers: [] } as any).then((x) => x.sessionId) + const input = { command: "echo hi", description: "run command" } + + sdk.session.messages = async () => ({ + data: [ + { + info: { + role: "assistant", + sessionID: sessionId, + }, + parts: [ + { + type: "tool", + callID: "call_1", + tool: "bash", + state: { + status: "running", + input, + metadata: { output: "hi\n" }, + time: { start: Date.now() }, + }, + }, + ], + }, + ], + }) + + await agent.loadSession({ sessionId, cwd, mcpServers: [] } as any) + controller.push( + toolEvent(sessionId, cwd, { + callID: "call_1", + tool: "bash", + status: "running", + input, + metadata: { output: "hi\nthere\n" }, + }), + ) + await new Promise((r) => setTimeout(r, 20)) + + const types = sessionUpdates + .filter((u) => u.sessionId === sessionId) + .map((u) => u.update) + .filter((u) => "toolCallId" in u && u.toolCallId === "call_1") + .map((u) => u.sessionUpdate) + .filter((u) => u === "tool_call" || u === "tool_call_update") + + expect(types).toEqual(["tool_call", "tool_call_update", "tool_call_update"]) + stop() + }, + }) + }) + + test("clears bash snapshot marker on pending state", async () => { + await using tmp = await tmpdir() + await Instance.provide({ + directory: tmp.path, + fn: async () => { + const { agent, controller, sessionUpdates, stop } = createFakeAgent() + const cwd = "/tmp/opencode-acp-test" + const sessionId = await agent.newSession({ cwd, mcpServers: [] } as any).then((x) => x.sessionId) + const input = { command: "echo hello", description: "run command" } + + controller.push( + toolEvent(sessionId, cwd, { + callID: "call_1", + tool: "bash", + status: "running", + input, + metadata: { output: "a" }, + }), + ) + controller.push( + toolEvent(sessionId, cwd, { + callID: "call_1", + tool: "bash", + status: "pending", + input, + raw: '{"command":"echo hello"}', + }), + ) + controller.push( + toolEvent(sessionId, cwd, { + callID: "call_1", + tool: "bash", + status: "running", + input, + metadata: { output: "a" }, + }), + ) + await new Promise((r) => setTimeout(r, 20)) + + const snapshots = sessionUpdates + .filter((u) => u.sessionId === sessionId) + .filter((u) => isToolCallUpdate(u.update)) + .map((u) => inProgressText(u.update)) + + expect(snapshots).toEqual(["a", "a"]) + stop() + }, + }) + }) }) diff --git a/packages/opencode/test/auth/auth.test.ts b/packages/opencode/test/auth/auth.test.ts new file mode 100644 index 0000000000..a569c71139 --- /dev/null +++ b/packages/opencode/test/auth/auth.test.ts @@ -0,0 +1,58 @@ +import { test, expect } from "bun:test" +import { Auth } from "../../src/auth" + +test("set normalizes trailing slashes in keys", async () => { + await Auth.set("https://example.com/", { + type: "wellknown", + key: "TOKEN", + token: "abc", + }) + const data = await Auth.all() + expect(data["https://example.com"]).toBeDefined() + expect(data["https://example.com/"]).toBeUndefined() +}) + +test("set cleans up pre-existing trailing-slash entry", async () => { + // Simulate a pre-fix entry with trailing slash + await Auth.set("https://example.com/", { + type: "wellknown", + key: "TOKEN", + token: "old", + }) + // Re-login with normalized key (as the CLI does post-fix) + await Auth.set("https://example.com", { + type: "wellknown", + key: "TOKEN", + token: "new", + }) + const data = await Auth.all() + const keys = Object.keys(data).filter((k) => k.includes("example.com")) + expect(keys).toEqual(["https://example.com"]) + const entry = data["https://example.com"]! + expect(entry.type).toBe("wellknown") + if (entry.type === "wellknown") expect(entry.token).toBe("new") +}) + +test("remove deletes both trailing-slash and normalized keys", async () => { + await Auth.set("https://example.com", { + type: "wellknown", + key: "TOKEN", + token: "abc", + }) + await Auth.remove("https://example.com/") + const data = await Auth.all() + expect(data["https://example.com"]).toBeUndefined() + expect(data["https://example.com/"]).toBeUndefined() +}) + +test("set and remove are no-ops on keys without trailing slashes", async () => { + await Auth.set("anthropic", { + type: "api", + key: "sk-test", + }) + const data = await Auth.all() + expect(data["anthropic"]).toBeDefined() + await Auth.remove("anthropic") + const after = await Auth.all() + expect(after["anthropic"]).toBeUndefined() +}) diff --git a/packages/opencode/test/cli/tui/thread.test.ts b/packages/opencode/test/cli/tui/thread.test.ts new file mode 100644 index 0000000000..d3de7c3183 --- /dev/null +++ b/packages/opencode/test/cli/tui/thread.test.ts @@ -0,0 +1,157 @@ +import { describe, expect, mock, test } from "bun:test" +import fs from "fs/promises" +import path from "path" +import { tmpdir } from "../../fixture/fixture" + +const stop = new Error("stop") +const seen = { + tui: [] as string[], + inst: [] as string[], +} + +mock.module("../../../src/cli/cmd/tui/app", () => ({ + tui: async (input: { directory: string }) => { + seen.tui.push(input.directory) + throw stop + }, +})) + +mock.module("@/util/rpc", () => ({ + Rpc: { + client: () => ({ + call: async () => ({ url: "http://127.0.0.1" }), + on: () => {}, + }), + }, +})) + +mock.module("@/cli/ui", () => ({ + UI: { + error: () => {}, + }, +})) + +mock.module("@/util/log", () => ({ + Log: { + init: async () => {}, + create: () => ({ + error: () => {}, + info: () => {}, + warn: () => {}, + debug: () => {}, + time: () => ({ stop: () => {} }), + }), + Default: { + error: () => {}, + info: () => {}, + warn: () => {}, + debug: () => {}, + }, + }, +})) + +mock.module("@/util/timeout", () => ({ + withTimeout: <T>(input: Promise<T>) => input, +})) + +mock.module("@/cli/network", () => ({ + withNetworkOptions: <T>(input: T) => input, + resolveNetworkOptions: async () => ({ + mdns: false, + port: 0, + hostname: "127.0.0.1", + }), +})) + +mock.module("../../../src/cli/cmd/tui/win32", () => ({ + win32DisableProcessedInput: () => {}, + win32InstallCtrlCGuard: () => undefined, +})) + +mock.module("@/config/tui", () => ({ + TuiConfig: { + get: () => ({}), + }, +})) + +mock.module("@/project/instance", () => ({ + Instance: { + provide: async (input: { directory: string; fn: () => Promise<unknown> | unknown }) => { + seen.inst.push(input.directory) + return input.fn() + }, + }, +})) + +describe("tui thread", () => { + async function call(project?: string) { + const { TuiThreadCommand } = await import("../../../src/cli/cmd/tui/thread") + const args: Parameters<NonNullable<typeof TuiThreadCommand.handler>>[0] = { + _: [], + $0: "opencode", + project, + prompt: "hi", + model: undefined, + agent: undefined, + session: undefined, + continue: false, + fork: false, + port: 0, + hostname: "127.0.0.1", + mdns: false, + "mdns-domain": "opencode.local", + mdnsDomain: "opencode.local", + cors: [], + } + return TuiThreadCommand.handler(args) + } + + async function check(project?: string) { + await using tmp = await tmpdir({ git: true }) + const cwd = process.cwd() + const pwd = process.env.PWD + const worker = globalThis.Worker + const tty = Object.getOwnPropertyDescriptor(process.stdin, "isTTY") + const link = path.join(path.dirname(tmp.path), path.basename(tmp.path) + "-link") + const type = process.platform === "win32" ? "junction" : "dir" + seen.tui.length = 0 + seen.inst.length = 0 + await fs.symlink(tmp.path, link, type) + + Object.defineProperty(process.stdin, "isTTY", { + configurable: true, + value: true, + }) + globalThis.Worker = class extends EventTarget { + onerror = null + onmessage = null + onmessageerror = null + postMessage() {} + terminate() {} + } as unknown as typeof Worker + + try { + process.chdir(tmp.path) + process.env.PWD = link + await expect(call(project)).rejects.toBe(stop) + expect(seen.inst[0]).toBe(tmp.path) + expect(seen.tui[0]).toBe(tmp.path) + } finally { + process.chdir(cwd) + if (pwd === undefined) delete process.env.PWD + else process.env.PWD = pwd + if (tty) Object.defineProperty(process.stdin, "isTTY", tty) + else delete (process.stdin as { isTTY?: boolean }).isTTY + globalThis.Worker = worker + await fs.rm(link, { recursive: true, force: true }).catch(() => undefined) + } + } + + test("uses the real cwd when PWD points at a symlink", async () => { + await check() + }) + + test("uses the real cwd after resolving a relative project from PWD", async () => { + await check(".") + }) +}) diff --git a/packages/opencode/test/config/config.test.ts b/packages/opencode/test/config/config.test.ts index 56773570af..96fac8cca2 100644 --- a/packages/opencode/test/config/config.test.ts +++ b/packages/opencode/test/config/config.test.ts @@ -25,6 +25,34 @@ async function writeConfig(dir: string, config: object, name = "opencode.json") await Filesystem.write(path.join(dir, name), JSON.stringify(config)) } +async function check(map: (dir: string) => string) { + if (process.platform !== "win32") return + await using globalTmp = await tmpdir() + await using tmp = await tmpdir({ git: true, config: { snapshot: true } }) + const prev = Global.Path.config + ;(Global.Path as { config: string }).config = globalTmp.path + Config.global.reset() + try { + await writeConfig(globalTmp.path, { + $schema: "https://opencode.ai/config.json", + snapshot: false, + }) + await Instance.provide({ + directory: map(tmp.path), + fn: async () => { + const cfg = await Config.get() + expect(cfg.snapshot).toBe(true) + expect(Instance.directory).toBe(Filesystem.resolve(tmp.path)) + expect(Instance.project.id).not.toBe("global") + }, + }) + } finally { + await Instance.disposeAll() + ;(Global.Path as { config: string }).config = prev + Config.global.reset() + } +} + test("loads config with defaults when no files exist", async () => { await using tmp = await tmpdir() await Instance.provide({ @@ -56,6 +84,45 @@ test("loads JSON config file", async () => { }) }) +test("loads project config from Git Bash and MSYS2 paths on Windows", async () => { + // Git Bash and MSYS2 both use /<drive>/... paths on Windows. + await check((dir) => { + const drive = dir[0].toLowerCase() + const rest = dir.slice(2).replaceAll("\\", "/") + return `/${drive}${rest}` + }) +}) + +test("loads project config from Cygwin paths on Windows", async () => { + await check((dir) => { + const drive = dir[0].toLowerCase() + const rest = dir.slice(2).replaceAll("\\", "/") + return `/cygdrive/${drive}${rest}` + }) +}) + +test("ignores legacy tui keys in opencode config", async () => { + await using tmp = await tmpdir({ + init: async (dir) => { + await writeConfig(dir, { + $schema: "https://opencode.ai/config.json", + model: "test/model", + theme: "legacy", + tui: { scroll_speed: 4 }, + }) + }, + }) + await Instance.provide({ + directory: tmp.path, + fn: async () => { + const config = await Config.get() + expect(config.model).toBe("test/model") + expect((config as Record<string, unknown>).theme).toBeUndefined() + expect((config as Record<string, unknown>).tui).toBeUndefined() + }, + }) +}) + test("loads JSONC config file", async () => { await using tmp = await tmpdir({ init: async (dir) => { @@ -110,14 +177,14 @@ test("merges multiple config files with correct precedence", async () => { test("handles environment variable substitution", async () => { const originalEnv = process.env["TEST_VAR"] - process.env["TEST_VAR"] = "test_theme" + process.env["TEST_VAR"] = "test-user" try { await using tmp = await tmpdir({ init: async (dir) => { await writeConfig(dir, { $schema: "https://opencode.ai/config.json", - theme: "{env:TEST_VAR}", + username: "{env:TEST_VAR}", }) }, }) @@ -125,7 +192,7 @@ test("handles environment variable substitution", async () => { directory: tmp.path, fn: async () => { const config = await Config.get() - expect(config.theme).toBe("test_theme") + expect(config.username).toBe("test-user") }, }) } finally { @@ -148,7 +215,7 @@ test("preserves env variables when adding $schema to config", async () => { await Filesystem.write( path.join(dir, "opencode.json"), JSON.stringify({ - theme: "{env:PRESERVE_VAR}", + username: "{env:PRESERVE_VAR}", }), ) }, @@ -157,7 +224,7 @@ test("preserves env variables when adding $schema to config", async () => { directory: tmp.path, fn: async () => { const config = await Config.get() - expect(config.theme).toBe("secret_value") + expect(config.username).toBe("secret_value") // Read the file to verify the env variable was preserved const content = await Filesystem.readText(path.join(tmp.path, "opencode.json")) @@ -178,10 +245,10 @@ test("preserves env variables when adding $schema to config", async () => { test("handles file inclusion substitution", async () => { await using tmp = await tmpdir({ init: async (dir) => { - await Filesystem.write(path.join(dir, "included.txt"), "test_theme") + await Filesystem.write(path.join(dir, "included.txt"), "test-user") await writeConfig(dir, { $schema: "https://opencode.ai/config.json", - theme: "{file:included.txt}", + username: "{file:included.txt}", }) }, }) @@ -189,7 +256,7 @@ test("handles file inclusion substitution", async () => { directory: tmp.path, fn: async () => { const config = await Config.get() - expect(config.theme).toBe("test_theme") + expect(config.username).toBe("test-user") }, }) }) @@ -200,7 +267,7 @@ test("handles file inclusion with replacement tokens", async () => { await Filesystem.write(path.join(dir, "included.md"), "const out = await Bun.$`echo hi`") await writeConfig(dir, { $schema: "https://opencode.ai/config.json", - theme: "{file:included.md}", + username: "{file:included.md}", }) }, }) @@ -208,7 +275,7 @@ test("handles file inclusion with replacement tokens", async () => { directory: tmp.path, fn: async () => { const config = await Config.get() - expect(config.theme).toBe("const out = await Bun.$`echo hi`") + expect(config.username).toBe("const out = await Bun.$`echo hi`") }, }) }) @@ -689,7 +756,7 @@ test("resolves scoped npm plugins in config", async () => { const pluginEntries = config.plugin ?? [] const baseUrl = pathToFileURL(path.join(tmp.path, "opencode.json")).href - const expected = import.meta.resolve("@scope/plugin", baseUrl) + const expected = pathToFileURL(path.join(tmp.path, "node_modules", "@scope", "plugin", "index.js")).href expect(pluginEntries.includes(expected)).toBe(true) @@ -1043,7 +1110,6 @@ test("managed settings override project settings", async () => { $schema: "https://opencode.ai/config.json", autoupdate: true, disabled_providers: [], - theme: "dark", }) }, }) @@ -1060,7 +1126,6 @@ test("managed settings override project settings", async () => { const config = await Config.get() expect(config.autoupdate).toBe(false) expect(config.disabled_providers).toEqual(["openai"]) - expect(config.theme).toBe("dark") }, }) }) @@ -1515,6 +1580,71 @@ test("project config overrides remote well-known config", async () => { } }) +test("wellknown URL with trailing slash is normalized", async () => { + const originalFetch = globalThis.fetch + let fetchedUrl: string | undefined + const mockFetch = mock((url: string | URL | Request) => { + const urlStr = url.toString() + if (urlStr.includes(".well-known/opencode")) { + fetchedUrl = urlStr + return Promise.resolve( + new Response( + JSON.stringify({ + config: { + mcp: { + slack: { + type: "remote", + url: "https://slack.example.com/mcp", + enabled: true, + }, + }, + }, + }), + { status: 200 }, + ), + ) + } + return originalFetch(url) + }) + globalThis.fetch = mockFetch as unknown as typeof fetch + + const originalAuthAll = Auth.all + Auth.all = mock(() => + Promise.resolve({ + "https://example.com/": { + type: "wellknown" as const, + key: "TEST_TOKEN", + token: "test-token", + }, + }), + ) + + try { + await using tmp = await tmpdir({ + git: true, + init: async (dir) => { + await Filesystem.write( + path.join(dir, "opencode.json"), + JSON.stringify({ + $schema: "https://opencode.ai/config.json", + }), + ) + }, + }) + await Instance.provide({ + directory: tmp.path, + fn: async () => { + await Config.get() + // Trailing slash should be stripped — no double slash in the fetch URL + expect(fetchedUrl).toBe("https://example.com/.well-known/opencode") + }, + }) + } finally { + globalThis.fetch = originalFetch + Auth.all = originalAuthAll + } +}) + describe("getPluginName", () => { test("extracts name from file:// URL", () => { expect(Config.getPluginName("file:///path/to/plugin/foo.js")).toBe("foo") @@ -1809,7 +1939,7 @@ describe("OPENCODE_CONFIG_CONTENT token substitution", () => { process.env["TEST_CONFIG_VAR"] = "test_api_key_12345" process.env["OPENCODE_CONFIG_CONTENT"] = JSON.stringify({ $schema: "https://opencode.ai/config.json", - theme: "{env:TEST_CONFIG_VAR}", + username: "{env:TEST_CONFIG_VAR}", }) try { @@ -1818,7 +1948,7 @@ describe("OPENCODE_CONFIG_CONTENT token substitution", () => { directory: tmp.path, fn: async () => { const config = await Config.get() - expect(config.theme).toBe("test_api_key_12345") + expect(config.username).toBe("test_api_key_12345") }, }) } finally { @@ -1841,10 +1971,10 @@ describe("OPENCODE_CONFIG_CONTENT token substitution", () => { try { await using tmp = await tmpdir({ init: async (dir) => { - await Bun.write(path.join(dir, "api_key.txt"), "secret_key_from_file") + await Filesystem.write(path.join(dir, "api_key.txt"), "secret_key_from_file") process.env["OPENCODE_CONFIG_CONTENT"] = JSON.stringify({ $schema: "https://opencode.ai/config.json", - theme: "{file:./api_key.txt}", + username: "{file:./api_key.txt}", }) }, }) @@ -1852,7 +1982,7 @@ describe("OPENCODE_CONFIG_CONTENT token substitution", () => { directory: tmp.path, fn: async () => { const config = await Config.get() - expect(config.theme).toBe("secret_key_from_file") + expect(config.username).toBe("secret_key_from_file") }, }) } finally { diff --git a/packages/opencode/test/config/markdown.test.ts b/packages/opencode/test/config/markdown.test.ts index c6133317e2..865af21077 100644 --- a/packages/opencode/test/config/markdown.test.ts +++ b/packages/opencode/test/config/markdown.test.ts @@ -197,7 +197,7 @@ describe("ConfigMarkdown: frontmatter parsing w/ Markdown header", async () => { test("should parse and match", () => { expect(result).toBeDefined() expect(result.data).toEqual({}) - expect(result.content.trim()).toBe(`# Response Formatting Requirements + expect(result.content.trim().replace(/\r\n/g, "\n")).toBe(`# Response Formatting Requirements Always structure your responses using clear markdown formatting: diff --git a/packages/opencode/test/config/tui.test.ts b/packages/opencode/test/config/tui.test.ts new file mode 100644 index 0000000000..f9de5b041b --- /dev/null +++ b/packages/opencode/test/config/tui.test.ts @@ -0,0 +1,510 @@ +import { afterEach, expect, test } from "bun:test" +import path from "path" +import fs from "fs/promises" +import { tmpdir } from "../fixture/fixture" +import { Instance } from "../../src/project/instance" +import { TuiConfig } from "../../src/config/tui" +import { Global } from "../../src/global" +import { Filesystem } from "../../src/util/filesystem" + +const managedConfigDir = process.env.OPENCODE_TEST_MANAGED_CONFIG_DIR! + +afterEach(async () => { + delete process.env.OPENCODE_CONFIG + delete process.env.OPENCODE_TUI_CONFIG + await fs.rm(path.join(Global.Path.config, "tui.json"), { force: true }).catch(() => {}) + await fs.rm(path.join(Global.Path.config, "tui.jsonc"), { force: true }).catch(() => {}) + await fs.rm(managedConfigDir, { force: true, recursive: true }).catch(() => {}) +}) + +test("loads tui config with the same precedence order as server config paths", async () => { + await using tmp = await tmpdir({ + init: async (dir) => { + await Bun.write(path.join(Global.Path.config, "tui.json"), JSON.stringify({ theme: "global" }, null, 2)) + await Bun.write(path.join(dir, "tui.json"), JSON.stringify({ theme: "project" }, null, 2)) + await fs.mkdir(path.join(dir, ".opencode"), { recursive: true }) + await Bun.write( + path.join(dir, ".opencode", "tui.json"), + JSON.stringify({ theme: "local", diff_style: "stacked" }, null, 2), + ) + }, + }) + + await Instance.provide({ + directory: tmp.path, + fn: async () => { + const config = await TuiConfig.get() + expect(config.theme).toBe("local") + expect(config.diff_style).toBe("stacked") + }, + }) +}) + +test("migrates tui-specific keys from opencode.json when tui.json does not exist", async () => { + await using tmp = await tmpdir({ + init: async (dir) => { + await Bun.write( + path.join(dir, "opencode.json"), + JSON.stringify( + { + theme: "migrated-theme", + tui: { scroll_speed: 5 }, + keybinds: { app_exit: "ctrl+q" }, + }, + null, + 2, + ), + ) + }, + }) + + await Instance.provide({ + directory: tmp.path, + fn: async () => { + const config = await TuiConfig.get() + expect(config.theme).toBe("migrated-theme") + expect(config.scroll_speed).toBe(5) + expect(config.keybinds?.app_exit).toBe("ctrl+q") + const text = await Filesystem.readText(path.join(tmp.path, "tui.json")) + expect(JSON.parse(text)).toMatchObject({ + theme: "migrated-theme", + scroll_speed: 5, + }) + const server = JSON.parse(await Filesystem.readText(path.join(tmp.path, "opencode.json"))) + expect(server.theme).toBeUndefined() + expect(server.keybinds).toBeUndefined() + expect(server.tui).toBeUndefined() + expect(await Filesystem.exists(path.join(tmp.path, "opencode.json.tui-migration.bak"))).toBe(true) + expect(await Filesystem.exists(path.join(tmp.path, "tui.json"))).toBe(true) + }, + }) +}) + +test("migrates project legacy tui keys even when global tui.json already exists", async () => { + await using tmp = await tmpdir({ + init: async (dir) => { + await Bun.write(path.join(Global.Path.config, "tui.json"), JSON.stringify({ theme: "global" }, null, 2)) + await Bun.write( + path.join(dir, "opencode.json"), + JSON.stringify( + { + theme: "project-migrated", + tui: { scroll_speed: 2 }, + }, + null, + 2, + ), + ) + }, + }) + + await Instance.provide({ + directory: tmp.path, + fn: async () => { + const config = await TuiConfig.get() + expect(config.theme).toBe("project-migrated") + expect(config.scroll_speed).toBe(2) + expect(await Filesystem.exists(path.join(tmp.path, "tui.json"))).toBe(true) + + const server = JSON.parse(await Filesystem.readText(path.join(tmp.path, "opencode.json"))) + expect(server.theme).toBeUndefined() + expect(server.tui).toBeUndefined() + }, + }) +}) + +test("drops unknown legacy tui keys during migration", async () => { + await using tmp = await tmpdir({ + init: async (dir) => { + await Bun.write( + path.join(dir, "opencode.json"), + JSON.stringify( + { + theme: "migrated-theme", + tui: { scroll_speed: 2, foo: 1 }, + }, + null, + 2, + ), + ) + }, + }) + + await Instance.provide({ + directory: tmp.path, + fn: async () => { + const config = await TuiConfig.get() + expect(config.theme).toBe("migrated-theme") + expect(config.scroll_speed).toBe(2) + + const text = await Filesystem.readText(path.join(tmp.path, "tui.json")) + const migrated = JSON.parse(text) + expect(migrated.scroll_speed).toBe(2) + expect(migrated.foo).toBeUndefined() + }, + }) +}) + +test("skips migration when opencode.jsonc is syntactically invalid", async () => { + await using tmp = await tmpdir({ + init: async (dir) => { + await Bun.write( + path.join(dir, "opencode.jsonc"), + `{ + "theme": "broken-theme", + "tui": { "scroll_speed": 2 } + "username": "still-broken" +}`, + ) + }, + }) + + await Instance.provide({ + directory: tmp.path, + fn: async () => { + const config = await TuiConfig.get() + expect(config.theme).toBeUndefined() + expect(config.scroll_speed).toBeUndefined() + expect(await Filesystem.exists(path.join(tmp.path, "tui.json"))).toBe(false) + expect(await Filesystem.exists(path.join(tmp.path, "opencode.jsonc.tui-migration.bak"))).toBe(false) + const source = await Filesystem.readText(path.join(tmp.path, "opencode.jsonc")) + expect(source).toContain('"theme": "broken-theme"') + expect(source).toContain('"tui": { "scroll_speed": 2 }') + }, + }) +}) + +test("skips migration when tui.json already exists", async () => { + await using tmp = await tmpdir({ + init: async (dir) => { + await Bun.write(path.join(dir, "opencode.json"), JSON.stringify({ theme: "legacy" }, null, 2)) + await Bun.write(path.join(dir, "tui.json"), JSON.stringify({ diff_style: "stacked" }, null, 2)) + }, + }) + + await Instance.provide({ + directory: tmp.path, + fn: async () => { + const config = await TuiConfig.get() + expect(config.diff_style).toBe("stacked") + expect(config.theme).toBeUndefined() + + const server = JSON.parse(await Filesystem.readText(path.join(tmp.path, "opencode.json"))) + expect(server.theme).toBe("legacy") + expect(await Filesystem.exists(path.join(tmp.path, "opencode.json.tui-migration.bak"))).toBe(false) + }, + }) +}) + +test("continues loading tui config when legacy source cannot be stripped", async () => { + await using tmp = await tmpdir({ + init: async (dir) => { + await Bun.write(path.join(dir, "opencode.json"), JSON.stringify({ theme: "readonly-theme" }, null, 2)) + }, + }) + + const source = path.join(tmp.path, "opencode.json") + await fs.chmod(source, 0o444) + + try { + await Instance.provide({ + directory: tmp.path, + fn: async () => { + const config = await TuiConfig.get() + expect(config.theme).toBe("readonly-theme") + expect(await Filesystem.exists(path.join(tmp.path, "tui.json"))).toBe(true) + + const server = JSON.parse(await Filesystem.readText(source)) + expect(server.theme).toBe("readonly-theme") + }, + }) + } finally { + await fs.chmod(source, 0o644) + } +}) + +test("migration backup preserves JSONC comments", async () => { + await using tmp = await tmpdir({ + init: async (dir) => { + await Bun.write( + path.join(dir, "opencode.jsonc"), + `{ + // top-level comment + "theme": "jsonc-theme", + "tui": { + // nested comment + "scroll_speed": 1.5 + } +}`, + ) + }, + }) + + await Instance.provide({ + directory: tmp.path, + fn: async () => { + await TuiConfig.get() + const backup = await Filesystem.readText(path.join(tmp.path, "opencode.jsonc.tui-migration.bak")) + expect(backup).toContain("// top-level comment") + expect(backup).toContain("// nested comment") + expect(backup).toContain('"theme": "jsonc-theme"') + expect(backup).toContain('"scroll_speed": 1.5') + }, + }) +}) + +test("migrates legacy tui keys across multiple opencode.json levels", async () => { + await using tmp = await tmpdir({ + init: async (dir) => { + const nested = path.join(dir, "apps", "client") + await fs.mkdir(nested, { recursive: true }) + await Bun.write(path.join(dir, "opencode.json"), JSON.stringify({ theme: "root-theme" }, null, 2)) + await Bun.write(path.join(nested, "opencode.json"), JSON.stringify({ theme: "nested-theme" }, null, 2)) + }, + }) + + await Instance.provide({ + directory: path.join(tmp.path, "apps", "client"), + fn: async () => { + const config = await TuiConfig.get() + expect(config.theme).toBe("nested-theme") + expect(await Filesystem.exists(path.join(tmp.path, "tui.json"))).toBe(true) + expect(await Filesystem.exists(path.join(tmp.path, "apps", "client", "tui.json"))).toBe(true) + }, + }) +}) + +test("flattens nested tui key inside tui.json", async () => { + await using tmp = await tmpdir({ + init: async (dir) => { + await Bun.write( + path.join(dir, "tui.json"), + JSON.stringify({ + theme: "outer", + tui: { scroll_speed: 3, diff_style: "stacked" }, + }), + ) + }, + }) + + await Instance.provide({ + directory: tmp.path, + fn: async () => { + const config = await TuiConfig.get() + expect(config.scroll_speed).toBe(3) + expect(config.diff_style).toBe("stacked") + // top-level keys take precedence over nested tui keys + expect(config.theme).toBe("outer") + }, + }) +}) + +test("top-level keys in tui.json take precedence over nested tui key", async () => { + await using tmp = await tmpdir({ + init: async (dir) => { + await Bun.write( + path.join(dir, "tui.json"), + JSON.stringify({ + diff_style: "auto", + tui: { diff_style: "stacked", scroll_speed: 2 }, + }), + ) + }, + }) + + await Instance.provide({ + directory: tmp.path, + fn: async () => { + const config = await TuiConfig.get() + expect(config.diff_style).toBe("auto") + expect(config.scroll_speed).toBe(2) + }, + }) +}) + +test("project config takes precedence over OPENCODE_TUI_CONFIG (matches OPENCODE_CONFIG)", async () => { + await using tmp = await tmpdir({ + init: async (dir) => { + await Bun.write(path.join(dir, "tui.json"), JSON.stringify({ theme: "project", diff_style: "auto" })) + const custom = path.join(dir, "custom-tui.json") + await Bun.write(custom, JSON.stringify({ theme: "custom", diff_style: "stacked" })) + process.env.OPENCODE_TUI_CONFIG = custom + }, + }) + + await Instance.provide({ + directory: tmp.path, + fn: async () => { + const config = await TuiConfig.get() + // project tui.json overrides the custom path, same as server config precedence + expect(config.theme).toBe("project") + // project also set diff_style, so that wins + expect(config.diff_style).toBe("auto") + }, + }) +}) + +test("merges keybind overrides across precedence layers", async () => { + await using tmp = await tmpdir({ + init: async (dir) => { + await Bun.write(path.join(Global.Path.config, "tui.json"), JSON.stringify({ keybinds: { app_exit: "ctrl+q" } })) + await Bun.write(path.join(dir, "tui.json"), JSON.stringify({ keybinds: { theme_list: "ctrl+k" } })) + }, + }) + + await Instance.provide({ + directory: tmp.path, + fn: async () => { + const config = await TuiConfig.get() + expect(config.keybinds?.app_exit).toBe("ctrl+q") + expect(config.keybinds?.theme_list).toBe("ctrl+k") + }, + }) +}) + +test("OPENCODE_TUI_CONFIG provides settings when no project config exists", async () => { + await using tmp = await tmpdir({ + init: async (dir) => { + const custom = path.join(dir, "custom-tui.json") + await Bun.write(custom, JSON.stringify({ theme: "from-env", diff_style: "stacked" })) + process.env.OPENCODE_TUI_CONFIG = custom + }, + }) + + await Instance.provide({ + directory: tmp.path, + fn: async () => { + const config = await TuiConfig.get() + expect(config.theme).toBe("from-env") + expect(config.diff_style).toBe("stacked") + }, + }) +}) + +test("does not derive tui path from OPENCODE_CONFIG", async () => { + await using tmp = await tmpdir({ + init: async (dir) => { + const customDir = path.join(dir, "custom") + await fs.mkdir(customDir, { recursive: true }) + await Bun.write(path.join(customDir, "opencode.json"), JSON.stringify({ model: "test/model" })) + await Bun.write(path.join(customDir, "tui.json"), JSON.stringify({ theme: "should-not-load" })) + process.env.OPENCODE_CONFIG = path.join(customDir, "opencode.json") + }, + }) + + await Instance.provide({ + directory: tmp.path, + fn: async () => { + const config = await TuiConfig.get() + expect(config.theme).toBeUndefined() + }, + }) +}) + +test("applies env and file substitutions in tui.json", async () => { + const original = process.env.TUI_THEME_TEST + process.env.TUI_THEME_TEST = "env-theme" + try { + await using tmp = await tmpdir({ + init: async (dir) => { + await Bun.write(path.join(dir, "keybind.txt"), "ctrl+q") + await Bun.write( + path.join(dir, "tui.json"), + JSON.stringify({ + theme: "{env:TUI_THEME_TEST}", + keybinds: { app_exit: "{file:keybind.txt}" }, + }), + ) + }, + }) + + await Instance.provide({ + directory: tmp.path, + fn: async () => { + const config = await TuiConfig.get() + expect(config.theme).toBe("env-theme") + expect(config.keybinds?.app_exit).toBe("ctrl+q") + }, + }) + } finally { + if (original === undefined) delete process.env.TUI_THEME_TEST + else process.env.TUI_THEME_TEST = original + } +}) + +test("applies file substitutions when first identical token is in a commented line", async () => { + await using tmp = await tmpdir({ + init: async (dir) => { + await Bun.write(path.join(dir, "theme.txt"), "resolved-theme") + await Bun.write( + path.join(dir, "tui.jsonc"), + `{ + // "theme": "{file:theme.txt}", + "theme": "{file:theme.txt}" +}`, + ) + }, + }) + + await Instance.provide({ + directory: tmp.path, + fn: async () => { + const config = await TuiConfig.get() + expect(config.theme).toBe("resolved-theme") + }, + }) +}) + +test("loads managed tui config and gives it highest precedence", async () => { + await using tmp = await tmpdir({ + init: async (dir) => { + await Bun.write(path.join(dir, "tui.json"), JSON.stringify({ theme: "project-theme" }, null, 2)) + await fs.mkdir(managedConfigDir, { recursive: true }) + await Bun.write(path.join(managedConfigDir, "tui.json"), JSON.stringify({ theme: "managed-theme" }, null, 2)) + }, + }) + + await Instance.provide({ + directory: tmp.path, + fn: async () => { + const config = await TuiConfig.get() + expect(config.theme).toBe("managed-theme") + }, + }) +}) + +test("loads .opencode/tui.json", async () => { + await using tmp = await tmpdir({ + init: async (dir) => { + await fs.mkdir(path.join(dir, ".opencode"), { recursive: true }) + await Bun.write(path.join(dir, ".opencode", "tui.json"), JSON.stringify({ diff_style: "stacked" }, null, 2)) + }, + }) + + await Instance.provide({ + directory: tmp.path, + fn: async () => { + const config = await TuiConfig.get() + expect(config.diff_style).toBe("stacked") + }, + }) +}) + +test("gracefully falls back when tui.json has invalid JSON", async () => { + await using tmp = await tmpdir({ + init: async (dir) => { + await Bun.write(path.join(dir, "tui.json"), "{ invalid json }") + await fs.mkdir(managedConfigDir, { recursive: true }) + await Bun.write(path.join(managedConfigDir, "tui.json"), JSON.stringify({ theme: "managed-fallback" }, null, 2)) + }, + }) + + await Instance.provide({ + directory: tmp.path, + fn: async () => { + const config = await TuiConfig.get() + expect(config.theme).toBe("managed-fallback") + expect(config.keybinds).toBeDefined() + }, + }) +}) diff --git a/packages/opencode/test/control-plane/session-proxy-middleware.test.ts b/packages/opencode/test/control-plane/session-proxy-middleware.test.ts new file mode 100644 index 0000000000..c674d95ec7 --- /dev/null +++ b/packages/opencode/test/control-plane/session-proxy-middleware.test.ts @@ -0,0 +1,159 @@ +import { afterEach, describe, expect, mock, test } from "bun:test" +import { Identifier } from "../../src/id/id" +import { Hono } from "hono" +import { tmpdir } from "../fixture/fixture" +import { Project } from "../../src/project/project" +import { WorkspaceTable } from "../../src/control-plane/workspace.sql" +import { Instance } from "../../src/project/instance" +import { WorkspaceContext } from "../../src/control-plane/workspace-context" +import { Database } from "../../src/storage/db" +import { resetDatabase } from "../fixture/db" +import * as adaptors from "../../src/control-plane/adaptors" +import type { Adaptor } from "../../src/control-plane/types" +import { Flag } from "../../src/flag/flag" + +afterEach(async () => { + mock.restore() + await resetDatabase() +}) + +const original = Flag.OPENCODE_EXPERIMENTAL_WORKSPACES +// @ts-expect-error don't do this normally, but it works +Flag.OPENCODE_EXPERIMENTAL_WORKSPACES = true + +afterEach(() => { + // @ts-expect-error don't do this normally, but it works + Flag.OPENCODE_EXPERIMENTAL_WORKSPACES = original +}) + +type State = { + workspace?: "first" | "second" + calls: Array<{ method: string; url: string; body?: string }> +} + +const remote = { type: "testing", name: "remote-a" } as unknown as typeof WorkspaceTable.$inferInsert + +async function setup(state: State) { + const TestAdaptor: Adaptor = { + configure(config) { + return config + }, + async create() { + throw new Error("not used") + }, + async remove() {}, + + async fetch(_config: unknown, input: RequestInfo | URL, init?: RequestInit) { + const url = + input instanceof Request || input instanceof URL + ? input.toString() + : new URL(input, "http://workspace.test").toString() + const request = new Request(url, init) + const body = request.method === "GET" || request.method === "HEAD" ? undefined : await request.text() + state.calls.push({ + method: request.method, + url: `${new URL(request.url).pathname}${new URL(request.url).search}`, + body, + }) + return new Response("proxied", { status: 202 }) + }, + } + + adaptors.installAdaptor("testing", TestAdaptor) + + await using tmp = await tmpdir({ git: true }) + const { project } = await Project.fromDirectory(tmp.path) + + const id1 = Identifier.descending("workspace") + const id2 = Identifier.descending("workspace") + + Database.use((db) => + db + .insert(WorkspaceTable) + .values([ + { + id: id1, + branch: "main", + project_id: project.id, + type: remote.type, + name: remote.name, + }, + { + id: id2, + branch: "main", + project_id: project.id, + type: "worktree", + directory: tmp.path, + name: "local", + }, + ]) + .run(), + ) + + const { WorkspaceRouterMiddleware } = await import("../../src/control-plane/workspace-router-middleware") + const app = new Hono().use(WorkspaceRouterMiddleware) + + return { + id1, + id2, + app, + async request(input: RequestInfo | URL, init?: RequestInit) { + return Instance.provide({ + directory: tmp.path, + fn: async () => + WorkspaceContext.provide({ + workspaceID: state.workspace === "first" ? id1 : id2, + fn: () => app.request(input, init), + }), + }) + }, + } +} + +describe("control-plane/session-proxy-middleware", () => { + test("forwards non-GET session requests for workspaces", async () => { + const state: State = { + workspace: "first", + calls: [], + } + + const ctx = await setup(state) + + ctx.app.post("/session/foo", (c) => c.text("local", 200)) + const response = await ctx.request("http://workspace.test/session/foo?x=1", { + method: "POST", + body: JSON.stringify({ hello: "world" }), + headers: { + "content-type": "application/json", + }, + }) + + expect(response.status).toBe(202) + expect(await response.text()).toBe("proxied") + expect(state.calls).toEqual([ + { + method: "POST", + url: "/session/foo?x=1", + body: '{"hello":"world"}', + }, + ]) + }) + + // It will behave this way when we have syncing + // + // test("does not forward GET requests", async () => { + // const state: State = { + // workspace: "first", + // calls: [], + // } + + // const ctx = await setup(state) + + // ctx.app.get("/session/foo", (c) => c.text("local", 200)) + // const response = await ctx.request("http://workspace.test/session/foo?x=1") + + // expect(response.status).toBe(200) + // expect(await response.text()).toBe("local") + // expect(state.calls).toEqual([]) + // }) +}) diff --git a/packages/opencode/test/control-plane/sse.test.ts b/packages/opencode/test/control-plane/sse.test.ts new file mode 100644 index 0000000000..78a8341c0e --- /dev/null +++ b/packages/opencode/test/control-plane/sse.test.ts @@ -0,0 +1,56 @@ +import { afterEach, describe, expect, test } from "bun:test" +import { parseSSE } from "../../src/control-plane/sse" +import { resetDatabase } from "../fixture/db" + +afterEach(async () => { + await resetDatabase() +}) + +function stream(chunks: string[]) { + return new ReadableStream<Uint8Array>({ + start(controller) { + const encoder = new TextEncoder() + chunks.forEach((chunk) => controller.enqueue(encoder.encode(chunk))) + controller.close() + }, + }) +} + +describe("control-plane/sse", () => { + test("parses JSON events with CRLF and multiline data blocks", async () => { + const events: unknown[] = [] + const stop = new AbortController() + + await parseSSE( + stream([ + 'data: {"type":"one","properties":{"ok":true}}\r\n\r\n', + 'data: {"type":"two",\r\ndata: "properties":{"n":2}}\r\n\r\n', + ]), + stop.signal, + (event) => events.push(event), + ) + + expect(events).toEqual([ + { type: "one", properties: { ok: true } }, + { type: "two", properties: { n: 2 } }, + ]) + }) + + test("falls back to sse.message for non-json payload", async () => { + const events: unknown[] = [] + const stop = new AbortController() + + await parseSSE(stream(["id: abc\nretry: 1500\ndata: hello world\n\n"]), stop.signal, (event) => events.push(event)) + + expect(events).toEqual([ + { + type: "sse.message", + properties: { + data: "hello world", + id: "abc", + retry: 1500, + }, + }, + ]) + }) +}) diff --git a/packages/opencode/test/control-plane/workspace-server-sse.test.ts b/packages/opencode/test/control-plane/workspace-server-sse.test.ts new file mode 100644 index 0000000000..7e7cddb140 --- /dev/null +++ b/packages/opencode/test/control-plane/workspace-server-sse.test.ts @@ -0,0 +1,70 @@ +import { afterEach, describe, expect, test } from "bun:test" +import { Log } from "../../src/util/log" +import { WorkspaceServer } from "../../src/control-plane/workspace-server/server" +import { parseSSE } from "../../src/control-plane/sse" +import { GlobalBus } from "../../src/bus/global" +import { resetDatabase } from "../fixture/db" +import { tmpdir } from "../fixture/fixture" + +afterEach(async () => { + await resetDatabase() +}) + +Log.init({ print: false }) + +describe("control-plane/workspace-server SSE", () => { + test("streams GlobalBus events and parseSSE reads them", async () => { + await using tmp = await tmpdir({ git: true }) + const app = WorkspaceServer.App() + const stop = new AbortController() + const seen: unknown[] = [] + try { + const response = await app.request("/event", { + signal: stop.signal, + headers: { + "x-opencode-workspace": "wrk_test_workspace", + "x-opencode-directory": tmp.path, + }, + }) + + expect(response.status).toBe(200) + expect(response.body).toBeDefined() + + const done = new Promise<void>((resolve, reject) => { + const timeout = setTimeout(() => { + reject(new Error("timed out waiting for workspace.test event")) + }, 3000) + + void parseSSE(response.body!, stop.signal, (event) => { + seen.push(event) + const next = event as { type?: string } + if (next.type === "server.connected") { + GlobalBus.emit("event", { + payload: { + type: "workspace.test", + properties: { ok: true }, + }, + }) + return + } + if (next.type !== "workspace.test") return + clearTimeout(timeout) + resolve() + }).catch((error) => { + clearTimeout(timeout) + reject(error) + }) + }) + + await done + + expect(seen.some((event) => (event as { type?: string }).type === "server.connected")).toBe(true) + expect(seen).toContainEqual({ + type: "workspace.test", + properties: { ok: true }, + }) + } finally { + stop.abort() + } + }) +}) diff --git a/packages/opencode/test/control-plane/workspace-sync.test.ts b/packages/opencode/test/control-plane/workspace-sync.test.ts new file mode 100644 index 0000000000..899118920f --- /dev/null +++ b/packages/opencode/test/control-plane/workspace-sync.test.ts @@ -0,0 +1,99 @@ +import { afterEach, describe, expect, mock, test } from "bun:test" +import { Identifier } from "../../src/id/id" +import { Log } from "../../src/util/log" +import { tmpdir } from "../fixture/fixture" +import { Project } from "../../src/project/project" +import { Database } from "../../src/storage/db" +import { WorkspaceTable } from "../../src/control-plane/workspace.sql" +import { GlobalBus } from "../../src/bus/global" +import { resetDatabase } from "../fixture/db" +import * as adaptors from "../../src/control-plane/adaptors" +import type { Adaptor } from "../../src/control-plane/types" + +afterEach(async () => { + mock.restore() + await resetDatabase() +}) + +Log.init({ print: false }) + +const remote = { type: "testing", name: "remote-a" } as unknown as typeof WorkspaceTable.$inferInsert + +const TestAdaptor: Adaptor = { + configure(config) { + return config + }, + async create() { + throw new Error("not used") + }, + async remove() {}, + async fetch(_config: unknown, _input: RequestInfo | URL, _init?: RequestInit) { + const body = new ReadableStream<Uint8Array>({ + start(controller) { + const encoder = new TextEncoder() + controller.enqueue(encoder.encode('data: {"type":"remote.ready","properties":{}}\n\n')) + controller.close() + }, + }) + return new Response(body, { + status: 200, + headers: { + "content-type": "text/event-stream", + }, + }) + }, +} + +adaptors.installAdaptor("testing", TestAdaptor) + +describe("control-plane/workspace.startSyncing", () => { + test("syncs only remote workspaces and emits remote SSE events", async () => { + const { Workspace } = await import("../../src/control-plane/workspace") + await using tmp = await tmpdir({ git: true }) + const { project } = await Project.fromDirectory(tmp.path) + + const id1 = Identifier.descending("workspace") + const id2 = Identifier.descending("workspace") + + Database.use((db) => + db + .insert(WorkspaceTable) + .values([ + { + id: id1, + branch: "main", + project_id: project.id, + type: remote.type, + name: remote.name, + }, + { + id: id2, + branch: "main", + project_id: project.id, + type: "worktree", + directory: tmp.path, + name: "local", + }, + ]) + .run(), + ) + + const done = new Promise<void>((resolve) => { + const listener = (event: { directory?: string; payload: { type: string } }) => { + if (event.directory !== id1) return + if (event.payload.type !== "remote.ready") return + GlobalBus.off("event", listener) + resolve() + } + GlobalBus.on("event", listener) + }) + + const sync = Workspace.startSyncing(project) + await Promise.race([ + done, + new Promise((_, reject) => setTimeout(() => reject(new Error("timed out waiting for sync event")), 2000)), + ]) + + await sync.stop() + }) +}) diff --git a/packages/opencode/test/file/fsmonitor.test.ts b/packages/opencode/test/file/fsmonitor.test.ts new file mode 100644 index 0000000000..8cdde014db --- /dev/null +++ b/packages/opencode/test/file/fsmonitor.test.ts @@ -0,0 +1,62 @@ +import { $ } from "bun" +import { describe, expect, test } from "bun:test" +import fs from "fs/promises" +import path from "path" +import { File } from "../../src/file" +import { Instance } from "../../src/project/instance" +import { tmpdir } from "../fixture/fixture" + +const wintest = process.platform === "win32" ? test : test.skip + +describe("file fsmonitor", () => { + wintest("status does not start fsmonitor for readonly git checks", async () => { + await using tmp = await tmpdir({ git: true }) + const target = path.join(tmp.path, "tracked.txt") + + await fs.writeFile(target, "base\n") + await $`git add tracked.txt`.cwd(tmp.path).quiet() + await $`git commit -m init`.cwd(tmp.path).quiet() + await $`git config core.fsmonitor true`.cwd(tmp.path).quiet() + await $`git fsmonitor--daemon stop`.cwd(tmp.path).quiet().nothrow() + await fs.writeFile(target, "next\n") + await fs.writeFile(path.join(tmp.path, "new.txt"), "new\n") + + const before = await $`git fsmonitor--daemon status`.cwd(tmp.path).quiet().nothrow() + expect(before.exitCode).not.toBe(0) + + await Instance.provide({ + directory: tmp.path, + fn: async () => { + await File.status() + }, + }) + + const after = await $`git fsmonitor--daemon status`.cwd(tmp.path).quiet().nothrow() + expect(after.exitCode).not.toBe(0) + }) + + wintest("read does not start fsmonitor for git diffs", async () => { + await using tmp = await tmpdir({ git: true }) + const target = path.join(tmp.path, "tracked.txt") + + await fs.writeFile(target, "base\n") + await $`git add tracked.txt`.cwd(tmp.path).quiet() + await $`git commit -m init`.cwd(tmp.path).quiet() + await $`git config core.fsmonitor true`.cwd(tmp.path).quiet() + await $`git fsmonitor--daemon stop`.cwd(tmp.path).quiet().nothrow() + await fs.writeFile(target, "next\n") + + const before = await $`git fsmonitor--daemon status`.cwd(tmp.path).quiet().nothrow() + expect(before.exitCode).not.toBe(0) + + await Instance.provide({ + directory: tmp.path, + fn: async () => { + await File.read("tracked.txt") + }, + }) + + const after = await $`git fsmonitor--daemon status`.cwd(tmp.path).quiet().nothrow() + expect(after.exitCode).not.toBe(0) + }) +}) diff --git a/packages/opencode/test/file/ripgrep.test.ts b/packages/opencode/test/file/ripgrep.test.ts index ac46f1131b..5eb56e53de 100644 --- a/packages/opencode/test/file/ripgrep.test.ts +++ b/packages/opencode/test/file/ripgrep.test.ts @@ -36,4 +36,19 @@ describe("file.ripgrep", () => { expect(hasVisible).toBe(true) expect(hasHidden).toBe(false) }) + + test("search returns empty when nothing matches", async () => { + await using tmp = await tmpdir({ + init: async (dir) => { + await Bun.write(path.join(dir, "match.ts"), "const value = 'other'\n") + }, + }) + + const hits = await Ripgrep.search({ + cwd: tmp.path, + pattern: "needle", + }) + + expect(hits).toEqual([]) + }) }) diff --git a/packages/opencode/test/fixture/db.ts b/packages/opencode/test/fixture/db.ts new file mode 100644 index 0000000000..f11f0b9036 --- /dev/null +++ b/packages/opencode/test/fixture/db.ts @@ -0,0 +1,11 @@ +import { rm } from "fs/promises" +import { Instance } from "../../src/project/instance" +import { Database } from "../../src/storage/db" + +export async function resetDatabase() { + await Instance.disposeAll().catch(() => undefined) + Database.close() + await rm(Database.Path, { force: true }).catch(() => undefined) + await rm(`${Database.Path}-wal`, { force: true }).catch(() => undefined) + await rm(`${Database.Path}-shm`, { force: true }).catch(() => undefined) +} diff --git a/packages/opencode/test/fixture/fixture.test.ts b/packages/opencode/test/fixture/fixture.test.ts new file mode 100644 index 0000000000..153276a283 --- /dev/null +++ b/packages/opencode/test/fixture/fixture.test.ts @@ -0,0 +1,26 @@ +import { $ } from "bun" +import { describe, expect, test } from "bun:test" +import fs from "fs/promises" +import { tmpdir } from "./fixture" + +describe("tmpdir", () => { + test("disables fsmonitor for git fixtures", async () => { + await using tmp = await tmpdir({ git: true }) + + const value = (await $`git config core.fsmonitor`.cwd(tmp.path).quiet().text()).trim() + expect(value).toBe("false") + }) + + test("removes directories on dispose", async () => { + const tmp = await tmpdir({ git: true }) + const dir = tmp.path + + await tmp[Symbol.asyncDispose]() + + const exists = await fs + .stat(dir) + .then(() => true) + .catch(() => false) + expect(exists).toBe(false) + }) +}) diff --git a/packages/opencode/test/fixture/fixture.ts b/packages/opencode/test/fixture/fixture.ts index ed8c5e344a..63f93bcafe 100644 --- a/packages/opencode/test/fixture/fixture.ts +++ b/packages/opencode/test/fixture/fixture.ts @@ -9,6 +9,27 @@ function sanitizePath(p: string): string { return p.replace(/\0/g, "") } +function exists(dir: string) { + return fs + .stat(dir) + .then(() => true) + .catch(() => false) +} + +function clean(dir: string) { + return fs.rm(dir, { + recursive: true, + force: true, + maxRetries: 5, + retryDelay: 100, + }) +} + +async function stop(dir: string) { + if (!(await exists(dir))) return + await $`git fsmonitor--daemon stop`.cwd(dir).quiet().nothrow() +} + type TmpDirOptions<T> = { git?: boolean config?: Partial<Config.Info> @@ -20,6 +41,7 @@ export async function tmpdir<T>(options?: TmpDirOptions<T>) { await fs.mkdir(dirpath, { recursive: true }) if (options?.git) { await $`git init`.cwd(dirpath).quiet() + await $`git config core.fsmonitor false`.cwd(dirpath).quiet() await $`git commit --allow-empty -m "root commit ${dirpath}"`.cwd(dirpath).quiet() } if (options?.config) { @@ -31,12 +53,16 @@ export async function tmpdir<T>(options?: TmpDirOptions<T>) { }), ) } - const extra = await options?.init?.(dirpath) const realpath = sanitizePath(await fs.realpath(dirpath)) + const extra = await options?.init?.(realpath) const result = { [Symbol.asyncDispose]: async () => { - await options?.dispose?.(dirpath) - // await fs.rm(dirpath, { recursive: true, force: true }) + try { + await options?.dispose?.(realpath) + } finally { + if (options?.git) await stop(realpath).catch(() => undefined) + await clean(realpath).catch(() => undefined) + } }, path: realpath, extra: extra as T, diff --git a/packages/opencode/test/ide/ide.test.ts b/packages/opencode/test/ide/ide.test.ts index 4d70140197..e10700e80f 100644 --- a/packages/opencode/test/ide/ide.test.ts +++ b/packages/opencode/test/ide/ide.test.ts @@ -2,7 +2,7 @@ import { describe, expect, test, afterEach } from "bun:test" import { Ide } from "../../src/ide" describe("ide", () => { - const original = structuredClone(process.env) + const original = { ...process.env } afterEach(() => { Object.keys(process.env).forEach((key) => { diff --git a/packages/opencode/test/installation/installation.test.ts b/packages/opencode/test/installation/installation.test.ts new file mode 100644 index 0000000000..a7cfe50d95 --- /dev/null +++ b/packages/opencode/test/installation/installation.test.ts @@ -0,0 +1,47 @@ +import { afterEach, describe, expect, test } from "bun:test" +import { Installation } from "../../src/installation" + +const fetch0 = globalThis.fetch + +afterEach(() => { + globalThis.fetch = fetch0 +}) + +describe("installation", () => { + test("reads release version from GitHub releases", async () => { + globalThis.fetch = (async () => + new Response(JSON.stringify({ tag_name: "v1.2.3" }), { + status: 200, + headers: { "content-type": "application/json" }, + })) as unknown as typeof fetch + + expect(await Installation.latest("unknown")).toBe("1.2.3") + }) + + test("reads scoop manifest versions", async () => { + globalThis.fetch = (async () => + new Response(JSON.stringify({ version: "2.3.4" }), { + status: 200, + headers: { "content-type": "application/json" }, + })) as unknown as typeof fetch + + expect(await Installation.latest("scoop")).toBe("2.3.4") + }) + + test("reads chocolatey feed versions", async () => { + globalThis.fetch = (async () => + new Response( + JSON.stringify({ + d: { + results: [{ Version: "3.4.5" }], + }, + }), + { + status: 200, + headers: { "content-type": "application/json" }, + }, + )) as unknown as typeof fetch + + expect(await Installation.latest("choco")).toBe("3.4.5") + }) +}) diff --git a/packages/opencode/test/mcp/oauth-auto-connect.test.ts b/packages/opencode/test/mcp/oauth-auto-connect.test.ts new file mode 100644 index 0000000000..76f825247c --- /dev/null +++ b/packages/opencode/test/mcp/oauth-auto-connect.test.ts @@ -0,0 +1,199 @@ +import { test, expect, mock, beforeEach } from "bun:test" + +// Mock UnauthorizedError to match the SDK's class +class MockUnauthorizedError extends Error { + constructor(message?: string) { + super(message ?? "Unauthorized") + this.name = "UnauthorizedError" + } +} + +// Track what options were passed to each transport constructor +const transportCalls: Array<{ + type: "streamable" | "sse" + url: string + options: { authProvider?: unknown } +}> = [] + +// Controls whether the mock transport simulates a 401 that triggers the SDK +// auth flow (which calls provider.state()) or a simple UnauthorizedError. +let simulateAuthFlow = true + +// Mock the transport constructors to simulate OAuth auto-auth on 401 +mock.module("@modelcontextprotocol/sdk/client/streamableHttp.js", () => ({ + StreamableHTTPClientTransport: class MockStreamableHTTP { + authProvider: + | { + state?: () => Promise<string> + redirectToAuthorization?: (url: URL) => Promise<void> + saveCodeVerifier?: (v: string) => Promise<void> + } + | undefined + constructor(url: URL, options?: { authProvider?: unknown }) { + this.authProvider = options?.authProvider as typeof this.authProvider + transportCalls.push({ + type: "streamable", + url: url.toString(), + options: options ?? {}, + }) + } + async start() { + // Simulate what the real SDK transport does on 401: + // It calls auth() which eventually calls provider.state(), then + // provider.redirectToAuthorization(), then throws UnauthorizedError. + if (simulateAuthFlow && this.authProvider) { + // The SDK calls provider.state() to get the OAuth state parameter + if (this.authProvider.state) { + await this.authProvider.state() + } + // The SDK calls saveCodeVerifier before redirecting + if (this.authProvider.saveCodeVerifier) { + await this.authProvider.saveCodeVerifier("test-verifier") + } + // The SDK calls redirectToAuthorization to redirect the user + if (this.authProvider.redirectToAuthorization) { + await this.authProvider.redirectToAuthorization(new URL("https://auth.example.com/authorize?state=test")) + } + throw new MockUnauthorizedError() + } + throw new MockUnauthorizedError() + } + async finishAuth(_code: string) {} + }, +})) + +mock.module("@modelcontextprotocol/sdk/client/sse.js", () => ({ + SSEClientTransport: class MockSSE { + constructor(url: URL, options?: { authProvider?: unknown }) { + transportCalls.push({ + type: "sse", + url: url.toString(), + options: options ?? {}, + }) + } + async start() { + throw new Error("Mock SSE transport cannot connect") + } + }, +})) + +// Mock the MCP SDK Client +mock.module("@modelcontextprotocol/sdk/client/index.js", () => ({ + Client: class MockClient { + async connect(transport: { start: () => Promise<void> }) { + await transport.start() + } + }, +})) + +// Mock UnauthorizedError in the auth module so instanceof checks work +mock.module("@modelcontextprotocol/sdk/client/auth.js", () => ({ + UnauthorizedError: MockUnauthorizedError, +})) + +beforeEach(() => { + transportCalls.length = 0 + simulateAuthFlow = true +}) + +// Import modules after mocking +const { MCP } = await import("../../src/mcp/index") +const { Instance } = await import("../../src/project/instance") +const { tmpdir } = await import("../fixture/fixture") + +test("first connect to OAuth server shows needs_auth instead of failed", async () => { + await using tmp = await tmpdir({ + init: async (dir) => { + await Bun.write( + `${dir}/opencode.json`, + JSON.stringify({ + $schema: "https://opencode.ai/config.json", + mcp: { + "test-oauth": { + type: "remote", + url: "https://example.com/mcp", + }, + }, + }), + ) + }, + }) + + await Instance.provide({ + directory: tmp.path, + fn: async () => { + const result = await MCP.add("test-oauth", { + type: "remote", + url: "https://example.com/mcp", + }) + + const serverStatus = result.status as Record<string, { status: string; error?: string }> + + // The server should be detected as needing auth, NOT as failed. + // Before the fix, provider.state() would throw a plain Error + // ("No OAuth state saved for MCP server: test-oauth") which was + // not caught as UnauthorizedError, causing status to be "failed". + expect(serverStatus["test-oauth"]).toBeDefined() + expect(serverStatus["test-oauth"].status).toBe("needs_auth") + }, + }) +}) + +test("state() generates a new state when none is saved", async () => { + const { McpOAuthProvider } = await import("../../src/mcp/oauth-provider") + const { McpAuth } = await import("../../src/mcp/auth") + + await using tmp = await tmpdir() + + await Instance.provide({ + directory: tmp.path, + fn: async () => { + const provider = new McpOAuthProvider( + "test-state-gen", + "https://example.com/mcp", + {}, + { onRedirect: async () => {} }, + ) + + // Ensure no state exists + const entryBefore = await McpAuth.get("test-state-gen") + expect(entryBefore?.oauthState).toBeUndefined() + + // state() should generate and return a new state, not throw + const state = await provider.state() + expect(typeof state).toBe("string") + expect(state.length).toBe(64) // 32 bytes as hex + + // The generated state should be persisted + const entryAfter = await McpAuth.get("test-state-gen") + expect(entryAfter?.oauthState).toBe(state) + }, + }) +}) + +test("state() returns existing state when one is saved", async () => { + const { McpOAuthProvider } = await import("../../src/mcp/oauth-provider") + const { McpAuth } = await import("../../src/mcp/auth") + + await using tmp = await tmpdir() + + await Instance.provide({ + directory: tmp.path, + fn: async () => { + const provider = new McpOAuthProvider( + "test-state-existing", + "https://example.com/mcp", + {}, + { onRedirect: async () => {} }, + ) + + // Pre-save a state + const existingState = "pre-saved-state-value" + await McpAuth.updateOAuthState("test-state-existing", existingState) + + // state() should return the existing state + const state = await provider.state() + expect(state).toBe(existingState) + }, + }) +}) diff --git a/packages/opencode/test/preload.ts b/packages/opencode/test/preload.ts index dee7045707..1ebd273d26 100644 --- a/packages/opencode/test/preload.ts +++ b/packages/opencode/test/preload.ts @@ -3,14 +3,30 @@ import os from "os" import path from "path" import fs from "fs/promises" -import fsSync from "fs" +import { setTimeout as sleep } from "node:timers/promises" import { afterAll } from "bun:test" // Set XDG env vars FIRST, before any src/ imports const dir = path.join(os.tmpdir(), "opencode-test-data-" + process.pid) await fs.mkdir(dir, { recursive: true }) -afterAll(() => { - fsSync.rmSync(dir, { recursive: true, force: true }) +afterAll(async () => { + const { Database } = await import("../src/storage/db") + Database.close() + const busy = (error: unknown) => + typeof error === "object" && error !== null && "code" in error && error.code === "EBUSY" + const rm = async (left: number): Promise<void> => { + Bun.gc(true) + await sleep(100) + return fs.rm(dir, { recursive: true, force: true }).catch((error) => { + if (!busy(error)) throw error + if (left <= 1) throw error + return rm(left - 1) + }) + } + + // Windows can keep SQLite WAL handles alive until GC finalizers run, so we + // force GC and retry teardown to avoid flaky EBUSY in test cleanup. + await rm(30) }) process.env["XDG_DATA_HOME"] = path.join(dir, "share") @@ -34,7 +50,7 @@ const cacheDir = path.join(dir, "cache", "opencode") await fs.mkdir(cacheDir, { recursive: true }) await fs.writeFile(path.join(cacheDir, "version"), "14") -// Clear provider env vars to ensure clean test state +// Clear provider and server auth env vars to ensure clean test state delete process.env["ANTHROPIC_API_KEY"] delete process.env["OPENAI_API_KEY"] delete process.env["GOOGLE_API_KEY"] @@ -54,6 +70,8 @@ delete process.env["DEEPSEEK_API_KEY"] delete process.env["FIREWORKS_API_KEY"] delete process.env["CEREBRAS_API_KEY"] delete process.env["SAMBANOVA_API_KEY"] +delete process.env["OPENCODE_SERVER_PASSWORD"] +delete process.env["OPENCODE_SERVER_USERNAME"] // Now safe to import from src/ const { Log } = await import("../src/util/log") diff --git a/packages/opencode/test/project/worktree-remove.test.ts b/packages/opencode/test/project/worktree-remove.test.ts index e17a5392bc..a6b5bb7c34 100644 --- a/packages/opencode/test/project/worktree-remove.test.ts +++ b/packages/opencode/test/project/worktree-remove.test.ts @@ -7,6 +7,8 @@ import { Worktree } from "../../src/worktree" import { Filesystem } from "../../src/util/filesystem" import { tmpdir } from "../fixture/fixture" +const wintest = process.platform === "win32" ? test : test.skip + describe("Worktree.remove", () => { test("continues when git remove exits non-zero after detaching", async () => { await using tmp = await tmpdir({ git: true }) @@ -62,4 +64,33 @@ describe("Worktree.remove", () => { const ref = await $`git show-ref --verify --quiet refs/heads/${branch}`.cwd(root).quiet().nothrow() expect(ref.exitCode).not.toBe(0) }) + + wintest("stops fsmonitor before removing a worktree", async () => { + await using tmp = await tmpdir({ git: true }) + const root = tmp.path + const name = `remove-fsmonitor-${Date.now().toString(36)}` + const branch = `opencode/${name}` + const dir = path.join(root, "..", name) + + await $`git worktree add --no-checkout -b ${branch} ${dir}`.cwd(root).quiet() + await $`git reset --hard`.cwd(dir).quiet() + await $`git config core.fsmonitor true`.cwd(dir).quiet() + await $`git fsmonitor--daemon stop`.cwd(dir).quiet().nothrow() + await Bun.write(path.join(dir, "tracked.txt"), "next\n") + await $`git diff`.cwd(dir).quiet() + + const before = await $`git fsmonitor--daemon status`.cwd(dir).quiet().nothrow() + expect(before.exitCode).toBe(0) + + const ok = await Instance.provide({ + directory: root, + fn: () => Worktree.remove({ directory: dir }), + }) + + expect(ok).toBe(true) + expect(await Filesystem.exists(dir)).toBe(false) + + const ref = await $`git show-ref --verify --quiet refs/heads/${branch}`.cwd(root).quiet().nothrow() + expect(ref.exitCode).not.toBe(0) + }) }) diff --git a/packages/opencode/test/provider/gitlab-duo.test.ts b/packages/opencode/test/provider/gitlab-duo.test.ts index c512a45909..86e08a7928 100644 --- a/packages/opencode/test/provider/gitlab-duo.test.ts +++ b/packages/opencode/test/provider/gitlab-duo.test.ts @@ -198,6 +198,30 @@ test("GitLab Duo: config apiKey takes precedence over environment variable", asy }) }) +test("GitLab Duo: includes context-1m beta header in aiGatewayHeaders", async () => { + await using tmp = await tmpdir({ + init: async (dir) => { + await Bun.write( + path.join(dir, "opencode.json"), + JSON.stringify({ + $schema: "https://opencode.ai/config.json", + }), + ) + }, + }) + await Instance.provide({ + directory: tmp.path, + init: async () => { + Env.set("GITLAB_TOKEN", "test-token") + }, + fn: async () => { + const providers = await Provider.list() + expect(providers["gitlab"]).toBeDefined() + expect(providers["gitlab"].options?.aiGatewayHeaders?.["anthropic-beta"]).toContain("context-1m-2025-08-07") + }, + }) +}) + test("GitLab Duo: supports feature flags configuration", async () => { await using tmp = await tmpdir({ init: async (dir) => { diff --git a/packages/opencode/test/provider/provider.test.ts b/packages/opencode/test/provider/provider.test.ts index 0a5aa41513..11c943db6f 100644 --- a/packages/opencode/test/provider/provider.test.ts +++ b/packages/opencode/test/provider/provider.test.ts @@ -2218,3 +2218,64 @@ test("Google Vertex: supports OpenAI compatible models", async () => { }, }) }) + +test("cloudflare-ai-gateway loads with env variables", async () => { + await using tmp = await tmpdir({ + init: async (dir) => { + await Bun.write( + path.join(dir, "opencode.json"), + JSON.stringify({ + $schema: "https://opencode.ai/config.json", + }), + ) + }, + }) + await Instance.provide({ + directory: tmp.path, + init: async () => { + Env.set("CLOUDFLARE_ACCOUNT_ID", "test-account") + Env.set("CLOUDFLARE_GATEWAY_ID", "test-gateway") + Env.set("CLOUDFLARE_API_TOKEN", "test-token") + }, + fn: async () => { + const providers = await Provider.list() + expect(providers["cloudflare-ai-gateway"]).toBeDefined() + }, + }) +}) + +test("cloudflare-ai-gateway forwards config metadata options", async () => { + await using tmp = await tmpdir({ + init: async (dir) => { + await Bun.write( + path.join(dir, "opencode.json"), + JSON.stringify({ + $schema: "https://opencode.ai/config.json", + provider: { + "cloudflare-ai-gateway": { + options: { + metadata: { invoked_by: "test", project: "opencode" }, + }, + }, + }, + }), + ) + }, + }) + await Instance.provide({ + directory: tmp.path, + init: async () => { + Env.set("CLOUDFLARE_ACCOUNT_ID", "test-account") + Env.set("CLOUDFLARE_GATEWAY_ID", "test-gateway") + Env.set("CLOUDFLARE_API_TOKEN", "test-token") + }, + fn: async () => { + const providers = await Provider.list() + expect(providers["cloudflare-ai-gateway"]).toBeDefined() + expect(providers["cloudflare-ai-gateway"].options.metadata).toEqual({ + invoked_by: "test", + project: "opencode", + }) + }, + }) +}) diff --git a/packages/opencode/test/provider/transform.test.ts b/packages/opencode/test/provider/transform.test.ts index 189bdfd32b..512819a657 100644 --- a/packages/opencode/test/provider/transform.test.ts +++ b/packages/opencode/test/provider/transform.test.ts @@ -510,6 +510,106 @@ describe("ProviderTransform.schema - gemini nested array items", () => { }) }) +describe("ProviderTransform.schema - gemini combiner nodes", () => { + const geminiModel = { + providerID: "google", + api: { + id: "gemini-3-pro", + }, + } as any + + const walk = (node: any, cb: (node: any, path: (string | number)[]) => void, path: (string | number)[] = []) => { + if (node === null || typeof node !== "object") { + return + } + if (Array.isArray(node)) { + node.forEach((item, i) => walk(item, cb, [...path, i])) + return + } + cb(node, path) + Object.entries(node).forEach(([key, value]) => walk(value, cb, [...path, key])) + } + + test("keeps edits.items.anyOf without adding type", () => { + const schema = { + type: "object", + properties: { + edits: { + type: "array", + items: { + anyOf: [ + { + type: "object", + properties: { + old_string: { type: "string" }, + new_string: { type: "string" }, + }, + required: ["old_string", "new_string"], + }, + { + type: "object", + properties: { + old_string: { type: "string" }, + new_string: { type: "string" }, + replace_all: { type: "boolean" }, + }, + required: ["old_string", "new_string"], + }, + ], + }, + }, + }, + required: ["edits"], + } as any + + const result = ProviderTransform.schema(geminiModel, schema) as any + + expect(Array.isArray(result.properties.edits.items.anyOf)).toBe(true) + expect(result.properties.edits.items.type).toBeUndefined() + }) + + test("does not add sibling keys to combiner nodes during sanitize", () => { + const schema = { + type: "object", + properties: { + edits: { + type: "array", + items: { + anyOf: [{ type: "string" }, { type: "number" }], + }, + }, + value: { + oneOf: [{ type: "string" }, { type: "boolean" }], + }, + meta: { + allOf: [ + { + type: "object", + properties: { a: { type: "string" } }, + }, + { + type: "object", + properties: { b: { type: "string" } }, + }, + ], + }, + }, + } as any + const input = JSON.parse(JSON.stringify(schema)) + const result = ProviderTransform.schema(geminiModel, schema) as any + + walk(result, (node, path) => { + const hasCombiner = Array.isArray(node.anyOf) || Array.isArray(node.oneOf) || Array.isArray(node.allOf) + if (!hasCombiner) { + return + } + const before = path.reduce((acc: any, key) => acc?.[key], input) + const added = Object.keys(node).filter((key) => !(key in before)) + expect(added).toEqual([]) + }) + }) +}) + describe("ProviderTransform.schema - gemini non-object properties removal", () => { const geminiModel = { providerID: "google", @@ -1902,6 +2002,35 @@ describe("ProviderTransform.variants", () => { const result = ProviderTransform.variants(model) expect(Object.keys(result)).toEqual(["low", "medium", "high", "xhigh"]) }) + + test("gpt-5.3-codex includes xhigh", () => { + const model = createMockModel({ + id: "gpt-5.3-codex", + providerID: "github-copilot", + api: { + id: "gpt-5.3-codex", + url: "https://api.githubcopilot.com", + npm: "@ai-sdk/github-copilot", + }, + }) + const result = ProviderTransform.variants(model) + expect(Object.keys(result)).toEqual(["low", "medium", "high", "xhigh"]) + }) + + test("gpt-5.4 includes xhigh", () => { + const model = createMockModel({ + id: "gpt-5.4", + release_date: "2026-03-05", + providerID: "github-copilot", + api: { + id: "gpt-5.4", + url: "https://api.githubcopilot.com", + npm: "@ai-sdk/github-copilot", + }, + }) + const result = ProviderTransform.variants(model) + expect(Object.keys(result)).toEqual(["low", "medium", "high", "xhigh"]) + }) }) describe("@ai-sdk/cerebras", () => { diff --git a/packages/opencode/test/pty/pty-output-isolation.test.ts b/packages/opencode/test/pty/pty-output-isolation.test.ts index 07e86ea97b..ec1bbd4690 100644 --- a/packages/opencode/test/pty/pty-output-isolation.test.ts +++ b/packages/opencode/test/pty/pty-output-isolation.test.ts @@ -2,6 +2,7 @@ import { describe, expect, test } from "bun:test" import { Instance } from "../../src/project/instance" import { Pty } from "../../src/pty" import { tmpdir } from "../fixture/fixture" +import { setTimeout as sleep } from "node:timers/promises" describe("pty", () => { test("does not leak output when websocket objects are reused", async () => { @@ -43,7 +44,7 @@ describe("pty", () => { // Output from a must never show up in b. Pty.write(a.id, "AAA\n") - await Bun.sleep(100) + await sleep(100) expect(outB.join("")).not.toContain("AAA") } finally { @@ -88,7 +89,7 @@ describe("pty", () => { } Pty.write(a.id, "AAA\n") - await Bun.sleep(100) + await sleep(100) expect(outB.join("")).not.toContain("AAA") } finally { @@ -98,7 +99,7 @@ describe("pty", () => { }) }) - test("does not leak output when socket data mutates in-place", async () => { + test("treats in-place socket data mutation as the same connection", async () => { await using dir = await tmpdir({ git: true }) await Instance.provide({ @@ -106,15 +107,14 @@ describe("pty", () => { fn: async () => { const a = await Pty.create({ command: "cat", title: "a" }) try { - const outA: string[] = [] - const outB: string[] = [] + const out: string[] = [] const ctx = { connId: 1 } const ws = { readyState: 1, data: ctx, send: (data: unknown) => { - outA.push(typeof data === "string" ? data : Buffer.from(data as Uint8Array).toString("utf8")) + out.push(typeof data === "string" ? data : Buffer.from(data as Uint8Array).toString("utf8")) }, close: () => { // no-op @@ -122,19 +122,16 @@ describe("pty", () => { } Pty.connect(a.id, ws as any) - outA.length = 0 + out.length = 0 - // Simulate the runtime mutating per-connection data without - // swapping the reference (ws.data stays the same object). + // Mutating fields on ws.data should not look like a new + // connection lifecycle when the object identity stays stable. ctx.connId = 2 - ws.send = (data: unknown) => { - outB.push(typeof data === "string" ? data : Buffer.from(data as Uint8Array).toString("utf8")) - } Pty.write(a.id, "AAA\n") - await Bun.sleep(100) + await sleep(100) - expect(outB.join("")).not.toContain("AAA") + expect(out.join("")).toContain("AAA") } finally { await Pty.remove(a.id) } diff --git a/packages/opencode/test/pty/pty-session.test.ts b/packages/opencode/test/pty/pty-session.test.ts new file mode 100644 index 0000000000..49b2c3ec26 --- /dev/null +++ b/packages/opencode/test/pty/pty-session.test.ts @@ -0,0 +1,87 @@ +import { describe, expect, test } from "bun:test" +import { Bus } from "../../src/bus" +import { Instance } from "../../src/project/instance" +import { Pty } from "../../src/pty" +import { tmpdir } from "../fixture/fixture" +import { setTimeout as sleep } from "node:timers/promises" + +const wait = async (fn: () => boolean, ms = 2000) => { + const end = Date.now() + ms + while (Date.now() < end) { + if (fn()) return + await sleep(25) + } + throw new Error("timeout waiting for pty events") +} + +const pick = (log: Array<{ type: "created" | "exited" | "deleted"; id: string }>, id: string) => { + return log.filter((evt) => evt.id === id).map((evt) => evt.type) +} + +describe("pty", () => { + test("publishes created, exited, deleted in order for /bin/ls + remove", async () => { + if (process.platform === "win32") return + + await using dir = await tmpdir({ git: true }) + + await Instance.provide({ + directory: dir.path, + fn: async () => { + const log: Array<{ type: "created" | "exited" | "deleted"; id: string }> = [] + const off = [ + Bus.subscribe(Pty.Event.Created, (evt) => log.push({ type: "created", id: evt.properties.info.id })), + Bus.subscribe(Pty.Event.Exited, (evt) => log.push({ type: "exited", id: evt.properties.id })), + Bus.subscribe(Pty.Event.Deleted, (evt) => log.push({ type: "deleted", id: evt.properties.id })), + ] + + let id = "" + try { + const info = await Pty.create({ command: "/bin/ls", title: "ls" }) + id = info.id + + await wait(() => pick(log, id).includes("exited")) + + await Pty.remove(id) + await wait(() => pick(log, id).length >= 3) + expect(pick(log, id)).toEqual(["created", "exited", "deleted"]) + } finally { + off.forEach((x) => x()) + if (id) await Pty.remove(id) + } + }, + }) + }) + + test("publishes created, exited, deleted in order for /bin/sh + remove", async () => { + if (process.platform === "win32") return + + await using dir = await tmpdir({ git: true }) + + await Instance.provide({ + directory: dir.path, + fn: async () => { + const log: Array<{ type: "created" | "exited" | "deleted"; id: string }> = [] + const off = [ + Bus.subscribe(Pty.Event.Created, (evt) => log.push({ type: "created", id: evt.properties.info.id })), + Bus.subscribe(Pty.Event.Exited, (evt) => log.push({ type: "exited", id: evt.properties.id })), + Bus.subscribe(Pty.Event.Deleted, (evt) => log.push({ type: "deleted", id: evt.properties.id })), + ] + + let id = "" + try { + const info = await Pty.create({ command: "/bin/sh", title: "sh" }) + id = info.id + + await sleep(100) + + await Pty.remove(id) + await wait(() => pick(log, id).length >= 3) + expect(pick(log, id)).toEqual(["created", "exited", "deleted"]) + } finally { + off.forEach((x) => x()) + if (id) await Pty.remove(id) + } + }, + }) + }) +}) diff --git a/packages/opencode/test/server/project-init-git.test.ts b/packages/opencode/test/server/project-init-git.test.ts new file mode 100644 index 0000000000..cc1ac0cbc9 --- /dev/null +++ b/packages/opencode/test/server/project-init-git.test.ts @@ -0,0 +1,119 @@ +import { afterEach, describe, expect, spyOn, test } from "bun:test" +import path from "path" +import { GlobalBus } from "../../src/bus/global" +import { Snapshot } from "../../src/snapshot" +import { InstanceBootstrap } from "../../src/project/bootstrap" +import { Instance } from "../../src/project/instance" +import { Server } from "../../src/server/server" +import { Filesystem } from "../../src/util/filesystem" +import { Log } from "../../src/util/log" +import { resetDatabase } from "../fixture/db" +import { tmpdir } from "../fixture/fixture" + +Log.init({ print: false }) + +afterEach(async () => { + await resetDatabase() +}) + +describe("project.initGit endpoint", () => { + test("initializes git and reloads immediately", async () => { + await using tmp = await tmpdir() + const app = Server.Default() + const seen: { directory?: string; payload: { type: string } }[] = [] + const fn = (evt: { directory?: string; payload: { type: string } }) => { + seen.push(evt) + } + const reload = Instance.reload + const reloadSpy = spyOn(Instance, "reload").mockImplementation((input) => reload(input)) + GlobalBus.on("event", fn) + + try { + const init = await app.request("/project/git/init", { + method: "POST", + headers: { + "x-opencode-directory": tmp.path, + }, + }) + const body = await init.json() + expect(init.status).toBe(200) + expect(body).toMatchObject({ + id: "global", + vcs: "git", + worktree: tmp.path, + }) + expect(reloadSpy).toHaveBeenCalledTimes(1) + expect(reloadSpy.mock.calls[0]?.[0]?.init).toBe(InstanceBootstrap) + expect(seen.some((evt) => evt.directory === tmp.path && evt.payload.type === "server.instance.disposed")).toBe( + true, + ) + expect(await Filesystem.exists(path.join(tmp.path, ".git", "opencode"))).toBe(false) + + const current = await app.request("/project/current", { + headers: { + "x-opencode-directory": tmp.path, + }, + }) + expect(current.status).toBe(200) + expect(await current.json()).toMatchObject({ + id: "global", + vcs: "git", + worktree: tmp.path, + }) + + await Instance.provide({ + directory: tmp.path, + fn: async () => { + expect(await Snapshot.track()).toBeTruthy() + }, + }) + } finally { + reloadSpy.mockRestore() + GlobalBus.off("event", fn) + } + }) + + test("does not reload when the project is already git", async () => { + await using tmp = await tmpdir({ git: true }) + const app = Server.Default() + const seen: { directory?: string; payload: { type: string } }[] = [] + const fn = (evt: { directory?: string; payload: { type: string } }) => { + seen.push(evt) + } + const reload = Instance.reload + const reloadSpy = spyOn(Instance, "reload").mockImplementation((input) => reload(input)) + GlobalBus.on("event", fn) + + try { + const init = await app.request("/project/git/init", { + method: "POST", + headers: { + "x-opencode-directory": tmp.path, + }, + }) + expect(init.status).toBe(200) + expect(await init.json()).toMatchObject({ + vcs: "git", + worktree: tmp.path, + }) + expect( + seen.filter((evt) => evt.directory === tmp.path && evt.payload.type === "server.instance.disposed").length, + ).toBe(0) + expect(reloadSpy).toHaveBeenCalledTimes(0) + + const current = await app.request("/project/current", { + headers: { + "x-opencode-directory": tmp.path, + }, + }) + expect(current.status).toBe(200) + expect(await current.json()).toMatchObject({ + vcs: "git", + worktree: tmp.path, + }) + } finally { + reloadSpy.mockRestore() + GlobalBus.off("event", fn) + } + }) +}) diff --git a/packages/opencode/test/server/session-select.test.ts b/packages/opencode/test/server/session-select.test.ts index 479be4a17f..a336f8133c 100644 --- a/packages/opencode/test/server/session-select.test.ts +++ b/packages/opencode/test/server/session-select.test.ts @@ -17,7 +17,7 @@ describe("tui.selectSession endpoint", () => { const session = await Session.create({}) // #when - const app = Server.App() + const app = Server.Default() const response = await app.request("/tui/select-session", { method: "POST", headers: { "Content-Type": "application/json" }, @@ -42,7 +42,7 @@ describe("tui.selectSession endpoint", () => { const nonExistentSessionID = "ses_nonexistent123" // #when - const app = Server.App() + const app = Server.Default() const response = await app.request("/tui/select-session", { method: "POST", headers: { "Content-Type": "application/json" }, @@ -63,7 +63,7 @@ describe("tui.selectSession endpoint", () => { const invalidSessionID = "invalid_session_id" // #when - const app = Server.App() + const app = Server.Default() const response = await app.request("/tui/select-session", { method: "POST", headers: { "Content-Type": "application/json" }, diff --git a/packages/opencode/test/session/retry.test.ts b/packages/opencode/test/session/retry.test.ts index 6768e72d95..eba4a99505 100644 --- a/packages/opencode/test/session/retry.test.ts +++ b/packages/opencode/test/session/retry.test.ts @@ -1,6 +1,7 @@ import { describe, expect, test } from "bun:test" import type { NamedError } from "@opencode-ai/util/error" import { APICallError } from "ai" +import { setTimeout as sleep } from "node:timers/promises" import { SessionRetry } from "../../src/session/retry" import { MessageV2 } from "../../src/session/message-v2" @@ -135,7 +136,7 @@ describe("session.message-v2.fromError", () => { new ReadableStream({ async pull(controller) { controller.enqueue("Hello,") - await Bun.sleep(10000) + await sleep(10000) controller.enqueue(" World!") controller.close() }, diff --git a/packages/opencode/test/session/session.test.ts b/packages/opencode/test/session/session.test.ts index 219cef1271..aa9ca05d04 100644 --- a/packages/opencode/test/session/session.test.ts +++ b/packages/opencode/test/session/session.test.ts @@ -4,6 +4,8 @@ import { Session } from "../../src/session" import { Bus } from "../../src/bus" import { Log } from "../../src/util/log" import { Instance } from "../../src/project/instance" +import { MessageV2 } from "../../src/session/message-v2" +import { Identifier } from "../../src/id/id" const projectRoot = path.join(__dirname, "../..") Log.init({ print: false }) @@ -69,3 +71,72 @@ describe("session.started event", () => { }) }) }) + +describe("step-finish token propagation via Bus event", () => { + test( + "non-zero tokens propagate through PartUpdated event", + async () => { + await Instance.provide({ + directory: projectRoot, + fn: async () => { + const session = await Session.create({}) + + const messageID = Identifier.ascending("message") + await Session.updateMessage({ + id: messageID, + sessionID: session.id, + role: "user", + time: { created: Date.now() }, + agent: "user", + model: { providerID: "test", modelID: "test" }, + tools: {}, + mode: "", + } as unknown as MessageV2.Info) + + let received: MessageV2.Part | undefined + const unsub = Bus.subscribe(MessageV2.Event.PartUpdated, (event) => { + received = event.properties.part + }) + + const tokens = { + total: 1500, + input: 500, + output: 800, + reasoning: 200, + cache: { read: 100, write: 50 }, + } + + const partInput = { + id: Identifier.ascending("part"), + messageID, + sessionID: session.id, + type: "step-finish" as const, + reason: "stop", + cost: 0.005, + tokens, + } + + await Session.updatePart(partInput) + + await new Promise((resolve) => setTimeout(resolve, 100)) + + expect(received).toBeDefined() + expect(received!.type).toBe("step-finish") + const finish = received as MessageV2.StepFinishPart + expect(finish.tokens.input).toBe(500) + expect(finish.tokens.output).toBe(800) + expect(finish.tokens.reasoning).toBe(200) + expect(finish.tokens.total).toBe(1500) + expect(finish.tokens.cache.read).toBe(100) + expect(finish.tokens.cache.write).toBe(50) + expect(finish.cost).toBe(0.005) + expect(received).not.toBe(partInput) + + unsub() + await Session.remove(session.id) + }, + }) + }, + { timeout: 30000 }, + ) +}) diff --git a/packages/opencode/test/skill/discovery.test.ts b/packages/opencode/test/skill/discovery.test.ts index d1963f697b..5664fa32b8 100644 --- a/packages/opencode/test/skill/discovery.test.ts +++ b/packages/opencode/test/skill/discovery.test.ts @@ -77,7 +77,7 @@ describe("Discovery.pull", () => { test("downloads reference files alongside SKILL.md", async () => { const dirs = await Discovery.pull(CLOUDFLARE_SKILLS_URL) // find a skill dir that should have reference files (e.g. agents-sdk) - const agentsSdk = dirs.find((d) => d.endsWith("/agents-sdk")) + const agentsSdk = dirs.find((d) => d.endsWith(path.sep + "agents-sdk")) expect(agentsSdk).toBeDefined() if (agentsSdk) { const refs = path.join(agentsSdk, "references") diff --git a/packages/opencode/test/skill/skill.test.ts b/packages/opencode/test/skill/skill.test.ts index c310256c5e..2264723a09 100644 --- a/packages/opencode/test/skill/skill.test.ts +++ b/packages/opencode/test/skill/skill.test.ts @@ -50,7 +50,7 @@ Instructions here. const testSkill = skills.find((s) => s.name === "test-skill") expect(testSkill).toBeDefined() expect(testSkill!.description).toBe("A test skill for verification.") - expect(testSkill!.location).toContain("skill/test-skill/SKILL.md") + expect(testSkill!.location).toContain(path.join("skill", "test-skill", "SKILL.md")) }, }) }) @@ -180,7 +180,7 @@ description: A skill in the .claude/skills directory. expect(skills.length).toBe(1) const claudeSkill = skills.find((s) => s.name === "claude-skill") expect(claudeSkill).toBeDefined() - expect(claudeSkill!.location).toContain(".claude/skills/claude-skill/SKILL.md") + expect(claudeSkill!.location).toContain(path.join(".claude", "skills", "claude-skill", "SKILL.md")) }, }) }) @@ -200,7 +200,7 @@ test("discovers global skills from ~/.claude/skills/ directory", async () => { expect(skills.length).toBe(1) expect(skills[0].name).toBe("global-test-skill") expect(skills[0].description).toBe("A global skill from ~/.claude/skills for testing.") - expect(skills[0].location).toContain(".claude/skills/global-test-skill/SKILL.md") + expect(skills[0].location).toContain(path.join(".claude", "skills", "global-test-skill", "SKILL.md")) }, }) } finally { @@ -245,7 +245,7 @@ description: A skill in the .agents/skills directory. expect(skills.length).toBe(1) const agentSkill = skills.find((s) => s.name === "agent-skill") expect(agentSkill).toBeDefined() - expect(agentSkill!.location).toContain(".agents/skills/agent-skill/SKILL.md") + expect(agentSkill!.location).toContain(path.join(".agents", "skills", "agent-skill", "SKILL.md")) }, }) }) @@ -279,7 +279,7 @@ This skill is loaded from the global home directory. expect(skills.length).toBe(1) expect(skills[0].name).toBe("global-agent-skill") expect(skills[0].description).toBe("A global skill from ~/.agents/skills for testing.") - expect(skills[0].location).toContain(".agents/skills/global-agent-skill/SKILL.md") + expect(skills[0].location).toContain(path.join(".agents", "skills", "global-agent-skill", "SKILL.md")) }, }) } finally { diff --git a/packages/opencode/test/snapshot/snapshot.test.ts b/packages/opencode/test/snapshot/snapshot.test.ts index 9a0622c4a5..1804ab5c2a 100644 --- a/packages/opencode/test/snapshot/snapshot.test.ts +++ b/packages/opencode/test/snapshot/snapshot.test.ts @@ -1,11 +1,17 @@ import { test, expect } from "bun:test" import { $ } from "bun" import fs from "fs/promises" +import path from "path" import { Snapshot } from "../../src/snapshot" import { Instance } from "../../src/project/instance" import { Filesystem } from "../../src/util/filesystem" import { tmpdir } from "../fixture/fixture" +// Git always outputs /-separated paths internally. Snapshot.patch() joins them +// with path.join (which produces \ on Windows) then normalizes back to /. +// This helper does the same for expected values so assertions match cross-platform. +const fwd = (...parts: string[]) => path.join(...parts).replaceAll("\\", "/") + async function bootstrap() { return tmpdir({ git: true, @@ -35,7 +41,7 @@ test("tracks deleted files correctly", async () => { await $`rm ${tmp.path}/a.txt`.quiet() - expect((await Snapshot.patch(before!)).files).toContain(`${tmp.path}/a.txt`) + expect((await Snapshot.patch(before!)).files).toContain(fwd(tmp.path, "a.txt")) }, }) }) @@ -143,7 +149,7 @@ test("binary file handling", async () => { await Filesystem.write(`${tmp.path}/image.png`, new Uint8Array([0x89, 0x50, 0x4e, 0x47])) const patch = await Snapshot.patch(before!) - expect(patch.files).toContain(`${tmp.path}/image.png`) + expect(patch.files).toContain(fwd(tmp.path, "image.png")) await Snapshot.revert([patch]) expect( @@ -164,9 +170,9 @@ test("symlink handling", async () => { const before = await Snapshot.track() expect(before).toBeTruthy() - await $`ln -s ${tmp.path}/a.txt ${tmp.path}/link.txt`.quiet() + await fs.symlink(`${tmp.path}/a.txt`, `${tmp.path}/link.txt`, "file") - expect((await Snapshot.patch(before!)).files).toContain(`${tmp.path}/link.txt`) + expect((await Snapshot.patch(before!)).files).toContain(fwd(tmp.path, "link.txt")) }, }) }) @@ -181,7 +187,7 @@ test("large file handling", async () => { await Filesystem.write(`${tmp.path}/large.txt`, "x".repeat(1024 * 1024)) - expect((await Snapshot.patch(before!)).files).toContain(`${tmp.path}/large.txt`) + expect((await Snapshot.patch(before!)).files).toContain(fwd(tmp.path, "large.txt")) }, }) }) @@ -222,9 +228,9 @@ test("special characters in filenames", async () => { await Filesystem.write(`${tmp.path}/file_with_underscores.txt`, "UNDERSCORES") const files = (await Snapshot.patch(before!)).files - expect(files).toContain(`${tmp.path}/file with spaces.txt`) - expect(files).toContain(`${tmp.path}/file-with-dashes.txt`) - expect(files).toContain(`${tmp.path}/file_with_underscores.txt`) + expect(files).toContain(fwd(tmp.path, "file with spaces.txt")) + expect(files).toContain(fwd(tmp.path, "file-with-dashes.txt")) + expect(files).toContain(fwd(tmp.path, "file_with_underscores.txt")) }, }) }) @@ -293,10 +299,10 @@ test("unicode filenames", async () => { expect(before).toBeTruthy() const unicodeFiles = [ - { path: `${tmp.path}/文件.txt`, content: "chinese content" }, - { path: `${tmp.path}/🚀rocket.txt`, content: "emoji content" }, - { path: `${tmp.path}/café.txt`, content: "accented content" }, - { path: `${tmp.path}/файл.txt`, content: "cyrillic content" }, + { path: fwd(tmp.path, "文件.txt"), content: "chinese content" }, + { path: fwd(tmp.path, "🚀rocket.txt"), content: "emoji content" }, + { path: fwd(tmp.path, "café.txt"), content: "accented content" }, + { path: fwd(tmp.path, "файл.txt"), content: "cyrillic content" }, ] for (const file of unicodeFiles) { @@ -329,8 +335,8 @@ test.skip("unicode filenames modification and restore", async () => { await Instance.provide({ directory: tmp.path, fn: async () => { - const chineseFile = `${tmp.path}/文件.txt` - const cyrillicFile = `${tmp.path}/файл.txt` + const chineseFile = fwd(tmp.path, "文件.txt") + const cyrillicFile = fwd(tmp.path, "файл.txt") await Filesystem.write(chineseFile, "original chinese") await Filesystem.write(cyrillicFile, "original cyrillic") @@ -362,7 +368,7 @@ test("unicode filenames in subdirectories", async () => { expect(before).toBeTruthy() await $`mkdir -p "${tmp.path}/目录/подкаталог"`.quiet() - const deepFile = `${tmp.path}/目录/подкаталог/文件.txt` + const deepFile = fwd(tmp.path, "目录", "подкаталог", "文件.txt") await Filesystem.write(deepFile, "deep unicode content") const patch = await Snapshot.patch(before!) @@ -388,7 +394,7 @@ test("very long filenames", async () => { expect(before).toBeTruthy() const longName = "a".repeat(200) + ".txt" - const longFile = `${tmp.path}/${longName}` + const longFile = fwd(tmp.path, longName) await Filesystem.write(longFile, "long filename content") @@ -419,9 +425,9 @@ test("hidden files", async () => { await Filesystem.write(`${tmp.path}/.config`, "config content") const patch = await Snapshot.patch(before!) - expect(patch.files).toContain(`${tmp.path}/.hidden`) - expect(patch.files).toContain(`${tmp.path}/.gitignore`) - expect(patch.files).toContain(`${tmp.path}/.config`) + expect(patch.files).toContain(fwd(tmp.path, ".hidden")) + expect(patch.files).toContain(fwd(tmp.path, ".gitignore")) + expect(patch.files).toContain(fwd(tmp.path, ".config")) }, }) }) @@ -436,12 +442,12 @@ test("nested symlinks", async () => { await $`mkdir -p ${tmp.path}/sub/dir`.quiet() await Filesystem.write(`${tmp.path}/sub/dir/target.txt`, "target content") - await $`ln -s ${tmp.path}/sub/dir/target.txt ${tmp.path}/sub/dir/link.txt`.quiet() - await $`ln -s ${tmp.path}/sub ${tmp.path}/sub-link`.quiet() + await fs.symlink(`${tmp.path}/sub/dir/target.txt`, `${tmp.path}/sub/dir/link.txt`, "file") + await fs.symlink(`${tmp.path}/sub`, `${tmp.path}/sub-link`, "dir") const patch = await Snapshot.patch(before!) - expect(patch.files).toContain(`${tmp.path}/sub/dir/link.txt`) - expect(patch.files).toContain(`${tmp.path}/sub-link`) + expect(patch.files).toContain(fwd(tmp.path, "sub", "dir", "link.txt")) + expect(patch.files).toContain(fwd(tmp.path, "sub-link")) }, }) }) @@ -476,7 +482,7 @@ test("circular symlinks", async () => { expect(before).toBeTruthy() // Create circular symlink - await $`ln -s ${tmp.path}/circular ${tmp.path}/circular`.quiet().nothrow() + await fs.symlink(`${tmp.path}/circular`, `${tmp.path}/circular`, "dir").catch(() => {}) const patch = await Snapshot.patch(before!) expect(patch.files.length).toBeGreaterThanOrEqual(0) // Should not crash @@ -499,11 +505,11 @@ test("gitignore changes", async () => { const patch = await Snapshot.patch(before!) // Should track gitignore itself - expect(patch.files).toContain(`${tmp.path}/.gitignore`) + expect(patch.files).toContain(fwd(tmp.path, ".gitignore")) // Should track normal files - expect(patch.files).toContain(`${tmp.path}/normal.txt`) + expect(patch.files).toContain(fwd(tmp.path, "normal.txt")) // Should not track ignored files (git won't see them) - expect(patch.files).not.toContain(`${tmp.path}/test.ignored`) + expect(patch.files).not.toContain(fwd(tmp.path, "test.ignored")) }, }) }) @@ -523,8 +529,8 @@ test("git info exclude changes", async () => { await Bun.write(`${tmp.path}/normal.txt`, "normal content") const patch = await Snapshot.patch(before!) - expect(patch.files).toContain(`${tmp.path}/normal.txt`) - expect(patch.files).not.toContain(`${tmp.path}/ignored.txt`) + expect(patch.files).toContain(fwd(tmp.path, "normal.txt")) + expect(patch.files).not.toContain(fwd(tmp.path, "ignored.txt")) const after = await Snapshot.track() const diffs = await Snapshot.diffFull(before!, after!) @@ -542,7 +548,7 @@ test("git info exclude keeps global excludes", async () => { const global = `${tmp.path}/global.ignore` const config = `${tmp.path}/global.gitconfig` await Bun.write(global, "global.tmp\n") - await Bun.write(config, `[core]\n\texcludesFile = ${global}\n`) + await Bun.write(config, `[core]\n\texcludesFile = ${global.replaceAll("\\", "/")}\n`) const prev = process.env.GIT_CONFIG_GLOBAL process.env.GIT_CONFIG_GLOBAL = config @@ -559,9 +565,9 @@ test("git info exclude keeps global excludes", async () => { await Bun.write(`${tmp.path}/normal.txt`, "normal content") const patch = await Snapshot.patch(before!) - expect(patch.files).toContain(`${tmp.path}/normal.txt`) - expect(patch.files).not.toContain(`${tmp.path}/global.tmp`) - expect(patch.files).not.toContain(`${tmp.path}/info.tmp`) + expect(patch.files).toContain(fwd(tmp.path, "normal.txt")) + expect(patch.files).not.toContain(fwd(tmp.path, "global.tmp")) + expect(patch.files).not.toContain(fwd(tmp.path, "info.tmp")) } finally { if (prev) process.env.GIT_CONFIG_GLOBAL = prev else delete process.env.GIT_CONFIG_GLOBAL @@ -610,7 +616,7 @@ test("snapshot state isolation between projects", async () => { const before1 = await Snapshot.track() await Filesystem.write(`${tmp1.path}/project1.txt`, "project1 content") const patch1 = await Snapshot.patch(before1!) - expect(patch1.files).toContain(`${tmp1.path}/project1.txt`) + expect(patch1.files).toContain(fwd(tmp1.path, "project1.txt")) }, }) @@ -620,10 +626,10 @@ test("snapshot state isolation between projects", async () => { const before2 = await Snapshot.track() await Filesystem.write(`${tmp2.path}/project2.txt`, "project2 content") const patch2 = await Snapshot.patch(before2!) - expect(patch2.files).toContain(`${tmp2.path}/project2.txt`) + expect(patch2.files).toContain(fwd(tmp2.path, "project2.txt")) // Ensure project1 files don't appear in project2 - expect(patch2.files).not.toContain(`${tmp1?.path}/project1.txt`) + expect(patch2.files).not.toContain(fwd(tmp1?.path ?? "", "project1.txt")) }, }) }) @@ -647,7 +653,7 @@ test("patch detects changes in secondary worktree", async () => { const before = await Snapshot.track() expect(before).toBeTruthy() - const worktreeFile = `${worktreePath}/worktree.txt` + const worktreeFile = fwd(worktreePath, "worktree.txt") await Filesystem.write(worktreeFile, "worktree content") const patch = await Snapshot.patch(before!) @@ -681,7 +687,7 @@ test("revert only removes files in invoking worktree", async () => { const before = await Snapshot.track() expect(before).toBeTruthy() - const worktreeFile = `${worktreePath}/worktree.txt` + const worktreeFile = fwd(worktreePath, "worktree.txt") await Filesystem.write(worktreeFile, "worktree content") const patch = await Snapshot.patch(before!) @@ -832,7 +838,7 @@ test("revert should not delete files that existed but were deleted in snapshot", await Filesystem.write(`${tmp.path}/a.txt`, "recreated content") const patch = await Snapshot.patch(snapshot2!) - expect(patch.files).toContain(`${tmp.path}/a.txt`) + expect(patch.files).toContain(fwd(tmp.path, "a.txt")) await Snapshot.revert([patch]) @@ -861,8 +867,8 @@ test("revert preserves file that existed in snapshot when deleted then recreated await Filesystem.write(`${tmp.path}/newfile.txt`, "new") const patch = await Snapshot.patch(snapshot!) - expect(patch.files).toContain(`${tmp.path}/existing.txt`) - expect(patch.files).toContain(`${tmp.path}/newfile.txt`) + expect(patch.files).toContain(fwd(tmp.path, "existing.txt")) + expect(patch.files).toContain(fwd(tmp.path, "newfile.txt")) await Snapshot.revert([patch]) diff --git a/packages/opencode/test/storage/db.test.ts b/packages/opencode/test/storage/db.test.ts new file mode 100644 index 0000000000..601289e58e --- /dev/null +++ b/packages/opencode/test/storage/db.test.ts @@ -0,0 +1,14 @@ +import { describe, expect, test } from "bun:test" +import path from "path" +import { Installation } from "../../src/installation" +import { Database } from "../../src/storage/db" + +describe("Database.Path", () => { + test("returns database path for the current channel", () => { + const file = path.basename(Database.Path) + const expected = ["latest", "beta"].includes(Installation.CHANNEL) + ? "opencode.db" + : `opencode-${Installation.CHANNEL.replace(/[^a-zA-Z0-9._-]/g, "-")}.db` + expect(file).toBe(expected) + }) +}) diff --git a/packages/opencode/test/storage/json-migration.test.ts b/packages/opencode/test/storage/json-migration.test.ts index b70c9e1ebe..40dd611453 100644 --- a/packages/opencode/test/storage/json-migration.test.ts +++ b/packages/opencode/test/storage/json-migration.test.ts @@ -84,6 +84,7 @@ function createTestDb() { .map((entry) => ({ sql: readFileSync(path.join(dir, entry.name, "migration.sql"), "utf-8"), timestamp: Number(entry.name.split("_")[0]), + name: entry.name, })) .sort((a, b) => a.timestamp - b.timestamp) migrate(drizzle({ client: sqlite }), migrations) diff --git a/packages/opencode/test/tool/apply_patch.test.ts b/packages/opencode/test/tool/apply_patch.test.ts index a08e235885..f81723fee0 100644 --- a/packages/opencode/test/tool/apply_patch.test.ts +++ b/packages/opencode/test/tool/apply_patch.test.ts @@ -93,6 +93,13 @@ describe("tool.apply_patch freeform", () => { expect(result.title).toContain("Success. Updated the following files") expect(result.output).toContain("Success. Updated the following files") + // Strict formatting assertions for slashes + expect(result.output).toMatch(/A nested\/new\.txt/) + expect(result.output).toMatch(/D delete\.txt/) + expect(result.output).toMatch(/M modify\.txt/) + if (process.platform === "win32") { + expect(result.output).not.toContain("\\") + } expect(result.metadata.diff).toContain("Index:") expect(calls.length).toBe(1) diff --git a/packages/opencode/test/tool/bash.test.ts b/packages/opencode/test/tool/bash.test.ts index 3bd923b604..ac93016927 100644 --- a/packages/opencode/test/tool/bash.test.ts +++ b/packages/opencode/test/tool/bash.test.ts @@ -1,4 +1,5 @@ import { describe, expect, test } from "bun:test" +import os from "os" import path from "path" import { BashTool } from "../../src/tool/bash" import { Instance } from "../../src/project/instance" @@ -138,14 +139,14 @@ describe("tool.bash permissions", () => { await bash.execute( { command: "ls", - workdir: "/tmp", - description: "List /tmp", + workdir: os.tmpdir(), + description: "List temp dir", }, testCtx, ) const extDirReq = requests.find((r) => r.permission === "external_directory") expect(extDirReq).toBeDefined() - expect(extDirReq!.patterns).toContain("/tmp/*") + expect(extDirReq!.patterns).toContain(path.join(os.tmpdir(), "*")) }, }) }) @@ -203,8 +204,8 @@ describe("tool.bash permissions", () => { await bash.execute( { - command: "rm tmpfile", - description: "Remove tmpfile", + command: `rm -rf ${path.join(tmp.path, "nested")}`, + description: "remove nested dir", }, testCtx, ) @@ -366,7 +367,8 @@ describe("tool.bash truncation", () => { ctx, ) expect((result.metadata as any).truncated).toBe(false) - expect(result.output).toBe("hello\n") + const eol = process.platform === "win32" ? "\r\n" : "\n" + expect(result.output).toBe(`hello${eol}`) }, }) }) diff --git a/packages/opencode/test/tool/edit.test.ts b/packages/opencode/test/tool/edit.test.ts index c3cf0404b9..bcf75da05c 100644 --- a/packages/opencode/test/tool/edit.test.ts +++ b/packages/opencode/test/tool/edit.test.ts @@ -451,6 +451,189 @@ describe("tool.edit", () => { }) }) + describe("line endings", () => { + const old = "alpha\nbeta\ngamma" + const next = "alpha\nbeta-updated\ngamma" + const alt = "alpha\nbeta\nomega" + + const normalize = (text: string, ending: "\n" | "\r\n") => { + const normalized = text.replaceAll("\r\n", "\n") + if (ending === "\n") return normalized + return normalized.replaceAll("\n", "\r\n") + } + + const count = (content: string) => { + const crlf = content.match(/\r\n/g)?.length ?? 0 + const lf = content.match(/\n/g)?.length ?? 0 + return { + crlf, + lf: lf - crlf, + } + } + + const expectLf = (content: string) => { + const counts = count(content) + expect(counts.crlf).toBe(0) + expect(counts.lf).toBeGreaterThan(0) + } + + const expectCrlf = (content: string) => { + const counts = count(content) + expect(counts.lf).toBe(0) + expect(counts.crlf).toBeGreaterThan(0) + } + + type Input = { + content: string + oldString: string + newString: string + replaceAll?: boolean + } + + const apply = async (input: Input) => { + await using tmp = await tmpdir({ + init: async (dir) => { + await Bun.write(path.join(dir, "test.txt"), input.content) + }, + }) + + return await Instance.provide({ + directory: tmp.path, + fn: async () => { + const edit = await EditTool.init() + const filePath = path.join(tmp.path, "test.txt") + FileTime.read(ctx.sessionID, filePath) + await edit.execute( + { + filePath, + oldString: input.oldString, + newString: input.newString, + replaceAll: input.replaceAll, + }, + ctx, + ) + return await Bun.file(filePath).text() + }, + }) + } + + test("preserves LF with LF multi-line strings", async () => { + const content = normalize(old + "\n", "\n") + const output = await apply({ + content, + oldString: normalize(old, "\n"), + newString: normalize(next, "\n"), + }) + expect(output).toBe(normalize(next + "\n", "\n")) + expectLf(output) + }) + + test("preserves CRLF with CRLF multi-line strings", async () => { + const content = normalize(old + "\n", "\r\n") + const output = await apply({ + content, + oldString: normalize(old, "\r\n"), + newString: normalize(next, "\r\n"), + }) + expect(output).toBe(normalize(next + "\n", "\r\n")) + expectCrlf(output) + }) + + test("preserves LF when old/new use CRLF", async () => { + const content = normalize(old + "\n", "\n") + const output = await apply({ + content, + oldString: normalize(old, "\r\n"), + newString: normalize(next, "\r\n"), + }) + expect(output).toBe(normalize(next + "\n", "\n")) + expectLf(output) + }) + + test("preserves CRLF when old/new use LF", async () => { + const content = normalize(old + "\n", "\r\n") + const output = await apply({ + content, + oldString: normalize(old, "\n"), + newString: normalize(next, "\n"), + }) + expect(output).toBe(normalize(next + "\n", "\r\n")) + expectCrlf(output) + }) + + test("preserves LF when newString uses CRLF", async () => { + const content = normalize(old + "\n", "\n") + const output = await apply({ + content, + oldString: normalize(old, "\n"), + newString: normalize(next, "\r\n"), + }) + expect(output).toBe(normalize(next + "\n", "\n")) + expectLf(output) + }) + + test("preserves CRLF when newString uses LF", async () => { + const content = normalize(old + "\n", "\r\n") + const output = await apply({ + content, + oldString: normalize(old, "\r\n"), + newString: normalize(next, "\n"), + }) + expect(output).toBe(normalize(next + "\n", "\r\n")) + expectCrlf(output) + }) + + test("preserves LF with mixed old/new line endings", async () => { + const content = normalize(old + "\n", "\n") + const output = await apply({ + content, + oldString: "alpha\nbeta\r\ngamma", + newString: "alpha\r\nbeta\nomega", + }) + expect(output).toBe(normalize(alt + "\n", "\n")) + expectLf(output) + }) + + test("preserves CRLF with mixed old/new line endings", async () => { + const content = normalize(old + "\n", "\r\n") + const output = await apply({ + content, + oldString: "alpha\r\nbeta\ngamma", + newString: "alpha\nbeta\r\nomega", + }) + expect(output).toBe(normalize(alt + "\n", "\r\n")) + expectCrlf(output) + }) + + test("replaceAll preserves LF for multi-line blocks", async () => { + const blockOld = "alpha\nbeta" + const blockNew = "alpha\nbeta-updated" + const content = normalize(blockOld + "\n" + blockOld + "\n", "\n") + const output = await apply({ + content, + oldString: normalize(blockOld, "\n"), + newString: normalize(blockNew, "\n"), + replaceAll: true, + }) + expect(output).toBe(normalize(blockNew + "\n" + blockNew + "\n", "\n")) + expectLf(output) + }) + + test("replaceAll preserves CRLF for multi-line blocks", async () => { + const blockOld = "alpha\nbeta" + const blockNew = "alpha\nbeta-updated" + const content = normalize(blockOld + "\n" + blockOld + "\n", "\r\n") + const output = await apply({ + content, + oldString: normalize(blockOld, "\r\n"), + newString: normalize(blockNew, "\r\n"), + replaceAll: true, + }) + expect(output).toBe(normalize(blockNew + "\n" + blockNew + "\n", "\r\n")) + expectCrlf(output) + }) + }) + describe("concurrent editing", () => { test("serializes concurrent edits to same file", async () => { await using tmp = await tmpdir() diff --git a/packages/opencode/test/tool/external-directory.test.ts b/packages/opencode/test/tool/external-directory.test.ts index 33c5e2c739..a75f767b3b 100644 --- a/packages/opencode/test/tool/external-directory.test.ts +++ b/packages/opencode/test/tool/external-directory.test.ts @@ -65,7 +65,7 @@ describe("tool.assertExternalDirectory", () => { const directory = "/tmp/project" const target = "/tmp/outside/file.txt" - const expected = path.join(path.dirname(target), "*") + const expected = path.join(path.dirname(target), "*").replaceAll("\\", "/") await Instance.provide({ directory, @@ -91,7 +91,7 @@ describe("tool.assertExternalDirectory", () => { const directory = "/tmp/project" const target = "/tmp/outside" - const expected = path.join(target, "*") + const expected = path.join(target, "*").replaceAll("\\", "/") await Instance.provide({ directory, diff --git a/packages/opencode/test/tool/read.test.ts b/packages/opencode/test/tool/read.test.ts index 88228f14e8..b22fc3e712 100644 --- a/packages/opencode/test/tool/read.test.ts +++ b/packages/opencode/test/tool/read.test.ts @@ -74,7 +74,7 @@ describe("tool.read external_directory permission", () => { await read.execute({ filePath: path.join(outerTmp.path, "secret.txt") }, testCtx) const extDirReq = requests.find((r) => r.permission === "external_directory") expect(extDirReq).toBeDefined() - expect(extDirReq!.patterns.some((p) => p.includes(outerTmp.path))).toBe(true) + expect(extDirReq!.patterns.some((p) => p.includes(outerTmp.path.replaceAll("\\", "/")))).toBe(true) }, }) }) @@ -100,7 +100,7 @@ describe("tool.read external_directory permission", () => { await read.execute({ filePath: path.join(outerTmp.path, "external") }, testCtx) const extDirReq = requests.find((r) => r.permission === "external_directory") expect(extDirReq).toBeDefined() - expect(extDirReq!.patterns).toContain(path.join(outerTmp.path, "external", "*")) + expect(extDirReq!.patterns).toContain(path.join(outerTmp.path, "external", "*").replaceAll("\\", "/")) }, }) }) diff --git a/packages/opencode/test/tool/write.test.ts b/packages/opencode/test/tool/write.test.ts index 4f1a7d28e8..695d48ccbb 100644 --- a/packages/opencode/test/tool/write.test.ts +++ b/packages/opencode/test/tool/write.test.ts @@ -293,19 +293,26 @@ describe("tool.write", () => { }) describe("error handling", () => { - test("throws error for paths outside project", async () => { + test("throws error when OS denies write access", async () => { await using tmp = await tmpdir() - const outsidePath = "/etc/passwd" + const readonlyPath = path.join(tmp.path, "readonly.txt") + + // Create a read-only file + await fs.writeFile(readonlyPath, "test", "utf-8") + await fs.chmod(readonlyPath, 0o444) await Instance.provide({ directory: tmp.path, fn: async () => { + const { FileTime } = await import("../../src/file/time") + FileTime.read(ctx.sessionID, readonlyPath) + const write = await WriteTool.init() await expect( write.execute( { - filePath: outsidePath, - content: "test", + filePath: readonlyPath, + content: "new content", }, ctx, ), diff --git a/packages/opencode/test/util/filesystem.test.ts b/packages/opencode/test/util/filesystem.test.ts index 0f54479373..c757e3424d 100644 --- a/packages/opencode/test/util/filesystem.test.ts +++ b/packages/opencode/test/util/filesystem.test.ts @@ -286,6 +286,40 @@ describe("filesystem", () => { }) }) + describe("windowsPath()", () => { + test("converts Git Bash paths", () => { + if (process.platform === "win32") { + expect(Filesystem.windowsPath("/c/Users/test")).toBe("C:/Users/test") + expect(Filesystem.windowsPath("/d/dev/project")).toBe("D:/dev/project") + } else { + expect(Filesystem.windowsPath("/c/Users/test")).toBe("/c/Users/test") + } + }) + + test("converts Cygwin paths", () => { + if (process.platform === "win32") { + expect(Filesystem.windowsPath("/cygdrive/c/Users/test")).toBe("C:/Users/test") + expect(Filesystem.windowsPath("/cygdrive/x/dev/project")).toBe("X:/dev/project") + } else { + expect(Filesystem.windowsPath("/cygdrive/c/Users/test")).toBe("/cygdrive/c/Users/test") + } + }) + + test("converts WSL paths", () => { + if (process.platform === "win32") { + expect(Filesystem.windowsPath("/mnt/c/Users/test")).toBe("C:/Users/test") + expect(Filesystem.windowsPath("/mnt/z/dev/project")).toBe("Z:/dev/project") + } else { + expect(Filesystem.windowsPath("/mnt/c/Users/test")).toBe("/mnt/c/Users/test") + } + }) + + test("ignores normal Windows paths", () => { + expect(Filesystem.windowsPath("C:/Users/test")).toBe("C:/Users/test") + expect(Filesystem.windowsPath("D:\\dev\\project")).toBe("D:\\dev\\project") + }) + }) + describe("writeStream()", () => { test("writes from Web ReadableStream", async () => { await using tmp = await tmpdir() @@ -406,4 +440,67 @@ describe("filesystem", () => { expect(await fs.readFile(filepath, "utf-8")).toBe(content) }) }) + + describe("resolve()", () => { + test("resolves slash-prefixed drive paths on Windows", async () => { + if (process.platform !== "win32") return + await using tmp = await tmpdir() + const forward = tmp.path.replaceAll("\\", "/") + expect(Filesystem.resolve(`/${forward}`)).toBe(Filesystem.normalizePath(tmp.path)) + }) + + test("resolves slash-prefixed drive roots on Windows", async () => { + if (process.platform !== "win32") return + await using tmp = await tmpdir() + const drive = tmp.path[0].toUpperCase() + expect(Filesystem.resolve(`/${drive}:`)).toBe(Filesystem.resolve(`${drive}:/`)) + }) + + test("resolves Git Bash and MSYS2 paths on Windows", async () => { + // Git Bash and MSYS2 both use /<drive>/... paths on Windows. + if (process.platform !== "win32") return + await using tmp = await tmpdir() + const drive = tmp.path[0].toLowerCase() + const rest = tmp.path.slice(2).replaceAll("\\", "/") + expect(Filesystem.resolve(`/${drive}${rest}`)).toBe(Filesystem.normalizePath(tmp.path)) + }) + + test("resolves Git Bash and MSYS2 drive roots on Windows", async () => { + // Git Bash and MSYS2 both use /<drive> paths on Windows. + if (process.platform !== "win32") return + await using tmp = await tmpdir() + const drive = tmp.path[0].toLowerCase() + expect(Filesystem.resolve(`/${drive}`)).toBe(Filesystem.resolve(`${drive.toUpperCase()}:/`)) + }) + + test("resolves Cygwin paths on Windows", async () => { + if (process.platform !== "win32") return + await using tmp = await tmpdir() + const drive = tmp.path[0].toLowerCase() + const rest = tmp.path.slice(2).replaceAll("\\", "/") + expect(Filesystem.resolve(`/cygdrive/${drive}${rest}`)).toBe(Filesystem.normalizePath(tmp.path)) + }) + + test("resolves Cygwin drive roots on Windows", async () => { + if (process.platform !== "win32") return + await using tmp = await tmpdir() + const drive = tmp.path[0].toLowerCase() + expect(Filesystem.resolve(`/cygdrive/${drive}`)).toBe(Filesystem.resolve(`${drive.toUpperCase()}:/`)) + }) + + test("resolves WSL mount paths on Windows", async () => { + if (process.platform !== "win32") return + await using tmp = await tmpdir() + const drive = tmp.path[0].toLowerCase() + const rest = tmp.path.slice(2).replaceAll("\\", "/") + expect(Filesystem.resolve(`/mnt/${drive}${rest}`)).toBe(Filesystem.normalizePath(tmp.path)) + }) + + test("resolves WSL mount roots on Windows", async () => { + if (process.platform !== "win32") return + await using tmp = await tmpdir() + const drive = tmp.path[0].toLowerCase() + expect(Filesystem.resolve(`/mnt/${drive}`)).toBe(Filesystem.resolve(`${drive.toUpperCase()}:/`)) + }) + }) }) diff --git a/packages/opencode/test/util/glob.test.ts b/packages/opencode/test/util/glob.test.ts index ae1bcdcf82..e58d92c85c 100644 --- a/packages/opencode/test/util/glob.test.ts +++ b/packages/opencode/test/util/glob.test.ts @@ -63,7 +63,7 @@ describe("Glob", () => { const results = await Glob.scan("**/*.txt", { cwd: tmp.path }) - expect(results).toEqual(["nested/deep.txt"]) + expect(results).toEqual([path.join("nested", "deep.txt")]) }) test("returns empty array for no matches", async () => { @@ -82,7 +82,7 @@ describe("Glob", () => { const results = await Glob.scan("**/*.txt", { cwd: tmp.path }) - expect(results).toEqual(["realdir/file.txt"]) + expect(results).toEqual([path.join("realdir", "file.txt")]) }) test("follows symlinks when symlink option is true", async () => { @@ -93,7 +93,7 @@ describe("Glob", () => { const results = await Glob.scan("**/*.txt", { cwd: tmp.path, symlink: true }) - expect(results.sort()).toEqual(["linkdir/file.txt", "realdir/file.txt"]) + expect(results.sort()).toEqual([path.join("linkdir", "file.txt"), path.join("realdir", "file.txt")]) }) test("includes dotfiles when dot option is true", async () => { diff --git a/packages/opencode/test/util/module.test.ts b/packages/opencode/test/util/module.test.ts new file mode 100644 index 0000000000..738b4a785b --- /dev/null +++ b/packages/opencode/test/util/module.test.ts @@ -0,0 +1,59 @@ +import { describe, expect, test } from "bun:test" +import path from "path" +import { Module } from "@opencode-ai/util/module" +import { Filesystem } from "../../src/util/filesystem" +import { tmpdir } from "../fixture/fixture" + +describe("util.module", () => { + test("resolves package subpaths from the provided dir", async () => { + await using tmp = await tmpdir() + const root = path.join(tmp.path, "proj") + const file = path.join(root, "node_modules/typescript/lib/tsserver.js") + await Filesystem.write(file, "export {}\n") + await Filesystem.writeJson(path.join(root, "node_modules/typescript/package.json"), { name: "typescript" }) + + expect(Module.resolve("typescript/lib/tsserver.js", root)).toBe(file) + }) + + test("resolves packages through ancestor node_modules", async () => { + await using tmp = await tmpdir() + const root = path.join(tmp.path, "proj") + const cwd = path.join(root, "apps/web") + const file = path.join(root, "node_modules/eslint/lib/api.js") + await Filesystem.write(file, "export {}\n") + await Filesystem.writeJson(path.join(root, "node_modules/eslint/package.json"), { + name: "eslint", + main: "lib/api.js", + }) + await Filesystem.write(path.join(cwd, ".keep"), "") + + expect(Module.resolve("eslint", cwd)).toBe(file) + }) + + test("resolves relative to the provided dir", async () => { + await using tmp = await tmpdir() + const a = path.join(tmp.path, "a") + const b = path.join(tmp.path, "b") + const left = path.join(a, "node_modules/biome/index.js") + const right = path.join(b, "node_modules/biome/index.js") + await Filesystem.write(left, "export {}\n") + await Filesystem.write(right, "export {}\n") + await Filesystem.writeJson(path.join(a, "node_modules/biome/package.json"), { + name: "biome", + main: "index.js", + }) + await Filesystem.writeJson(path.join(b, "node_modules/biome/package.json"), { + name: "biome", + main: "index.js", + }) + + expect(Module.resolve("biome", a)).toBe(left) + expect(Module.resolve("biome", b)).toBe(right) + expect(Module.resolve("biome", a)).not.toBe(Module.resolve("biome", b)) + }) + + test("returns undefined when resolution fails", async () => { + await using tmp = await tmpdir() + expect(Module.resolve("missing-package", tmp.path)).toBeUndefined() + }) +}) diff --git a/packages/opencode/test/util/process.test.ts b/packages/opencode/test/util/process.test.ts new file mode 100644 index 0000000000..758469fe3e --- /dev/null +++ b/packages/opencode/test/util/process.test.ts @@ -0,0 +1,77 @@ +import { describe, expect, test } from "bun:test" +import { Process } from "../../src/util/process" +import { tmpdir } from "../fixture/fixture" + +function node(script: string) { + return [process.execPath, "-e", script] +} + +describe("util.process", () => { + test("captures stdout and stderr", async () => { + const out = await Process.run(node('process.stdout.write("out");process.stderr.write("err")')) + expect(out.code).toBe(0) + expect(out.stdout.toString()).toBe("out") + expect(out.stderr.toString()).toBe("err") + }) + + test("returns code when nothrow is enabled", async () => { + const out = await Process.run(node("process.exit(7)"), { nothrow: true }) + expect(out.code).toBe(7) + }) + + test("throws RunFailedError on non-zero exit", async () => { + const err = await Process.run(node('process.stderr.write("bad");process.exit(3)')).catch((error) => error) + expect(err).toBeInstanceOf(Process.RunFailedError) + if (!(err instanceof Process.RunFailedError)) throw err + expect(err.code).toBe(3) + expect(err.stderr.toString()).toBe("bad") + }) + + test("aborts a running process", async () => { + const abort = new AbortController() + const started = Date.now() + setTimeout(() => abort.abort(), 25) + + const out = await Process.run(node("setInterval(() => {}, 1000)"), { + abort: abort.signal, + nothrow: true, + }) + + expect(out.code).not.toBe(0) + expect(Date.now() - started).toBeLessThan(1000) + }, 3000) + + test("kills after timeout when process ignores terminate signal", async () => { + if (process.platform === "win32") return + + const abort = new AbortController() + const started = Date.now() + setTimeout(() => abort.abort(), 25) + + const out = await Process.run(node('process.on("SIGTERM", () => {}); setInterval(() => {}, 1000)'), { + abort: abort.signal, + nothrow: true, + timeout: 25, + }) + + expect(out.code).not.toBe(0) + expect(Date.now() - started).toBeLessThan(1000) + }, 3000) + + test("uses cwd when spawning commands", async () => { + await using tmp = await tmpdir() + const out = await Process.run(node("process.stdout.write(process.cwd())"), { + cwd: tmp.path, + }) + expect(out.stdout.toString()).toBe(tmp.path) + }) + + test("merges environment overrides", async () => { + const out = await Process.run(node('process.stdout.write(process.env.OPENCODE_TEST ?? "")'), { + env: { + OPENCODE_TEST: "set", + }, + }) + expect(out.stdout.toString()).toBe("set") + }) +}) diff --git a/packages/opencode/test/util/which.test.ts b/packages/opencode/test/util/which.test.ts new file mode 100644 index 0000000000..70c2fb2d9f --- /dev/null +++ b/packages/opencode/test/util/which.test.ts @@ -0,0 +1,100 @@ +import { describe, expect, test } from "bun:test" +import fs from "fs/promises" +import path from "path" +import { which } from "../../src/util/which" +import { tmpdir } from "../fixture/fixture" + +async function cmd(dir: string, name: string, exec = true) { + const ext = process.platform === "win32" ? ".cmd" : "" + const file = path.join(dir, name + ext) + const body = process.platform === "win32" ? "@echo off\r\n" : "#!/bin/sh\n" + await fs.writeFile(file, body) + if (process.platform !== "win32") { + await fs.chmod(file, exec ? 0o755 : 0o644) + } + return file +} + +function env(PATH: string): NodeJS.ProcessEnv { + return { + PATH, + PATHEXT: process.env["PATHEXT"], + } +} + +function envPath(Path: string): NodeJS.ProcessEnv { + return { + Path, + PathExt: process.env["PathExt"] ?? process.env["PATHEXT"], + } +} + +function same(a: string | null, b: string) { + if (process.platform === "win32") { + expect(a?.toLowerCase()).toBe(b.toLowerCase()) + return + } + + expect(a).toBe(b) +} + +describe("util.which", () => { + test("returns null when command is missing", () => { + expect(which("opencode-missing-command-for-test")).toBeNull() + }) + + test("finds a command from PATH override", async () => { + await using tmp = await tmpdir() + const bin = path.join(tmp.path, "bin") + await fs.mkdir(bin) + const file = await cmd(bin, "tool") + + same(which("tool", env(bin)), file) + }) + + test("uses first PATH match", async () => { + await using tmp = await tmpdir() + const a = path.join(tmp.path, "a") + const b = path.join(tmp.path, "b") + await fs.mkdir(a) + await fs.mkdir(b) + const first = await cmd(a, "dupe") + await cmd(b, "dupe") + + same(which("dupe", env([a, b].join(path.delimiter))), first) + }) + + test("returns null for non-executable file on unix", async () => { + if (process.platform === "win32") return + + await using tmp = await tmpdir() + const bin = path.join(tmp.path, "bin") + await fs.mkdir(bin) + await cmd(bin, "noexec", false) + + expect(which("noexec", env(bin))).toBeNull() + }) + + test("uses PATHEXT on windows", async () => { + if (process.platform !== "win32") return + + await using tmp = await tmpdir() + const bin = path.join(tmp.path, "bin") + await fs.mkdir(bin) + const file = path.join(bin, "pathext.CMD") + await fs.writeFile(file, "@echo off\r\n") + + expect(which("pathext", { PATH: bin, PATHEXT: ".CMD" })).toBe(file) + }) + + test("uses Windows Path casing fallback", async () => { + if (process.platform !== "win32") return + + await using tmp = await tmpdir() + const bin = path.join(tmp.path, "bin") + await fs.mkdir(bin) + const file = await cmd(bin, "mixed") + + same(which("mixed", envPath(bin)), file) + }) +}) diff --git a/packages/opencode/test/util/wildcard.test.ts b/packages/opencode/test/util/wildcard.test.ts index 9cd0e9b945..56e753d12a 100644 --- a/packages/opencode/test/util/wildcard.test.ts +++ b/packages/opencode/test/util/wildcard.test.ts @@ -73,3 +73,18 @@ test("allStructured handles sed flags", () => { expect(Wildcard.allStructured({ head: "sed", tail: ["-n", "1p", "file"] }, rules)).toBe("allow") expect(Wildcard.allStructured({ head: "sed", tail: ["-i", "-n", "/./p", "myfile.txt"] }, rules)).toBe("ask") }) + +test("match normalizes slashes for cross-platform globbing", () => { + expect(Wildcard.match("C:\\Windows\\System32\\*", "C:/Windows/System32/*")).toBe(true) + expect(Wildcard.match("C:/Windows/System32/drivers", "C:\\Windows\\System32\\*")).toBe(true) +}) + +test("match handles case-insensitivity on Windows", () => { + if (process.platform === "win32") { + expect(Wildcard.match("C:\\windows\\system32\\hosts", "C:/Windows/System32/*")).toBe(true) + expect(Wildcard.match("c:/windows/system32/hosts", "C:\\Windows\\System32\\*")).toBe(true) + } else { + // Unix paths are case-sensitive + expect(Wildcard.match("/users/test/file", "/Users/test/*")).toBe(false) + } +}) diff --git a/packages/plugin/package.json b/packages/plugin/package.json index 623a117929..3f1f6af95f 100644 --- a/packages/plugin/package.json +++ b/packages/plugin/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/plugin", - "version": "1.2.10", + "version": "1.2.24", "type": "module", "license": "MIT", "scripts": { diff --git a/packages/plugin/script/publish.ts b/packages/plugin/script/publish.ts index 647b56e5e2..d2fe49f23c 100755 --- a/packages/plugin/script/publish.ts +++ b/packages/plugin/script/publish.ts @@ -1,8 +1,9 @@ #!/usr/bin/env bun import { Script } from "@opencode-ai/script" import { $ } from "bun" +import { fileURLToPath } from "url" -const dir = new URL("..", import.meta.url).pathname +const dir = fileURLToPath(new URL("..", import.meta.url)) process.chdir(dir) await $`bun tsc` diff --git a/packages/script/package.json b/packages/script/package.json index 45de3bcb99..aa0d2f563f 100644 --- a/packages/script/package.json +++ b/packages/script/package.json @@ -2,8 +2,12 @@ "$schema": "https://json.schemastore.org/package", "name": "@opencode-ai/script", "license": "MIT", + "dependencies": { + "semver": "^7.6.3" + }, "devDependencies": { - "@types/bun": "catalog:" + "@types/bun": "catalog:", + "@types/semver": "^7.5.8" }, "exports": { ".": "./src/index.ts" diff --git a/packages/script/src/index.ts b/packages/script/src/index.ts index 1f39d31388..d148ce0d2b 100644 --- a/packages/script/src/index.ts +++ b/packages/script/src/index.ts @@ -1,4 +1,5 @@ -import { $, semver } from "bun" +import { $ } from "bun" +import semver from "semver" import path from "path" const rootPkgPath = path.resolve(import.meta.dir, "../../../package.json") @@ -46,23 +47,14 @@ const VERSION = await (async () => { return `${major}.${minor}.${patch + 1}` })() +const bot = ["actions-user", "opencode", "opencode-agent[bot]"] +const teamPath = path.resolve(import.meta.dir, "../../../.github/TEAM_MEMBERS") const team = [ - "actions-user", - "opencode", - "rekram1-node", - "thdxr", - "kommander", - "jayair", - "fwang", - "MrMushrooooom", - "adamdotdevin", - "iamdavidhill", - "Brendonovich", - "nexxeln", - "Hona", - "jlongster", - "opencode-agent[bot]", - "R44VC0RP", + ...(await Bun.file(teamPath) + .text() + .then((x) => x.split(/\r?\n/).map((x) => x.trim())) + .then((x) => x.filter((x) => x && !x.startsWith("#")))), + ...bot, ] export const Script = { diff --git a/packages/sdk/js/package.json b/packages/sdk/js/package.json index 4fe0794d0c..7281174c0f 100644 --- a/packages/sdk/js/package.json +++ b/packages/sdk/js/package.json @@ -1,29 +1,20 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/sdk", - "version": "1.2.10", + "version": "1.2.24", "type": "module", "license": "MIT", "scripts": { "typecheck": "tsgo --noEmit", - "build": "./script/build.ts" + "build": "bun ./script/build.ts" }, "exports": { ".": "./src/index.ts", "./client": "./src/client.ts", "./server": "./src/server.ts", - "./v2": { - "types": "./dist/v2/index.d.ts", - "default": "./src/v2/index.ts" - }, - "./v2/client": { - "types": "./dist/v2/client.d.ts", - "default": "./src/v2/client.ts" - }, - "./v2/gen/client": { - "types": "./dist/v2/gen/client/index.d.ts", - "default": "./src/v2/gen/client/index.ts" - }, + "./v2": "./src/v2/index.ts", + "./v2/client": "./src/v2/client.ts", + "./v2/gen/client": "./src/v2/gen/client/index.ts", "./v2/server": "./src/v2/server.ts" }, "files": [ @@ -36,8 +27,5 @@ "typescript": "catalog:", "@typescript/native-preview": "catalog:" }, - "dependencies": {}, - "publishConfig": { - "directory": "dist" - } + "dependencies": {} } diff --git a/packages/sdk/js/script/build.ts b/packages/sdk/js/script/build.ts index 7568c54b0f..268233a012 100755 --- a/packages/sdk/js/script/build.ts +++ b/packages/sdk/js/script/build.ts @@ -1,6 +1,7 @@ #!/usr/bin/env bun +import { fileURLToPath } from "url" -const dir = new URL("..", import.meta.url).pathname +const dir = fileURLToPath(new URL("..", import.meta.url)) process.chdir(dir) import { $ } from "bun" diff --git a/packages/sdk/js/script/publish.ts b/packages/sdk/js/script/publish.ts index c21f06230d..ea5c5d634b 100755 --- a/packages/sdk/js/script/publish.ts +++ b/packages/sdk/js/script/publish.ts @@ -2,8 +2,9 @@ import { Script } from "@opencode-ai/script" import { $ } from "bun" +import { fileURLToPath } from "url" -const dir = new URL("..", import.meta.url).pathname +const dir = fileURLToPath(new URL("..", import.meta.url)) process.chdir(dir) const pkg = (await import("../package.json").then((m) => m.default)) as { diff --git a/packages/sdk/js/src/v2/client.ts b/packages/sdk/js/src/v2/client.ts index 8685be52d6..ad956dd4b3 100644 --- a/packages/sdk/js/src/v2/client.ts +++ b/packages/sdk/js/src/v2/client.ts @@ -5,7 +5,7 @@ import { type Config } from "./gen/client/types.gen.js" import { OpencodeClient } from "./gen/sdk.gen.js" export { type Config as OpencodeClientConfig, OpencodeClient } -export function createOpencodeClient(config?: Config & { directory?: string }) { +export function createOpencodeClient(config?: Config & { directory?: string; experimental_workspaceID?: string }) { if (!config?.fetch) { const customFetch: any = (req: any) => { // @ts-ignore @@ -27,6 +27,13 @@ export function createOpencodeClient(config?: Config & { directory?: string }) { } } + if (config?.experimental_workspaceID) { + config.headers = { + ...config.headers, + "x-opencode-workspace": config.experimental_workspaceID, + } + } + const client = createClient(config) return new OpencodeClient({ client }) } diff --git a/packages/sdk/js/src/v2/gen/sdk.gen.ts b/packages/sdk/js/src/v2/gen/sdk.gen.ts index b4848e6054..22dcfec355 100644 --- a/packages/sdk/js/src/v2/gen/sdk.gen.ts +++ b/packages/sdk/js/src/v2/gen/sdk.gen.ts @@ -26,6 +26,11 @@ import type { EventTuiToastShow, ExperimentalResourceListResponses, ExperimentalSessionListResponses, + ExperimentalWorkspaceCreateErrors, + ExperimentalWorkspaceCreateResponses, + ExperimentalWorkspaceListResponses, + ExperimentalWorkspaceRemoveErrors, + ExperimentalWorkspaceRemoveResponses, FileListResponses, FilePartInput, FilePartSource, @@ -72,6 +77,7 @@ import type { PermissionRespondResponses, PermissionRuleset, ProjectCurrentResponses, + ProjectInitGitResponses, ProjectListResponses, ProjectUpdateErrors, ProjectUpdateResponses, @@ -107,6 +113,8 @@ import type { SessionCreateErrors, SessionCreateResponses, SessionDeleteErrors, + SessionDeleteMessageErrors, + SessionDeleteMessageResponses, SessionDeleteResponses, SessionDiffResponses, SessionForkResponses, @@ -366,10 +374,21 @@ export class Project extends HeyApiClient { public list<ThrowOnError extends boolean = false>( parameters?: { directory?: string + workspace?: string }, options?: Options<never, ThrowOnError>, ) { - const params = buildClientParams([parameters], [{ args: [{ in: "query", key: "directory" }] }]) + const params = buildClientParams( + [parameters], + [ + { + args: [ + { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, + ], + }, + ], + ) return (options?.client ?? this.client).get<ProjectListResponses, unknown, ThrowOnError>({ url: "/project", ...options, @@ -385,10 +404,21 @@ export class Project extends HeyApiClient { public current<ThrowOnError extends boolean = false>( parameters?: { directory?: string + workspace?: string }, options?: Options<never, ThrowOnError>, ) { - const params = buildClientParams([parameters], [{ args: [{ in: "query", key: "directory" }] }]) + const params = buildClientParams( + [parameters], + [ + { + args: [ + { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, + ], + }, + ], + ) return (options?.client ?? this.client).get<ProjectCurrentResponses, unknown, ThrowOnError>({ url: "/project/current", ...options, @@ -396,6 +426,36 @@ export class Project extends HeyApiClient { }) } + /** + * Initialize git repository + * + * Create a git repository for the current project and return the refreshed project info. + */ + public initGit<ThrowOnError extends boolean = false>( + parameters?: { + directory?: string + workspace?: string + }, + options?: Options<never, ThrowOnError>, + ) { + const params = buildClientParams( + [parameters], + [ + { + args: [ + { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, + ], + }, + ], + ) + return (options?.client ?? this.client).post<ProjectInitGitResponses, unknown, ThrowOnError>({ + url: "/project/git/init", + ...options, + ...params, + }) + } + /** * Update project * @@ -405,6 +465,7 @@ export class Project extends HeyApiClient { parameters: { projectID: string directory?: string + workspace?: string name?: string icon?: { url?: string @@ -427,6 +488,7 @@ export class Project extends HeyApiClient { args: [ { in: "path", key: "projectID" }, { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, { in: "body", key: "name" }, { in: "body", key: "icon" }, { in: "body", key: "commands" }, @@ -456,10 +518,21 @@ export class Pty extends HeyApiClient { public list<ThrowOnError extends boolean = false>( parameters?: { directory?: string + workspace?: string }, options?: Options<never, ThrowOnError>, ) { - const params = buildClientParams([parameters], [{ args: [{ in: "query", key: "directory" }] }]) + const params = buildClientParams( + [parameters], + [ + { + args: [ + { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, + ], + }, + ], + ) return (options?.client ?? this.client).get<PtyListResponses, unknown, ThrowOnError>({ url: "/pty", ...options, @@ -475,6 +548,7 @@ export class Pty extends HeyApiClient { public create<ThrowOnError extends boolean = false>( parameters?: { directory?: string + workspace?: string command?: string args?: Array<string> cwd?: string @@ -491,6 +565,7 @@ export class Pty extends HeyApiClient { { args: [ { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, { in: "body", key: "command" }, { in: "body", key: "args" }, { in: "body", key: "cwd" }, @@ -521,6 +596,7 @@ export class Pty extends HeyApiClient { parameters: { ptyID: string directory?: string + workspace?: string }, options?: Options<never, ThrowOnError>, ) { @@ -531,6 +607,7 @@ export class Pty extends HeyApiClient { args: [ { in: "path", key: "ptyID" }, { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, ], }, ], @@ -551,6 +628,7 @@ export class Pty extends HeyApiClient { parameters: { ptyID: string directory?: string + workspace?: string }, options?: Options<never, ThrowOnError>, ) { @@ -561,6 +639,7 @@ export class Pty extends HeyApiClient { args: [ { in: "path", key: "ptyID" }, { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, ], }, ], @@ -581,6 +660,7 @@ export class Pty extends HeyApiClient { parameters: { ptyID: string directory?: string + workspace?: string title?: string size?: { rows: number @@ -596,6 +676,7 @@ export class Pty extends HeyApiClient { args: [ { in: "path", key: "ptyID" }, { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, { in: "body", key: "title" }, { in: "body", key: "size" }, ], @@ -623,6 +704,7 @@ export class Pty extends HeyApiClient { parameters: { ptyID: string directory?: string + workspace?: string }, options?: Options<never, ThrowOnError>, ) { @@ -633,6 +715,7 @@ export class Pty extends HeyApiClient { args: [ { in: "path", key: "ptyID" }, { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, ], }, ], @@ -654,10 +737,21 @@ export class Config2 extends HeyApiClient { public get<ThrowOnError extends boolean = false>( parameters?: { directory?: string + workspace?: string }, options?: Options<never, ThrowOnError>, ) { - const params = buildClientParams([parameters], [{ args: [{ in: "query", key: "directory" }] }]) + const params = buildClientParams( + [parameters], + [ + { + args: [ + { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, + ], + }, + ], + ) return (options?.client ?? this.client).get<ConfigGetResponses, unknown, ThrowOnError>({ url: "/config", ...options, @@ -673,6 +767,7 @@ export class Config2 extends HeyApiClient { public update<ThrowOnError extends boolean = false>( parameters?: { directory?: string + workspace?: string config?: Config3 }, options?: Options<never, ThrowOnError>, @@ -683,6 +778,7 @@ export class Config2 extends HeyApiClient { { args: [ { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, { key: "config", map: "body" }, ], }, @@ -708,10 +804,21 @@ export class Config2 extends HeyApiClient { public providers<ThrowOnError extends boolean = false>( parameters?: { directory?: string + workspace?: string }, options?: Options<never, ThrowOnError>, ) { - const params = buildClientParams([parameters], [{ args: [{ in: "query", key: "directory" }] }]) + const params = buildClientParams( + [parameters], + [ + { + args: [ + { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, + ], + }, + ], + ) return (options?.client ?? this.client).get<ConfigProvidersResponses, unknown, ThrowOnError>({ url: "/config/providers", ...options, @@ -729,10 +836,21 @@ export class Tool extends HeyApiClient { public ids<ThrowOnError extends boolean = false>( parameters?: { directory?: string + workspace?: string }, options?: Options<never, ThrowOnError>, ) { - const params = buildClientParams([parameters], [{ args: [{ in: "query", key: "directory" }] }]) + const params = buildClientParams( + [parameters], + [ + { + args: [ + { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, + ], + }, + ], + ) return (options?.client ?? this.client).get<ToolIdsResponses, ToolIdsErrors, ThrowOnError>({ url: "/experimental/tool/ids", ...options, @@ -748,6 +866,7 @@ export class Tool extends HeyApiClient { public list<ThrowOnError extends boolean = false>( parameters: { directory?: string + workspace?: string provider: string model: string }, @@ -759,6 +878,7 @@ export class Tool extends HeyApiClient { { args: [ { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, { in: "query", key: "provider" }, { in: "query", key: "model" }, ], @@ -773,70 +893,50 @@ export class Tool extends HeyApiClient { } } -export class Worktree extends HeyApiClient { +export class Workspace extends HeyApiClient { /** - * Remove worktree + * List workspaces * - * Remove a git worktree and delete its branch. - */ - public remove<ThrowOnError extends boolean = false>( - parameters?: { - directory?: string - worktreeRemoveInput?: WorktreeRemoveInput - }, - options?: Options<never, ThrowOnError>, - ) { - const params = buildClientParams( - [parameters], - [ - { - args: [ - { in: "query", key: "directory" }, - { key: "worktreeRemoveInput", map: "body" }, - ], - }, - ], - ) - return (options?.client ?? this.client).delete<WorktreeRemoveResponses, WorktreeRemoveErrors, ThrowOnError>({ - url: "/experimental/worktree", - ...options, - ...params, - headers: { - "Content-Type": "application/json", - ...options?.headers, - ...params.headers, - }, - }) - } - - /** - * List worktrees - * - * List all sandbox worktrees for the current project. + * List all workspaces. */ public list<ThrowOnError extends boolean = false>( parameters?: { directory?: string + workspace?: string }, options?: Options<never, ThrowOnError>, ) { - const params = buildClientParams([parameters], [{ args: [{ in: "query", key: "directory" }] }]) - return (options?.client ?? this.client).get<WorktreeListResponses, unknown, ThrowOnError>({ - url: "/experimental/worktree", + const params = buildClientParams( + [parameters], + [ + { + args: [ + { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, + ], + }, + ], + ) + return (options?.client ?? this.client).get<ExperimentalWorkspaceListResponses, unknown, ThrowOnError>({ + url: "/experimental/workspace", ...options, ...params, }) } /** - * Create worktree + * Create workspace * - * Create a new git worktree for the current project and run any configured startup scripts. + * Create a workspace for the current project. */ public create<ThrowOnError extends boolean = false>( parameters?: { directory?: string - worktreeCreateInput?: WorktreeCreateInput + workspace?: string + id?: string + type?: string + branch?: string | null + extra?: unknown | null }, options?: Options<never, ThrowOnError>, ) { @@ -846,13 +946,21 @@ export class Worktree extends HeyApiClient { { args: [ { in: "query", key: "directory" }, - { key: "worktreeCreateInput", map: "body" }, + { in: "query", key: "workspace" }, + { in: "body", key: "id" }, + { in: "body", key: "type" }, + { in: "body", key: "branch" }, + { in: "body", key: "extra" }, ], }, ], ) - return (options?.client ?? this.client).post<WorktreeCreateResponses, WorktreeCreateErrors, ThrowOnError>({ - url: "/experimental/worktree", + return (options?.client ?? this.client).post< + ExperimentalWorkspaceCreateResponses, + ExperimentalWorkspaceCreateErrors, + ThrowOnError + >({ + url: "/experimental/workspace", ...options, ...params, headers: { @@ -864,14 +972,15 @@ export class Worktree extends HeyApiClient { } /** - * Reset worktree + * Remove workspace * - * Reset a worktree branch to the primary default branch. + * Remove an existing workspace. */ - public reset<ThrowOnError extends boolean = false>( - parameters?: { + public remove<ThrowOnError extends boolean = false>( + parameters: { + id: string directory?: string - worktreeResetInput?: WorktreeResetInput + workspace?: string }, options?: Options<never, ThrowOnError>, ) { @@ -880,21 +989,21 @@ export class Worktree extends HeyApiClient { [ { args: [ + { in: "path", key: "id" }, { in: "query", key: "directory" }, - { key: "worktreeResetInput", map: "body" }, + { in: "query", key: "workspace" }, ], }, ], ) - return (options?.client ?? this.client).post<WorktreeResetResponses, WorktreeResetErrors, ThrowOnError>({ - url: "/experimental/worktree/reset", + return (options?.client ?? this.client).delete< + ExperimentalWorkspaceRemoveResponses, + ExperimentalWorkspaceRemoveErrors, + ThrowOnError + >({ + url: "/experimental/workspace/{id}", ...options, ...params, - headers: { - "Content-Type": "application/json", - ...options?.headers, - ...params.headers, - }, }) } } @@ -908,6 +1017,7 @@ export class Session extends HeyApiClient { public list<ThrowOnError extends boolean = false>( parameters?: { directory?: string + workspace?: string roots?: boolean start?: number cursor?: number @@ -923,6 +1033,7 @@ export class Session extends HeyApiClient { { args: [ { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, { in: "query", key: "roots" }, { in: "query", key: "start" }, { in: "query", key: "cursor" }, @@ -950,10 +1061,21 @@ export class Resource extends HeyApiClient { public list<ThrowOnError extends boolean = false>( parameters?: { directory?: string + workspace?: string }, options?: Options<never, ThrowOnError>, ) { - const params = buildClientParams([parameters], [{ args: [{ in: "query", key: "directory" }] }]) + const params = buildClientParams( + [parameters], + [ + { + args: [ + { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, + ], + }, + ], + ) return (options?.client ?? this.client).get<ExperimentalResourceListResponses, unknown, ThrowOnError>({ url: "/experimental/resource", ...options, @@ -963,6 +1085,11 @@ export class Resource extends HeyApiClient { } export class Experimental extends HeyApiClient { + private _workspace?: Workspace + get workspace(): Workspace { + return (this._workspace ??= new Workspace({ client: this.client })) + } + private _session?: Session get session(): Session { return (this._session ??= new Session({ client: this.client })) @@ -974,6 +1101,149 @@ export class Experimental extends HeyApiClient { } } +export class Worktree extends HeyApiClient { + /** + * Remove worktree + * + * Remove a git worktree and delete its branch. + */ + public remove<ThrowOnError extends boolean = false>( + parameters?: { + directory?: string + workspace?: string + worktreeRemoveInput?: WorktreeRemoveInput + }, + options?: Options<never, ThrowOnError>, + ) { + const params = buildClientParams( + [parameters], + [ + { + args: [ + { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, + { key: "worktreeRemoveInput", map: "body" }, + ], + }, + ], + ) + return (options?.client ?? this.client).delete<WorktreeRemoveResponses, WorktreeRemoveErrors, ThrowOnError>({ + url: "/experimental/worktree", + ...options, + ...params, + headers: { + "Content-Type": "application/json", + ...options?.headers, + ...params.headers, + }, + }) + } + + /** + * List worktrees + * + * List all sandbox worktrees for the current project. + */ + public list<ThrowOnError extends boolean = false>( + parameters?: { + directory?: string + workspace?: string + }, + options?: Options<never, ThrowOnError>, + ) { + const params = buildClientParams( + [parameters], + [ + { + args: [ + { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, + ], + }, + ], + ) + return (options?.client ?? this.client).get<WorktreeListResponses, unknown, ThrowOnError>({ + url: "/experimental/worktree", + ...options, + ...params, + }) + } + + /** + * Create worktree + * + * Create a new git worktree for the current project and run any configured startup scripts. + */ + public create<ThrowOnError extends boolean = false>( + parameters?: { + directory?: string + workspace?: string + worktreeCreateInput?: WorktreeCreateInput + }, + options?: Options<never, ThrowOnError>, + ) { + const params = buildClientParams( + [parameters], + [ + { + args: [ + { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, + { key: "worktreeCreateInput", map: "body" }, + ], + }, + ], + ) + return (options?.client ?? this.client).post<WorktreeCreateResponses, WorktreeCreateErrors, ThrowOnError>({ + url: "/experimental/worktree", + ...options, + ...params, + headers: { + "Content-Type": "application/json", + ...options?.headers, + ...params.headers, + }, + }) + } + + /** + * Reset worktree + * + * Reset a worktree branch to the primary default branch. + */ + public reset<ThrowOnError extends boolean = false>( + parameters?: { + directory?: string + workspace?: string + worktreeResetInput?: WorktreeResetInput + }, + options?: Options<never, ThrowOnError>, + ) { + const params = buildClientParams( + [parameters], + [ + { + args: [ + { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, + { key: "worktreeResetInput", map: "body" }, + ], + }, + ], + ) + return (options?.client ?? this.client).post<WorktreeResetResponses, WorktreeResetErrors, ThrowOnError>({ + url: "/experimental/worktree/reset", + ...options, + ...params, + headers: { + "Content-Type": "application/json", + ...options?.headers, + ...params.headers, + }, + }) + } +} + export class Session2 extends HeyApiClient { /** * List sessions @@ -983,6 +1253,7 @@ export class Session2 extends HeyApiClient { public list<ThrowOnError extends boolean = false>( parameters?: { directory?: string + workspace?: string roots?: boolean start?: number search?: string @@ -996,6 +1267,7 @@ export class Session2 extends HeyApiClient { { args: [ { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, { in: "query", key: "roots" }, { in: "query", key: "start" }, { in: "query", key: "search" }, @@ -1019,6 +1291,7 @@ export class Session2 extends HeyApiClient { public create<ThrowOnError extends boolean = false>( parameters?: { directory?: string + workspace?: string parentID?: string title?: string permission?: PermissionRuleset @@ -1031,6 +1304,7 @@ export class Session2 extends HeyApiClient { { args: [ { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, { in: "body", key: "parentID" }, { in: "body", key: "title" }, { in: "body", key: "permission" }, @@ -1058,10 +1332,21 @@ export class Session2 extends HeyApiClient { public status<ThrowOnError extends boolean = false>( parameters?: { directory?: string + workspace?: string }, options?: Options<never, ThrowOnError>, ) { - const params = buildClientParams([parameters], [{ args: [{ in: "query", key: "directory" }] }]) + const params = buildClientParams( + [parameters], + [ + { + args: [ + { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, + ], + }, + ], + ) return (options?.client ?? this.client).get<SessionStatusResponses, SessionStatusErrors, ThrowOnError>({ url: "/session/status", ...options, @@ -1078,6 +1363,7 @@ export class Session2 extends HeyApiClient { parameters: { sessionID: string directory?: string + workspace?: string }, options?: Options<never, ThrowOnError>, ) { @@ -1088,6 +1374,7 @@ export class Session2 extends HeyApiClient { args: [ { in: "path", key: "sessionID" }, { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, ], }, ], @@ -1108,6 +1395,7 @@ export class Session2 extends HeyApiClient { parameters: { sessionID: string directory?: string + workspace?: string }, options?: Options<never, ThrowOnError>, ) { @@ -1118,6 +1406,7 @@ export class Session2 extends HeyApiClient { args: [ { in: "path", key: "sessionID" }, { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, ], }, ], @@ -1138,6 +1427,7 @@ export class Session2 extends HeyApiClient { parameters: { sessionID: string directory?: string + workspace?: string title?: string time?: { archived?: number @@ -1152,6 +1442,7 @@ export class Session2 extends HeyApiClient { args: [ { in: "path", key: "sessionID" }, { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, { in: "body", key: "title" }, { in: "body", key: "time" }, ], @@ -1179,6 +1470,7 @@ export class Session2 extends HeyApiClient { parameters: { sessionID: string directory?: string + workspace?: string }, options?: Options<never, ThrowOnError>, ) { @@ -1189,6 +1481,7 @@ export class Session2 extends HeyApiClient { args: [ { in: "path", key: "sessionID" }, { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, ], }, ], @@ -1209,6 +1502,7 @@ export class Session2 extends HeyApiClient { parameters: { sessionID: string directory?: string + workspace?: string }, options?: Options<never, ThrowOnError>, ) { @@ -1219,6 +1513,7 @@ export class Session2 extends HeyApiClient { args: [ { in: "path", key: "sessionID" }, { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, ], }, ], @@ -1239,6 +1534,7 @@ export class Session2 extends HeyApiClient { parameters: { sessionID: string directory?: string + workspace?: string modelID?: string providerID?: string messageID?: string @@ -1252,6 +1548,7 @@ export class Session2 extends HeyApiClient { args: [ { in: "path", key: "sessionID" }, { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, { in: "body", key: "modelID" }, { in: "body", key: "providerID" }, { in: "body", key: "messageID" }, @@ -1280,6 +1577,7 @@ export class Session2 extends HeyApiClient { parameters: { sessionID: string directory?: string + workspace?: string messageID?: string }, options?: Options<never, ThrowOnError>, @@ -1291,6 +1589,7 @@ export class Session2 extends HeyApiClient { args: [ { in: "path", key: "sessionID" }, { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, { in: "body", key: "messageID" }, ], }, @@ -1317,6 +1616,7 @@ export class Session2 extends HeyApiClient { parameters: { sessionID: string directory?: string + workspace?: string }, options?: Options<never, ThrowOnError>, ) { @@ -1327,6 +1627,7 @@ export class Session2 extends HeyApiClient { args: [ { in: "path", key: "sessionID" }, { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, ], }, ], @@ -1347,6 +1648,7 @@ export class Session2 extends HeyApiClient { parameters: { sessionID: string directory?: string + workspace?: string }, options?: Options<never, ThrowOnError>, ) { @@ -1357,6 +1659,7 @@ export class Session2 extends HeyApiClient { args: [ { in: "path", key: "sessionID" }, { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, ], }, ], @@ -1377,6 +1680,7 @@ export class Session2 extends HeyApiClient { parameters: { sessionID: string directory?: string + workspace?: string }, options?: Options<never, ThrowOnError>, ) { @@ -1387,6 +1691,7 @@ export class Session2 extends HeyApiClient { args: [ { in: "path", key: "sessionID" }, { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, ], }, ], @@ -1407,6 +1712,7 @@ export class Session2 extends HeyApiClient { parameters: { sessionID: string directory?: string + workspace?: string messageID?: string }, options?: Options<never, ThrowOnError>, @@ -1418,6 +1724,7 @@ export class Session2 extends HeyApiClient { args: [ { in: "path", key: "sessionID" }, { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, { in: "query", key: "messageID" }, ], }, @@ -1439,6 +1746,7 @@ export class Session2 extends HeyApiClient { parameters: { sessionID: string directory?: string + workspace?: string providerID?: string modelID?: string auto?: boolean @@ -1452,6 +1760,7 @@ export class Session2 extends HeyApiClient { args: [ { in: "path", key: "sessionID" }, { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, { in: "body", key: "providerID" }, { in: "body", key: "modelID" }, { in: "body", key: "auto" }, @@ -1480,6 +1789,7 @@ export class Session2 extends HeyApiClient { parameters: { sessionID: string directory?: string + workspace?: string limit?: number }, options?: Options<never, ThrowOnError>, @@ -1491,6 +1801,7 @@ export class Session2 extends HeyApiClient { args: [ { in: "path", key: "sessionID" }, { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, { in: "query", key: "limit" }, ], }, @@ -1512,6 +1823,7 @@ export class Session2 extends HeyApiClient { parameters: { sessionID: string directory?: string + workspace?: string messageID?: string model?: { providerID: string @@ -1536,6 +1848,7 @@ export class Session2 extends HeyApiClient { args: [ { in: "path", key: "sessionID" }, { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, { in: "body", key: "messageID" }, { in: "body", key: "model" }, { in: "body", key: "agent" }, @@ -1562,15 +1875,16 @@ export class Session2 extends HeyApiClient { } /** - * Get message + * Delete message * - * Retrieve a specific message from a session by its message ID. + * Permanently delete a specific message (and all of its parts) from a session. This does not revert any file changes that may have been made while processing the message. */ - public message<ThrowOnError extends boolean = false>( + public deleteMessage<ThrowOnError extends boolean = false>( parameters: { sessionID: string messageID: string directory?: string + workspace?: string }, options?: Options<never, ThrowOnError>, ) { @@ -1582,6 +1896,45 @@ export class Session2 extends HeyApiClient { { in: "path", key: "sessionID" }, { in: "path", key: "messageID" }, { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, + ], + }, + ], + ) + return (options?.client ?? this.client).delete< + SessionDeleteMessageResponses, + SessionDeleteMessageErrors, + ThrowOnError + >({ + url: "/session/{sessionID}/message/{messageID}", + ...options, + ...params, + }) + } + + /** + * Get message + * + * Retrieve a specific message from a session by its message ID. + */ + public message<ThrowOnError extends boolean = false>( + parameters: { + sessionID: string + messageID: string + directory?: string + workspace?: string + }, + options?: Options<never, ThrowOnError>, + ) { + const params = buildClientParams( + [parameters], + [ + { + args: [ + { in: "path", key: "sessionID" }, + { in: "path", key: "messageID" }, + { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, ], }, ], @@ -1602,6 +1955,7 @@ export class Session2 extends HeyApiClient { parameters: { sessionID: string directory?: string + workspace?: string messageID?: string model?: { providerID: string @@ -1626,6 +1980,7 @@ export class Session2 extends HeyApiClient { args: [ { in: "path", key: "sessionID" }, { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, { in: "body", key: "messageID" }, { in: "body", key: "model" }, { in: "body", key: "agent" }, @@ -1660,6 +2015,7 @@ export class Session2 extends HeyApiClient { parameters: { sessionID: string directory?: string + workspace?: string messageID?: string agent?: string model?: string @@ -1684,6 +2040,7 @@ export class Session2 extends HeyApiClient { args: [ { in: "path", key: "sessionID" }, { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, { in: "body", key: "messageID" }, { in: "body", key: "agent" }, { in: "body", key: "model" }, @@ -1716,6 +2073,7 @@ export class Session2 extends HeyApiClient { parameters: { sessionID: string directory?: string + workspace?: string agent?: string model?: { providerID: string @@ -1732,6 +2090,7 @@ export class Session2 extends HeyApiClient { args: [ { in: "path", key: "sessionID" }, { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, { in: "body", key: "agent" }, { in: "body", key: "model" }, { in: "body", key: "command" }, @@ -1760,6 +2119,7 @@ export class Session2 extends HeyApiClient { parameters: { sessionID: string directory?: string + workspace?: string messageID?: string partID?: string }, @@ -1772,6 +2132,7 @@ export class Session2 extends HeyApiClient { args: [ { in: "path", key: "sessionID" }, { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, { in: "body", key: "messageID" }, { in: "body", key: "partID" }, ], @@ -1799,6 +2160,7 @@ export class Session2 extends HeyApiClient { parameters: { sessionID: string directory?: string + workspace?: string }, options?: Options<never, ThrowOnError>, ) { @@ -1809,6 +2171,7 @@ export class Session2 extends HeyApiClient { args: [ { in: "path", key: "sessionID" }, { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, ], }, ], @@ -1831,6 +2194,7 @@ export class Part extends HeyApiClient { messageID: string partID: string directory?: string + workspace?: string }, options?: Options<never, ThrowOnError>, ) { @@ -1843,6 +2207,7 @@ export class Part extends HeyApiClient { { in: "path", key: "messageID" }, { in: "path", key: "partID" }, { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, ], }, ], @@ -1863,6 +2228,7 @@ export class Part extends HeyApiClient { messageID: string partID: string directory?: string + workspace?: string part?: Part2 }, options?: Options<never, ThrowOnError>, @@ -1876,6 +2242,7 @@ export class Part extends HeyApiClient { { in: "path", key: "messageID" }, { in: "path", key: "partID" }, { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, { key: "part", map: "body" }, ], }, @@ -1907,6 +2274,7 @@ export class Permission extends HeyApiClient { sessionID: string permissionID: string directory?: string + workspace?: string response?: "once" | "always" | "reject" }, options?: Options<never, ThrowOnError>, @@ -1919,6 +2287,7 @@ export class Permission extends HeyApiClient { { in: "path", key: "sessionID" }, { in: "path", key: "permissionID" }, { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, { in: "body", key: "response" }, ], }, @@ -1945,6 +2314,7 @@ export class Permission extends HeyApiClient { parameters: { requestID: string directory?: string + workspace?: string reply?: "once" | "always" | "reject" message?: string }, @@ -1957,6 +2327,7 @@ export class Permission extends HeyApiClient { args: [ { in: "path", key: "requestID" }, { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, { in: "body", key: "reply" }, { in: "body", key: "message" }, ], @@ -1983,10 +2354,21 @@ export class Permission extends HeyApiClient { public list<ThrowOnError extends boolean = false>( parameters?: { directory?: string + workspace?: string }, options?: Options<never, ThrowOnError>, ) { - const params = buildClientParams([parameters], [{ args: [{ in: "query", key: "directory" }] }]) + const params = buildClientParams( + [parameters], + [ + { + args: [ + { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, + ], + }, + ], + ) return (options?.client ?? this.client).get<PermissionListResponses, unknown, ThrowOnError>({ url: "/permission", ...options, @@ -2004,10 +2386,21 @@ export class Question extends HeyApiClient { public list<ThrowOnError extends boolean = false>( parameters?: { directory?: string + workspace?: string }, options?: Options<never, ThrowOnError>, ) { - const params = buildClientParams([parameters], [{ args: [{ in: "query", key: "directory" }] }]) + const params = buildClientParams( + [parameters], + [ + { + args: [ + { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, + ], + }, + ], + ) return (options?.client ?? this.client).get<QuestionListResponses, unknown, ThrowOnError>({ url: "/question", ...options, @@ -2024,6 +2417,7 @@ export class Question extends HeyApiClient { parameters: { requestID: string directory?: string + workspace?: string answers?: Array<QuestionAnswer> }, options?: Options<never, ThrowOnError>, @@ -2035,6 +2429,7 @@ export class Question extends HeyApiClient { args: [ { in: "path", key: "requestID" }, { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, { in: "body", key: "answers" }, ], }, @@ -2061,6 +2456,7 @@ export class Question extends HeyApiClient { parameters: { requestID: string directory?: string + workspace?: string }, options?: Options<never, ThrowOnError>, ) { @@ -2071,6 +2467,7 @@ export class Question extends HeyApiClient { args: [ { in: "path", key: "requestID" }, { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, ], }, ], @@ -2093,6 +2490,7 @@ export class Oauth extends HeyApiClient { parameters: { providerID: string directory?: string + workspace?: string method?: number }, options?: Options<never, ThrowOnError>, @@ -2104,6 +2502,7 @@ export class Oauth extends HeyApiClient { args: [ { in: "path", key: "providerID" }, { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, { in: "body", key: "method" }, ], }, @@ -2134,6 +2533,7 @@ export class Oauth extends HeyApiClient { parameters: { providerID: string directory?: string + workspace?: string method?: number code?: string }, @@ -2146,6 +2546,7 @@ export class Oauth extends HeyApiClient { args: [ { in: "path", key: "providerID" }, { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, { in: "body", key: "method" }, { in: "body", key: "code" }, ], @@ -2178,10 +2579,21 @@ export class Provider extends HeyApiClient { public list<ThrowOnError extends boolean = false>( parameters?: { directory?: string + workspace?: string }, options?: Options<never, ThrowOnError>, ) { - const params = buildClientParams([parameters], [{ args: [{ in: "query", key: "directory" }] }]) + const params = buildClientParams( + [parameters], + [ + { + args: [ + { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, + ], + }, + ], + ) return (options?.client ?? this.client).get<ProviderListResponses, unknown, ThrowOnError>({ url: "/provider", ...options, @@ -2197,10 +2609,21 @@ export class Provider extends HeyApiClient { public auth<ThrowOnError extends boolean = false>( parameters?: { directory?: string + workspace?: string }, options?: Options<never, ThrowOnError>, ) { - const params = buildClientParams([parameters], [{ args: [{ in: "query", key: "directory" }] }]) + const params = buildClientParams( + [parameters], + [ + { + args: [ + { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, + ], + }, + ], + ) return (options?.client ?? this.client).get<ProviderAuthResponses, unknown, ThrowOnError>({ url: "/provider/auth", ...options, @@ -2223,6 +2646,7 @@ export class Find extends HeyApiClient { public text<ThrowOnError extends boolean = false>( parameters: { directory?: string + workspace?: string pattern: string }, options?: Options<never, ThrowOnError>, @@ -2233,6 +2657,7 @@ export class Find extends HeyApiClient { { args: [ { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, { in: "query", key: "pattern" }, ], }, @@ -2253,6 +2678,7 @@ export class Find extends HeyApiClient { public files<ThrowOnError extends boolean = false>( parameters: { directory?: string + workspace?: string query: string dirs?: "true" | "false" type?: "file" | "directory" @@ -2266,6 +2692,7 @@ export class Find extends HeyApiClient { { args: [ { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, { in: "query", key: "query" }, { in: "query", key: "dirs" }, { in: "query", key: "type" }, @@ -2289,6 +2716,7 @@ export class Find extends HeyApiClient { public symbols<ThrowOnError extends boolean = false>( parameters: { directory?: string + workspace?: string query: string }, options?: Options<never, ThrowOnError>, @@ -2299,6 +2727,7 @@ export class Find extends HeyApiClient { { args: [ { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, { in: "query", key: "query" }, ], }, @@ -2321,6 +2750,7 @@ export class File extends HeyApiClient { public list<ThrowOnError extends boolean = false>( parameters: { directory?: string + workspace?: string path: string }, options?: Options<never, ThrowOnError>, @@ -2331,6 +2761,7 @@ export class File extends HeyApiClient { { args: [ { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, { in: "query", key: "path" }, ], }, @@ -2351,6 +2782,7 @@ export class File extends HeyApiClient { public read<ThrowOnError extends boolean = false>( parameters: { directory?: string + workspace?: string path: string }, options?: Options<never, ThrowOnError>, @@ -2361,6 +2793,7 @@ export class File extends HeyApiClient { { args: [ { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, { in: "query", key: "path" }, ], }, @@ -2381,10 +2814,21 @@ export class File extends HeyApiClient { public status<ThrowOnError extends boolean = false>( parameters?: { directory?: string + workspace?: string }, options?: Options<never, ThrowOnError>, ) { - const params = buildClientParams([parameters], [{ args: [{ in: "query", key: "directory" }] }]) + const params = buildClientParams( + [parameters], + [ + { + args: [ + { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, + ], + }, + ], + ) return (options?.client ?? this.client).get<FileStatusResponses, unknown, ThrowOnError>({ url: "/file/status", ...options, @@ -2403,6 +2847,7 @@ export class Auth2 extends HeyApiClient { parameters: { name: string directory?: string + workspace?: string }, options?: Options<never, ThrowOnError>, ) { @@ -2413,6 +2858,7 @@ export class Auth2 extends HeyApiClient { args: [ { in: "path", key: "name" }, { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, ], }, ], @@ -2433,6 +2879,7 @@ export class Auth2 extends HeyApiClient { parameters: { name: string directory?: string + workspace?: string }, options?: Options<never, ThrowOnError>, ) { @@ -2443,6 +2890,7 @@ export class Auth2 extends HeyApiClient { args: [ { in: "path", key: "name" }, { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, ], }, ], @@ -2463,6 +2911,7 @@ export class Auth2 extends HeyApiClient { parameters: { name: string directory?: string + workspace?: string code?: string }, options?: Options<never, ThrowOnError>, @@ -2474,6 +2923,7 @@ export class Auth2 extends HeyApiClient { args: [ { in: "path", key: "name" }, { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, { in: "body", key: "code" }, ], }, @@ -2500,6 +2950,7 @@ export class Auth2 extends HeyApiClient { parameters: { name: string directory?: string + workspace?: string }, options?: Options<never, ThrowOnError>, ) { @@ -2510,6 +2961,7 @@ export class Auth2 extends HeyApiClient { args: [ { in: "path", key: "name" }, { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, ], }, ], @@ -2533,10 +2985,21 @@ export class Mcp extends HeyApiClient { public status<ThrowOnError extends boolean = false>( parameters?: { directory?: string + workspace?: string }, options?: Options<never, ThrowOnError>, ) { - const params = buildClientParams([parameters], [{ args: [{ in: "query", key: "directory" }] }]) + const params = buildClientParams( + [parameters], + [ + { + args: [ + { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, + ], + }, + ], + ) return (options?.client ?? this.client).get<McpStatusResponses, unknown, ThrowOnError>({ url: "/mcp", ...options, @@ -2552,6 +3015,7 @@ export class Mcp extends HeyApiClient { public add<ThrowOnError extends boolean = false>( parameters?: { directory?: string + workspace?: string name?: string config?: McpLocalConfig | McpRemoteConfig }, @@ -2563,6 +3027,7 @@ export class Mcp extends HeyApiClient { { args: [ { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, { in: "body", key: "name" }, { in: "body", key: "config" }, ], @@ -2588,6 +3053,7 @@ export class Mcp extends HeyApiClient { parameters: { name: string directory?: string + workspace?: string }, options?: Options<never, ThrowOnError>, ) { @@ -2598,6 +3064,7 @@ export class Mcp extends HeyApiClient { args: [ { in: "path", key: "name" }, { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, ], }, ], @@ -2616,6 +3083,7 @@ export class Mcp extends HeyApiClient { parameters: { name: string directory?: string + workspace?: string }, options?: Options<never, ThrowOnError>, ) { @@ -2626,6 +3094,7 @@ export class Mcp extends HeyApiClient { args: [ { in: "path", key: "name" }, { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, ], }, ], @@ -2652,10 +3121,21 @@ export class Control extends HeyApiClient { public next<ThrowOnError extends boolean = false>( parameters?: { directory?: string + workspace?: string }, options?: Options<never, ThrowOnError>, ) { - const params = buildClientParams([parameters], [{ args: [{ in: "query", key: "directory" }] }]) + const params = buildClientParams( + [parameters], + [ + { + args: [ + { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, + ], + }, + ], + ) return (options?.client ?? this.client).get<TuiControlNextResponses, unknown, ThrowOnError>({ url: "/tui/control/next", ...options, @@ -2671,6 +3151,7 @@ export class Control extends HeyApiClient { public response<ThrowOnError extends boolean = false>( parameters?: { directory?: string + workspace?: string body?: unknown }, options?: Options<never, ThrowOnError>, @@ -2681,6 +3162,7 @@ export class Control extends HeyApiClient { { args: [ { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, { key: "body", map: "body" }, ], }, @@ -2708,6 +3190,7 @@ export class Tui extends HeyApiClient { public appendPrompt<ThrowOnError extends boolean = false>( parameters?: { directory?: string + workspace?: string text?: string }, options?: Options<never, ThrowOnError>, @@ -2718,6 +3201,7 @@ export class Tui extends HeyApiClient { { args: [ { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, { in: "body", key: "text" }, ], }, @@ -2743,10 +3227,21 @@ export class Tui extends HeyApiClient { public openHelp<ThrowOnError extends boolean = false>( parameters?: { directory?: string + workspace?: string }, options?: Options<never, ThrowOnError>, ) { - const params = buildClientParams([parameters], [{ args: [{ in: "query", key: "directory" }] }]) + const params = buildClientParams( + [parameters], + [ + { + args: [ + { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, + ], + }, + ], + ) return (options?.client ?? this.client).post<TuiOpenHelpResponses, unknown, ThrowOnError>({ url: "/tui/open-help", ...options, @@ -2762,10 +3257,21 @@ export class Tui extends HeyApiClient { public openSessions<ThrowOnError extends boolean = false>( parameters?: { directory?: string + workspace?: string }, options?: Options<never, ThrowOnError>, ) { - const params = buildClientParams([parameters], [{ args: [{ in: "query", key: "directory" }] }]) + const params = buildClientParams( + [parameters], + [ + { + args: [ + { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, + ], + }, + ], + ) return (options?.client ?? this.client).post<TuiOpenSessionsResponses, unknown, ThrowOnError>({ url: "/tui/open-sessions", ...options, @@ -2781,10 +3287,21 @@ export class Tui extends HeyApiClient { public openThemes<ThrowOnError extends boolean = false>( parameters?: { directory?: string + workspace?: string }, options?: Options<never, ThrowOnError>, ) { - const params = buildClientParams([parameters], [{ args: [{ in: "query", key: "directory" }] }]) + const params = buildClientParams( + [parameters], + [ + { + args: [ + { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, + ], + }, + ], + ) return (options?.client ?? this.client).post<TuiOpenThemesResponses, unknown, ThrowOnError>({ url: "/tui/open-themes", ...options, @@ -2800,10 +3317,21 @@ export class Tui extends HeyApiClient { public openModels<ThrowOnError extends boolean = false>( parameters?: { directory?: string + workspace?: string }, options?: Options<never, ThrowOnError>, ) { - const params = buildClientParams([parameters], [{ args: [{ in: "query", key: "directory" }] }]) + const params = buildClientParams( + [parameters], + [ + { + args: [ + { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, + ], + }, + ], + ) return (options?.client ?? this.client).post<TuiOpenModelsResponses, unknown, ThrowOnError>({ url: "/tui/open-models", ...options, @@ -2819,10 +3347,21 @@ export class Tui extends HeyApiClient { public submitPrompt<ThrowOnError extends boolean = false>( parameters?: { directory?: string + workspace?: string }, options?: Options<never, ThrowOnError>, ) { - const params = buildClientParams([parameters], [{ args: [{ in: "query", key: "directory" }] }]) + const params = buildClientParams( + [parameters], + [ + { + args: [ + { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, + ], + }, + ], + ) return (options?.client ?? this.client).post<TuiSubmitPromptResponses, unknown, ThrowOnError>({ url: "/tui/submit-prompt", ...options, @@ -2838,10 +3377,21 @@ export class Tui extends HeyApiClient { public clearPrompt<ThrowOnError extends boolean = false>( parameters?: { directory?: string + workspace?: string }, options?: Options<never, ThrowOnError>, ) { - const params = buildClientParams([parameters], [{ args: [{ in: "query", key: "directory" }] }]) + const params = buildClientParams( + [parameters], + [ + { + args: [ + { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, + ], + }, + ], + ) return (options?.client ?? this.client).post<TuiClearPromptResponses, unknown, ThrowOnError>({ url: "/tui/clear-prompt", ...options, @@ -2857,6 +3407,7 @@ export class Tui extends HeyApiClient { public executeCommand<ThrowOnError extends boolean = false>( parameters?: { directory?: string + workspace?: string command?: string }, options?: Options<never, ThrowOnError>, @@ -2867,6 +3418,7 @@ export class Tui extends HeyApiClient { { args: [ { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, { in: "body", key: "command" }, ], }, @@ -2892,6 +3444,7 @@ export class Tui extends HeyApiClient { public showToast<ThrowOnError extends boolean = false>( parameters?: { directory?: string + workspace?: string title?: string message?: string variant?: "info" | "success" | "warning" | "error" @@ -2905,6 +3458,7 @@ export class Tui extends HeyApiClient { { args: [ { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, { in: "body", key: "title" }, { in: "body", key: "message" }, { in: "body", key: "variant" }, @@ -2933,6 +3487,7 @@ export class Tui extends HeyApiClient { public publish<ThrowOnError extends boolean = false>( parameters?: { directory?: string + workspace?: string body?: EventTuiPromptAppend | EventTuiCommandExecute | EventTuiToastShow | EventTuiSessionSelect }, options?: Options<never, ThrowOnError>, @@ -2943,6 +3498,7 @@ export class Tui extends HeyApiClient { { args: [ { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, { key: "body", map: "body" }, ], }, @@ -2968,6 +3524,7 @@ export class Tui extends HeyApiClient { public selectSession<ThrowOnError extends boolean = false>( parameters?: { directory?: string + workspace?: string sessionID?: string }, options?: Options<never, ThrowOnError>, @@ -2978,6 +3535,7 @@ export class Tui extends HeyApiClient { { args: [ { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, { in: "body", key: "sessionID" }, ], }, @@ -3010,10 +3568,21 @@ export class Instance extends HeyApiClient { public dispose<ThrowOnError extends boolean = false>( parameters?: { directory?: string + workspace?: string }, options?: Options<never, ThrowOnError>, ) { - const params = buildClientParams([parameters], [{ args: [{ in: "query", key: "directory" }] }]) + const params = buildClientParams( + [parameters], + [ + { + args: [ + { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, + ], + }, + ], + ) return (options?.client ?? this.client).post<InstanceDisposeResponses, unknown, ThrowOnError>({ url: "/instance/dispose", ...options, @@ -3031,10 +3600,21 @@ export class Path extends HeyApiClient { public get<ThrowOnError extends boolean = false>( parameters?: { directory?: string + workspace?: string }, options?: Options<never, ThrowOnError>, ) { - const params = buildClientParams([parameters], [{ args: [{ in: "query", key: "directory" }] }]) + const params = buildClientParams( + [parameters], + [ + { + args: [ + { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, + ], + }, + ], + ) return (options?.client ?? this.client).get<PathGetResponses, unknown, ThrowOnError>({ url: "/path", ...options, @@ -3052,10 +3632,21 @@ export class Vcs extends HeyApiClient { public get<ThrowOnError extends boolean = false>( parameters?: { directory?: string + workspace?: string }, options?: Options<never, ThrowOnError>, ) { - const params = buildClientParams([parameters], [{ args: [{ in: "query", key: "directory" }] }]) + const params = buildClientParams( + [parameters], + [ + { + args: [ + { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, + ], + }, + ], + ) return (options?.client ?? this.client).get<VcsGetResponses, unknown, ThrowOnError>({ url: "/vcs", ...options, @@ -3073,10 +3664,21 @@ export class Command extends HeyApiClient { public list<ThrowOnError extends boolean = false>( parameters?: { directory?: string + workspace?: string }, options?: Options<never, ThrowOnError>, ) { - const params = buildClientParams([parameters], [{ args: [{ in: "query", key: "directory" }] }]) + const params = buildClientParams( + [parameters], + [ + { + args: [ + { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, + ], + }, + ], + ) return (options?.client ?? this.client).get<CommandListResponses, unknown, ThrowOnError>({ url: "/command", ...options, @@ -3094,6 +3696,7 @@ export class App extends HeyApiClient { public log<ThrowOnError extends boolean = false>( parameters?: { directory?: string + workspace?: string service?: string level?: "debug" | "info" | "error" | "warn" message?: string @@ -3109,6 +3712,7 @@ export class App extends HeyApiClient { { args: [ { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, { in: "body", key: "service" }, { in: "body", key: "level" }, { in: "body", key: "message" }, @@ -3137,10 +3741,21 @@ export class App extends HeyApiClient { public agents<ThrowOnError extends boolean = false>( parameters?: { directory?: string + workspace?: string }, options?: Options<never, ThrowOnError>, ) { - const params = buildClientParams([parameters], [{ args: [{ in: "query", key: "directory" }] }]) + const params = buildClientParams( + [parameters], + [ + { + args: [ + { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, + ], + }, + ], + ) return (options?.client ?? this.client).get<AppAgentsResponses, unknown, ThrowOnError>({ url: "/agent", ...options, @@ -3156,10 +3771,21 @@ export class App extends HeyApiClient { public skills<ThrowOnError extends boolean = false>( parameters?: { directory?: string + workspace?: string }, options?: Options<never, ThrowOnError>, ) { - const params = buildClientParams([parameters], [{ args: [{ in: "query", key: "directory" }] }]) + const params = buildClientParams( + [parameters], + [ + { + args: [ + { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, + ], + }, + ], + ) return (options?.client ?? this.client).get<AppSkillsResponses, unknown, ThrowOnError>({ url: "/skill", ...options, @@ -3177,10 +3803,21 @@ export class Lsp extends HeyApiClient { public status<ThrowOnError extends boolean = false>( parameters?: { directory?: string + workspace?: string }, options?: Options<never, ThrowOnError>, ) { - const params = buildClientParams([parameters], [{ args: [{ in: "query", key: "directory" }] }]) + const params = buildClientParams( + [parameters], + [ + { + args: [ + { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, + ], + }, + ], + ) return (options?.client ?? this.client).get<LspStatusResponses, unknown, ThrowOnError>({ url: "/lsp", ...options, @@ -3198,10 +3835,21 @@ export class Formatter extends HeyApiClient { public status<ThrowOnError extends boolean = false>( parameters?: { directory?: string + workspace?: string }, options?: Options<never, ThrowOnError>, ) { - const params = buildClientParams([parameters], [{ args: [{ in: "query", key: "directory" }] }]) + const params = buildClientParams( + [parameters], + [ + { + args: [ + { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, + ], + }, + ], + ) return (options?.client ?? this.client).get<FormatterStatusResponses, unknown, ThrowOnError>({ url: "/formatter", ...options, @@ -3219,10 +3867,21 @@ export class Event extends HeyApiClient { public subscribe<ThrowOnError extends boolean = false>( parameters?: { directory?: string + workspace?: string }, options?: Options<never, ThrowOnError>, ) { - const params = buildClientParams([parameters], [{ args: [{ in: "query", key: "directory" }] }]) + const params = buildClientParams( + [parameters], + [ + { + args: [ + { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, + ], + }, + ], + ) return (options?.client ?? this.client).sse.get<EventSubscribeResponses, unknown, ThrowOnError>({ url: "/event", ...options, @@ -3269,16 +3928,16 @@ export class OpencodeClient extends HeyApiClient { return (this._tool ??= new Tool({ client: this.client })) } - private _worktree?: Worktree - get worktree(): Worktree { - return (this._worktree ??= new Worktree({ client: this.client })) - } - private _experimental?: Experimental get experimental(): Experimental { return (this._experimental ??= new Experimental({ client: this.client })) } + private _worktree?: Worktree + get worktree(): Worktree { + return (this._worktree ??= new Worktree({ client: this.client })) + } + private _session?: Session2 get session(): Session2 { return (this._session ??= new Session2({ client: this.client })) diff --git a/packages/sdk/js/src/v2/gen/types.gen.ts b/packages/sdk/js/src/v2/gen/types.gen.ts index 4050ef1573..71e075b391 100644 --- a/packages/sdk/js/src/v2/gen/types.gen.ts +++ b/packages/sdk/js/src/v2/gen/types.gen.ts @@ -505,6 +505,7 @@ export type CompactionPart = { messageID: string type: "compaction" auto: boolean + overflow?: boolean } export type Part = @@ -808,6 +809,7 @@ export type Session = { id: string slug: string projectID: string + workspaceID?: string directory: string parentID?: string summary?: { @@ -887,6 +889,20 @@ export type EventVcsBranchUpdated = { } } +export type EventWorkspaceReady = { + type: "workspace.ready" + properties: { + name: string + } +} + +export type EventWorkspaceFailed = { + type: "workspace.failed" + properties: { + message: string + } +} + export type Pty = { id: string title: string @@ -979,6 +995,8 @@ export type Event = | EventSessionDiff | EventSessionError | EventVcsBranchUpdated + | EventWorkspaceReady + | EventWorkspaceFailed | EventPtyCreated | EventPtyUpdated | EventPtyExited @@ -991,388 +1009,6 @@ export type GlobalEvent = { payload: Event } -/** - * Custom keybind configurations - */ -export type KeybindsConfig = { - /** - * Leader key for keybind combinations - */ - leader?: string - /** - * Exit the application - */ - app_exit?: string - /** - * Open external editor - */ - editor_open?: string - /** - * List available themes - */ - theme_list?: string - /** - * Toggle sidebar - */ - sidebar_toggle?: string - /** - * Toggle session scrollbar - */ - scrollbar_toggle?: string - /** - * Toggle username visibility - */ - username_toggle?: string - /** - * View status - */ - status_view?: string - /** - * Export session to editor - */ - session_export?: string - /** - * Create a new session - */ - session_new?: string - /** - * List all sessions - */ - session_list?: string - /** - * Show session timeline - */ - session_timeline?: string - /** - * Fork session from message - */ - session_fork?: string - /** - * Rename session - */ - session_rename?: string - /** - * Delete session - */ - session_delete?: string - /** - * Delete stash entry - */ - stash_delete?: string - /** - * Open provider list from model dialog - */ - model_provider_list?: string - /** - * Toggle model favorite status - */ - model_favorite_toggle?: string - /** - * Share current session - */ - session_share?: string - /** - * Unshare current session - */ - session_unshare?: string - /** - * Interrupt current session - */ - session_interrupt?: string - /** - * Compact the session - */ - session_compact?: string - /** - * Scroll messages up by one page - */ - messages_page_up?: string - /** - * Scroll messages down by one page - */ - messages_page_down?: string - /** - * Scroll messages up by one line - */ - messages_line_up?: string - /** - * Scroll messages down by one line - */ - messages_line_down?: string - /** - * Scroll messages up by half page - */ - messages_half_page_up?: string - /** - * Scroll messages down by half page - */ - messages_half_page_down?: string - /** - * Navigate to first message - */ - messages_first?: string - /** - * Navigate to last message - */ - messages_last?: string - /** - * Navigate to next message - */ - messages_next?: string - /** - * Navigate to previous message - */ - messages_previous?: string - /** - * Navigate to last user message - */ - messages_last_user?: string - /** - * Copy message - */ - messages_copy?: string - /** - * Undo message - */ - messages_undo?: string - /** - * Redo message - */ - messages_redo?: string - /** - * Toggle code block concealment in messages - */ - messages_toggle_conceal?: string - /** - * Toggle tool details visibility - */ - tool_details?: string - /** - * List available models - */ - model_list?: string - /** - * Next recently used model - */ - model_cycle_recent?: string - /** - * Previous recently used model - */ - model_cycle_recent_reverse?: string - /** - * Next favorite model - */ - model_cycle_favorite?: string - /** - * Previous favorite model - */ - model_cycle_favorite_reverse?: string - /** - * List available commands - */ - command_list?: string - /** - * List agents - */ - agent_list?: string - /** - * Next agent - */ - agent_cycle?: string - /** - * Previous agent - */ - agent_cycle_reverse?: string - /** - * Cycle model variants - */ - variant_cycle?: string - /** - * Clear input field - */ - input_clear?: string - /** - * Paste from clipboard - */ - input_paste?: string - /** - * Submit input - */ - input_submit?: string - /** - * Insert newline in input - */ - input_newline?: string - /** - * Move cursor left in input - */ - input_move_left?: string - /** - * Move cursor right in input - */ - input_move_right?: string - /** - * Move cursor up in input - */ - input_move_up?: string - /** - * Move cursor down in input - */ - input_move_down?: string - /** - * Select left in input - */ - input_select_left?: string - /** - * Select right in input - */ - input_select_right?: string - /** - * Select up in input - */ - input_select_up?: string - /** - * Select down in input - */ - input_select_down?: string - /** - * Move to start of line in input - */ - input_line_home?: string - /** - * Move to end of line in input - */ - input_line_end?: string - /** - * Select to start of line in input - */ - input_select_line_home?: string - /** - * Select to end of line in input - */ - input_select_line_end?: string - /** - * Move to start of visual line in input - */ - input_visual_line_home?: string - /** - * Move to end of visual line in input - */ - input_visual_line_end?: string - /** - * Select to start of visual line in input - */ - input_select_visual_line_home?: string - /** - * Select to end of visual line in input - */ - input_select_visual_line_end?: string - /** - * Move to start of buffer in input - */ - input_buffer_home?: string - /** - * Move to end of buffer in input - */ - input_buffer_end?: string - /** - * Select to start of buffer in input - */ - input_select_buffer_home?: string - /** - * Select to end of buffer in input - */ - input_select_buffer_end?: string - /** - * Delete line in input - */ - input_delete_line?: string - /** - * Delete to end of line in input - */ - input_delete_to_line_end?: string - /** - * Delete to start of line in input - */ - input_delete_to_line_start?: string - /** - * Backspace in input - */ - input_backspace?: string - /** - * Delete character in input - */ - input_delete?: string - /** - * Undo in input - */ - input_undo?: string - /** - * Redo in input - */ - input_redo?: string - /** - * Move word forward in input - */ - input_word_forward?: string - /** - * Move word backward in input - */ - input_word_backward?: string - /** - * Select word forward in input - */ - input_select_word_forward?: string - /** - * Select word backward in input - */ - input_select_word_backward?: string - /** - * Delete word forward in input - */ - input_delete_word_forward?: string - /** - * Delete word backward in input - */ - input_delete_word_backward?: string - /** - * Previous history item - */ - history_previous?: string - /** - * Next history item - */ - history_next?: string - /** - * Next child session - */ - session_child_cycle?: string - /** - * Previous child session - */ - session_child_cycle_reverse?: string - /** - * Go to parent session - */ - session_parent?: string - /** - * Suspend terminal - */ - terminal_suspend?: string - /** - * Toggle terminal title - */ - terminal_title_toggle?: string - /** - * Toggle tips on home screen - */ - tips_toggle?: string - /** - * Toggle thinking blocks visibility - */ - display_thinking?: string -} - /** * Log level */ @@ -1672,34 +1308,7 @@ export type Config = { * JSON schema reference for configuration validation */ $schema?: string - /** - * Theme name to use for the interface - */ - theme?: string - keybinds?: KeybindsConfig logLevel?: LogLevel - /** - * TUI specific settings - */ - tui?: { - /** - * TUI scroll speed - */ - scroll_speed?: number - /** - * Scroll acceleration settings - */ - scroll_acceleration?: { - /** - * Enable scroll acceleration - */ - enabled: boolean - } - /** - * Control diff rendering style: 'auto' adapts to terminal width, 'stacked' always shows single column - */ - diff_style?: "auto" | "stacked" - } server?: ServerConfig /** * Command configuration, see https://opencode.ai/docs/commands @@ -2022,6 +1631,16 @@ export type ToolListItem = { export type ToolList = Array<ToolListItem> +export type Workspace = { + id: string + type: string + branch: string | null + name: string | null + directory: string | null + extra: unknown | null + projectID: string +} + export type Worktree = { name: string branch: string @@ -2054,6 +1673,7 @@ export type GlobalSession = { id: string slug: string projectID: string + workspaceID?: string directory: string parentID?: string summary?: { @@ -2434,6 +2054,7 @@ export type ProjectListData = { path?: never query?: { directory?: string + workspace?: string } url: "/project" } @@ -2452,6 +2073,7 @@ export type ProjectCurrentData = { path?: never query?: { directory?: string + workspace?: string } url: "/project/current" } @@ -2465,6 +2087,25 @@ export type ProjectCurrentResponses = { export type ProjectCurrentResponse = ProjectCurrentResponses[keyof ProjectCurrentResponses] +export type ProjectInitGitData = { + body?: never + path?: never + query?: { + directory?: string + workspace?: string + } + url: "/project/git/init" +} + +export type ProjectInitGitResponses = { + /** + * Project information after git initialization + */ + 200: Project +} + +export type ProjectInitGitResponse = ProjectInitGitResponses[keyof ProjectInitGitResponses] + export type ProjectUpdateData = { body?: { name?: string @@ -2485,6 +2126,7 @@ export type ProjectUpdateData = { } query?: { directory?: string + workspace?: string } url: "/project/{projectID}" } @@ -2516,6 +2158,7 @@ export type PtyListData = { path?: never query?: { directory?: string + workspace?: string } url: "/pty" } @@ -2542,6 +2185,7 @@ export type PtyCreateData = { path?: never query?: { directory?: string + workspace?: string } url: "/pty" } @@ -2571,6 +2215,7 @@ export type PtyRemoveData = { } query?: { directory?: string + workspace?: string } url: "/pty/{ptyID}" } @@ -2600,6 +2245,7 @@ export type PtyGetData = { } query?: { directory?: string + workspace?: string } url: "/pty/{ptyID}" } @@ -2635,6 +2281,7 @@ export type PtyUpdateData = { } query?: { directory?: string + workspace?: string } url: "/pty/{ptyID}" } @@ -2664,6 +2311,7 @@ export type PtyConnectData = { } query?: { directory?: string + workspace?: string } url: "/pty/{ptyID}/connect" } @@ -2691,6 +2339,7 @@ export type ConfigGetData = { path?: never query?: { directory?: string + workspace?: string } url: "/config" } @@ -2709,6 +2358,7 @@ export type ConfigUpdateData = { path?: never query?: { directory?: string + workspace?: string } url: "/config" } @@ -2736,6 +2386,7 @@ export type ConfigProvidersData = { path?: never query?: { directory?: string + workspace?: string } url: "/config/providers" } @@ -2759,6 +2410,7 @@ export type ToolIdsData = { path?: never query?: { directory?: string + workspace?: string } url: "/experimental/tool/ids" } @@ -2786,6 +2438,7 @@ export type ToolListData = { path?: never query: { directory?: string + workspace?: string provider: string model: string } @@ -2810,11 +2463,99 @@ export type ToolListResponses = { export type ToolListResponse = ToolListResponses[keyof ToolListResponses] +export type ExperimentalWorkspaceListData = { + body?: never + path?: never + query?: { + directory?: string + workspace?: string + } + url: "/experimental/workspace" +} + +export type ExperimentalWorkspaceListResponses = { + /** + * Workspaces + */ + 200: Array<Workspace> +} + +export type ExperimentalWorkspaceListResponse = + ExperimentalWorkspaceListResponses[keyof ExperimentalWorkspaceListResponses] + +export type ExperimentalWorkspaceCreateData = { + body?: { + id?: string + type: string + branch: string | null + extra: unknown | null + } + path?: never + query?: { + directory?: string + workspace?: string + } + url: "/experimental/workspace" +} + +export type ExperimentalWorkspaceCreateErrors = { + /** + * Bad request + */ + 400: BadRequestError +} + +export type ExperimentalWorkspaceCreateError = + ExperimentalWorkspaceCreateErrors[keyof ExperimentalWorkspaceCreateErrors] + +export type ExperimentalWorkspaceCreateResponses = { + /** + * Workspace created + */ + 200: Workspace +} + +export type ExperimentalWorkspaceCreateResponse = + ExperimentalWorkspaceCreateResponses[keyof ExperimentalWorkspaceCreateResponses] + +export type ExperimentalWorkspaceRemoveData = { + body?: never + path: { + id: string + } + query?: { + directory?: string + workspace?: string + } + url: "/experimental/workspace/{id}" +} + +export type ExperimentalWorkspaceRemoveErrors = { + /** + * Bad request + */ + 400: BadRequestError +} + +export type ExperimentalWorkspaceRemoveError = + ExperimentalWorkspaceRemoveErrors[keyof ExperimentalWorkspaceRemoveErrors] + +export type ExperimentalWorkspaceRemoveResponses = { + /** + * Workspace removed + */ + 200: Workspace +} + +export type ExperimentalWorkspaceRemoveResponse = + ExperimentalWorkspaceRemoveResponses[keyof ExperimentalWorkspaceRemoveResponses] + export type WorktreeRemoveData = { body?: WorktreeRemoveInput path?: never query?: { directory?: string + workspace?: string } url: "/experimental/worktree" } @@ -2842,6 +2583,7 @@ export type WorktreeListData = { path?: never query?: { directory?: string + workspace?: string } url: "/experimental/worktree" } @@ -2860,6 +2602,7 @@ export type WorktreeCreateData = { path?: never query?: { directory?: string + workspace?: string } url: "/experimental/worktree" } @@ -2887,6 +2630,7 @@ export type WorktreeResetData = { path?: never query?: { directory?: string + workspace?: string } url: "/experimental/worktree/reset" } @@ -2917,6 +2661,7 @@ export type ExperimentalSessionListData = { * Filter sessions by project directory */ directory?: string + workspace?: string /** * Only return root sessions (no parentID) */ @@ -2959,6 +2704,7 @@ export type ExperimentalResourceListData = { path?: never query?: { directory?: string + workspace?: string } url: "/experimental/resource" } @@ -2983,6 +2729,7 @@ export type SessionListData = { * Filter sessions by project directory */ directory?: string + workspace?: string /** * Only return root sessions (no parentID) */ @@ -3021,6 +2768,7 @@ export type SessionCreateData = { path?: never query?: { directory?: string + workspace?: string } url: "/session" } @@ -3048,6 +2796,7 @@ export type SessionStatusData = { path?: never query?: { directory?: string + workspace?: string } url: "/session/status" } @@ -3079,6 +2828,7 @@ export type SessionDeleteData = { } query?: { directory?: string + workspace?: string } url: "/session/{sessionID}" } @@ -3112,6 +2862,7 @@ export type SessionGetData = { } query?: { directory?: string + workspace?: string } url: "/session/{sessionID}" } @@ -3150,6 +2901,7 @@ export type SessionUpdateData = { } query?: { directory?: string + workspace?: string } url: "/session/{sessionID}" } @@ -3183,6 +2935,7 @@ export type SessionChildrenData = { } query?: { directory?: string + workspace?: string } url: "/session/{sessionID}/children" } @@ -3219,6 +2972,7 @@ export type SessionTodoData = { } query?: { directory?: string + workspace?: string } url: "/session/{sessionID}/todo" } @@ -3259,6 +3013,7 @@ export type SessionInitData = { } query?: { directory?: string + workspace?: string } url: "/session/{sessionID}/init" } @@ -3294,6 +3049,7 @@ export type SessionForkData = { } query?: { directory?: string + workspace?: string } url: "/session/{sessionID}/fork" } @@ -3314,6 +3070,7 @@ export type SessionAbortData = { } query?: { directory?: string + workspace?: string } url: "/session/{sessionID}/abort" } @@ -3347,6 +3104,7 @@ export type SessionUnshareData = { } query?: { directory?: string + workspace?: string } url: "/session/{sessionID}/share" } @@ -3380,6 +3138,7 @@ export type SessionShareData = { } query?: { directory?: string + workspace?: string } url: "/session/{sessionID}/share" } @@ -3413,6 +3172,7 @@ export type SessionDiffData = { } query?: { directory?: string + workspace?: string messageID?: string } url: "/session/{sessionID}/diff" @@ -3441,6 +3201,7 @@ export type SessionSummarizeData = { } query?: { directory?: string + workspace?: string } url: "/session/{sessionID}/summarize" } @@ -3477,6 +3238,7 @@ export type SessionMessagesData = { } query?: { directory?: string + workspace?: string limit?: number } url: "/session/{sessionID}/message" @@ -3535,6 +3297,7 @@ export type SessionPromptData = { } query?: { directory?: string + workspace?: string } url: "/session/{sessionID}/message" } @@ -3564,6 +3327,47 @@ export type SessionPromptResponses = { export type SessionPromptResponse = SessionPromptResponses[keyof SessionPromptResponses] +export type SessionDeleteMessageData = { + body?: never + path: { + /** + * Session ID + */ + sessionID: string + /** + * Message ID + */ + messageID: string + } + query?: { + directory?: string + workspace?: string + } + url: "/session/{sessionID}/message/{messageID}" +} + +export type SessionDeleteMessageErrors = { + /** + * Bad request + */ + 400: BadRequestError + /** + * Not found + */ + 404: NotFoundError +} + +export type SessionDeleteMessageError = SessionDeleteMessageErrors[keyof SessionDeleteMessageErrors] + +export type SessionDeleteMessageResponses = { + /** + * Successfully deleted message + */ + 200: boolean +} + +export type SessionDeleteMessageResponse = SessionDeleteMessageResponses[keyof SessionDeleteMessageResponses] + export type SessionMessageData = { body?: never path: { @@ -3578,6 +3382,7 @@ export type SessionMessageData = { } query?: { directory?: string + workspace?: string } url: "/session/{sessionID}/message/{messageID}" } @@ -3625,6 +3430,7 @@ export type PartDeleteData = { } query?: { directory?: string + workspace?: string } url: "/session/{sessionID}/message/{messageID}/part/{partID}" } @@ -3669,6 +3475,7 @@ export type PartUpdateData = { } query?: { directory?: string + workspace?: string } url: "/session/{sessionID}/message/{messageID}/part/{partID}" } @@ -3723,6 +3530,7 @@ export type SessionPromptAsyncData = { } query?: { directory?: string + workspace?: string } url: "/session/{sessionID}/prompt_async" } @@ -3774,6 +3582,7 @@ export type SessionCommandData = { } query?: { directory?: string + workspace?: string } url: "/session/{sessionID}/command" } @@ -3820,6 +3629,7 @@ export type SessionShellData = { } query?: { directory?: string + workspace?: string } url: "/session/{sessionID}/shell" } @@ -3856,6 +3666,7 @@ export type SessionRevertData = { } query?: { directory?: string + workspace?: string } url: "/session/{sessionID}/revert" } @@ -3889,6 +3700,7 @@ export type SessionUnrevertData = { } query?: { directory?: string + workspace?: string } url: "/session/{sessionID}/unrevert" } @@ -3925,6 +3737,7 @@ export type PermissionRespondData = { } query?: { directory?: string + workspace?: string } url: "/session/{sessionID}/permissions/{permissionID}" } @@ -3961,6 +3774,7 @@ export type PermissionReplyData = { } query?: { directory?: string + workspace?: string } url: "/permission/{requestID}/reply" } @@ -3992,6 +3806,7 @@ export type PermissionListData = { path?: never query?: { directory?: string + workspace?: string } url: "/permission" } @@ -4010,6 +3825,7 @@ export type QuestionListData = { path?: never query?: { directory?: string + workspace?: string } url: "/question" } @@ -4035,6 +3851,7 @@ export type QuestionReplyData = { } query?: { directory?: string + workspace?: string } url: "/question/{requestID}/reply" } @@ -4068,6 +3885,7 @@ export type QuestionRejectData = { } query?: { directory?: string + workspace?: string } url: "/question/{requestID}/reject" } @@ -4099,6 +3917,7 @@ export type ProviderListData = { path?: never query?: { directory?: string + workspace?: string } url: "/provider" } @@ -4184,6 +4003,7 @@ export type ProviderAuthData = { path?: never query?: { directory?: string + workspace?: string } url: "/provider/auth" } @@ -4214,6 +4034,7 @@ export type ProviderOauthAuthorizeData = { } query?: { directory?: string + workspace?: string } url: "/provider/{providerID}/oauth/authorize" } @@ -4255,6 +4076,7 @@ export type ProviderOauthCallbackData = { } query?: { directory?: string + workspace?: string } url: "/provider/{providerID}/oauth/callback" } @@ -4282,6 +4104,7 @@ export type FindTextData = { path?: never query: { directory?: string + workspace?: string pattern: string } url: "/find" @@ -4317,6 +4140,7 @@ export type FindFilesData = { path?: never query: { directory?: string + workspace?: string query: string dirs?: "true" | "false" type?: "file" | "directory" @@ -4339,6 +4163,7 @@ export type FindSymbolsData = { path?: never query: { directory?: string + workspace?: string query: string } url: "/find/symbol" @@ -4358,6 +4183,7 @@ export type FileListData = { path?: never query: { directory?: string + workspace?: string path: string } url: "/file" @@ -4377,6 +4203,7 @@ export type FileReadData = { path?: never query: { directory?: string + workspace?: string path: string } url: "/file/content" @@ -4396,6 +4223,7 @@ export type FileStatusData = { path?: never query?: { directory?: string + workspace?: string } url: "/file/status" } @@ -4414,6 +4242,7 @@ export type McpStatusData = { path?: never query?: { directory?: string + workspace?: string } url: "/mcp" } @@ -4437,6 +4266,7 @@ export type McpAddData = { path?: never query?: { directory?: string + workspace?: string } url: "/mcp" } @@ -4468,6 +4298,7 @@ export type McpAuthRemoveData = { } query?: { directory?: string + workspace?: string } url: "/mcp/{name}/auth" } @@ -4499,6 +4330,7 @@ export type McpAuthStartData = { } query?: { directory?: string + workspace?: string } url: "/mcp/{name}/auth" } @@ -4542,6 +4374,7 @@ export type McpAuthCallbackData = { } query?: { directory?: string + workspace?: string } url: "/mcp/{name}/auth/callback" } @@ -4575,6 +4408,7 @@ export type McpAuthAuthenticateData = { } query?: { directory?: string + workspace?: string } url: "/mcp/{name}/auth/authenticate" } @@ -4608,6 +4442,7 @@ export type McpConnectData = { } query?: { directory?: string + workspace?: string } url: "/mcp/{name}/connect" } @@ -4628,6 +4463,7 @@ export type McpDisconnectData = { } query?: { directory?: string + workspace?: string } url: "/mcp/{name}/disconnect" } @@ -4648,6 +4484,7 @@ export type TuiAppendPromptData = { path?: never query?: { directory?: string + workspace?: string } url: "/tui/append-prompt" } @@ -4675,6 +4512,7 @@ export type TuiOpenHelpData = { path?: never query?: { directory?: string + workspace?: string } url: "/tui/open-help" } @@ -4693,6 +4531,7 @@ export type TuiOpenSessionsData = { path?: never query?: { directory?: string + workspace?: string } url: "/tui/open-sessions" } @@ -4711,6 +4550,7 @@ export type TuiOpenThemesData = { path?: never query?: { directory?: string + workspace?: string } url: "/tui/open-themes" } @@ -4729,6 +4569,7 @@ export type TuiOpenModelsData = { path?: never query?: { directory?: string + workspace?: string } url: "/tui/open-models" } @@ -4747,6 +4588,7 @@ export type TuiSubmitPromptData = { path?: never query?: { directory?: string + workspace?: string } url: "/tui/submit-prompt" } @@ -4765,6 +4607,7 @@ export type TuiClearPromptData = { path?: never query?: { directory?: string + workspace?: string } url: "/tui/clear-prompt" } @@ -4785,6 +4628,7 @@ export type TuiExecuteCommandData = { path?: never query?: { directory?: string + workspace?: string } url: "/tui/execute-command" } @@ -4820,6 +4664,7 @@ export type TuiShowToastData = { path?: never query?: { directory?: string + workspace?: string } url: "/tui/show-toast" } @@ -4838,6 +4683,7 @@ export type TuiPublishData = { path?: never query?: { directory?: string + workspace?: string } url: "/tui/publish" } @@ -4870,6 +4716,7 @@ export type TuiSelectSessionData = { path?: never query?: { directory?: string + workspace?: string } url: "/tui/select-session" } @@ -4901,6 +4748,7 @@ export type TuiControlNextData = { path?: never query?: { directory?: string + workspace?: string } url: "/tui/control/next" } @@ -4922,6 +4770,7 @@ export type TuiControlResponseData = { path?: never query?: { directory?: string + workspace?: string } url: "/tui/control/response" } @@ -4940,6 +4789,7 @@ export type InstanceDisposeData = { path?: never query?: { directory?: string + workspace?: string } url: "/instance/dispose" } @@ -4958,6 +4808,7 @@ export type PathGetData = { path?: never query?: { directory?: string + workspace?: string } url: "/path" } @@ -4976,6 +4827,7 @@ export type VcsGetData = { path?: never query?: { directory?: string + workspace?: string } url: "/vcs" } @@ -4994,6 +4846,7 @@ export type CommandListData = { path?: never query?: { directory?: string + workspace?: string } url: "/command" } @@ -5031,6 +4884,7 @@ export type AppLogData = { path?: never query?: { directory?: string + workspace?: string } url: "/log" } @@ -5058,6 +4912,7 @@ export type AppAgentsData = { path?: never query?: { directory?: string + workspace?: string } url: "/agent" } @@ -5076,6 +4931,7 @@ export type AppSkillsData = { path?: never query?: { directory?: string + workspace?: string } url: "/skill" } @@ -5099,6 +4955,7 @@ export type LspStatusData = { path?: never query?: { directory?: string + workspace?: string } url: "/lsp" } @@ -5117,6 +4974,7 @@ export type FormatterStatusData = { path?: never query?: { directory?: string + workspace?: string } url: "/formatter" } @@ -5135,6 +4993,7 @@ export type EventSubscribeData = { path?: never query?: { directory?: string + workspace?: string } url: "/event" } diff --git a/packages/sdk/openapi.json b/packages/sdk/openapi.json index 2741c2362e..d1198c11dd 100644 --- a/packages/sdk/openapi.json +++ b/packages/sdk/openapi.json @@ -265,6 +265,13 @@ "schema": { "type": "string" } + }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } } ], "summary": "List all projects", @@ -302,6 +309,13 @@ "schema": { "type": "string" } + }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } } ], "summary": "Get current project", @@ -326,6 +340,47 @@ ] } }, + "/project/git/init": { + "post": { + "operationId": "project.initGit", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } + } + ], + "summary": "Initialize git repository", + "description": "Create a git repository for the current project and return the refreshed project info.", + "responses": { + "200": { + "description": "Project information after git initialization", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Project" + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.project.initGit({\n ...\n})" + } + ] + } + }, "/project/{projectID}": { "patch": { "operationId": "project.update", @@ -337,6 +392,13 @@ "type": "string" } }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } + }, { "in": "path", "name": "projectID", @@ -435,6 +497,13 @@ "schema": { "type": "string" } + }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } } ], "summary": "List PTY sessions", @@ -470,6 +539,13 @@ "schema": { "type": "string" } + }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } } ], "summary": "Create PTY session", @@ -550,6 +626,13 @@ "type": "string" } }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } + }, { "in": "path", "name": "ptyID", @@ -600,6 +683,13 @@ "type": "string" } }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } + }, { "in": "path", "name": "ptyID", @@ -676,6 +766,13 @@ "type": "string" } }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } + }, { "in": "path", "name": "ptyID", @@ -728,6 +825,13 @@ "type": "string" } }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } + }, { "in": "path", "name": "ptyID", @@ -779,6 +883,13 @@ "schema": { "type": "string" } + }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } } ], "summary": "Get configuration", @@ -811,6 +922,13 @@ "schema": { "type": "string" } + }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } } ], "summary": "Update configuration", @@ -864,6 +982,13 @@ "schema": { "type": "string" } + }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } } ], "summary": "List config providers", @@ -916,6 +1041,13 @@ "schema": { "type": "string" } + }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } } ], "summary": "List tool IDs", @@ -961,6 +1093,13 @@ "type": "string" } }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } + }, { "in": "query", "name": "provider", @@ -1010,6 +1149,196 @@ ] } }, + "/experimental/workspace": { + "post": { + "operationId": "experimental.workspace.create", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } + } + ], + "summary": "Create workspace", + "description": "Create a workspace for the current project.", + "responses": { + "200": { + "description": "Workspace created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Workspace" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestError" + } + } + } + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string", + "pattern": "^wrk.*" + }, + "type": { + "type": "string" + }, + "branch": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "extra": { + "anyOf": [ + {}, + { + "type": "null" + } + ] + } + }, + "required": ["type", "branch", "extra"] + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.experimental.workspace.create({\n ...\n})" + } + ] + }, + "get": { + "operationId": "experimental.workspace.list", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } + } + ], + "summary": "List workspaces", + "description": "List all workspaces.", + "responses": { + "200": { + "description": "Workspaces", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Workspace" + } + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.experimental.workspace.list({\n ...\n})" + } + ] + } + }, + "/experimental/workspace/{id}": { + "delete": { + "operationId": "experimental.workspace.remove", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "id", + "schema": { + "type": "string", + "pattern": "^wrk.*" + }, + "required": true + } + ], + "summary": "Remove workspace", + "description": "Remove an existing workspace.", + "responses": { + "200": { + "description": "Workspace removed", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Workspace" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestError" + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.experimental.workspace.remove({\n ...\n})" + } + ] + } + }, "/experimental/worktree": { "post": { "operationId": "worktree.create", @@ -1020,6 +1349,13 @@ "schema": { "type": "string" } + }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } } ], "summary": "Create worktree", @@ -1071,6 +1407,13 @@ "schema": { "type": "string" } + }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } } ], "summary": "List worktrees", @@ -1106,6 +1449,13 @@ "schema": { "type": "string" } + }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } } ], "summary": "Remove worktree", @@ -1159,6 +1509,13 @@ "schema": { "type": "string" } + }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } } ], "summary": "Reset worktree", @@ -1214,6 +1571,13 @@ }, "description": "Filter sessions by project directory" }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } + }, { "in": "query", "name": "roots", @@ -1298,6 +1662,13 @@ "schema": { "type": "string" } + }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } } ], "summary": "Get MCP resources", @@ -1340,6 +1711,13 @@ }, "description": "Filter sessions by project directory" }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } + }, { "in": "query", "name": "roots", @@ -1406,6 +1784,13 @@ "schema": { "type": "string" } + }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } } ], "summary": "Create session", @@ -1471,6 +1856,13 @@ "schema": { "type": "string" } + }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } } ], "summary": "Get session status", @@ -1522,6 +1914,13 @@ "type": "string" } }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } + }, { "in": "path", "name": "sessionID", @@ -1584,6 +1983,13 @@ "type": "string" } }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } + }, { "in": "path", "name": "sessionID", @@ -1645,6 +2051,13 @@ "type": "string" } }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } + }, { "in": "path", "name": "sessionID", @@ -1729,6 +2142,13 @@ "type": "string" } }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } + }, { "in": "path", "name": "sessionID", @@ -1796,6 +2216,13 @@ "type": "string" } }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } + }, { "in": "path", "name": "sessionID", @@ -1862,6 +2289,13 @@ "type": "string" } }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } + }, { "in": "path", "name": "sessionID", @@ -1947,6 +2381,13 @@ "type": "string" } }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } + }, { "in": "path", "name": "sessionID", @@ -2005,6 +2446,13 @@ "type": "string" } }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } + }, { "in": "path", "name": "sessionID", @@ -2067,6 +2515,13 @@ "type": "string" } }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } + }, { "in": "path", "name": "sessionID", @@ -2127,6 +2582,13 @@ "type": "string" } }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } + }, { "in": "path", "name": "sessionID", @@ -2190,6 +2652,13 @@ "type": "string" } }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } + }, { "in": "path", "name": "sessionID", @@ -2244,6 +2713,13 @@ "type": "string" } }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } + }, { "in": "path", "name": "sessionID", @@ -2329,6 +2805,13 @@ "type": "string" } }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } + }, { "in": "path", "name": "sessionID", @@ -2412,6 +2895,13 @@ "type": "string" } }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } + }, { "in": "path", "name": "sessionID", @@ -2559,6 +3049,13 @@ "type": "string" } }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } + }, { "in": "path", "name": "sessionID", @@ -2630,6 +3127,83 @@ "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.session.message({\n ...\n})" } ] + }, + "delete": { + "operationId": "session.deleteMessage", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "sessionID", + "schema": { + "type": "string" + }, + "required": true, + "description": "Session ID" + }, + { + "in": "path", + "name": "messageID", + "schema": { + "type": "string" + }, + "required": true, + "description": "Message ID" + } + ], + "summary": "Delete message", + "description": "Permanently delete a specific message (and all of its parts) from a session. This does not revert any file changes that may have been made while processing the message.", + "responses": { + "200": { + "description": "Successfully deleted message", + "content": { + "application/json": { + "schema": { + "type": "boolean" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestError" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotFoundError" + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.session.deleteMessage({\n ...\n})" + } + ] } }, "/session/{sessionID}/message/{messageID}/part/{partID}": { @@ -2643,6 +3217,13 @@ "type": "string" } }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } + }, { "in": "path", "name": "sessionID", @@ -2721,6 +3302,13 @@ "type": "string" } }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } + }, { "in": "path", "name": "sessionID", @@ -2810,6 +3398,13 @@ "type": "string" } }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } + }, { "in": "path", "name": "sessionID", @@ -2938,6 +3533,13 @@ "type": "string" } }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } + }, { "in": "path", "name": "sessionID", @@ -3076,6 +3678,13 @@ "type": "string" } }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } + }, { "in": "path", "name": "sessionID", @@ -3169,6 +3778,13 @@ "type": "string" } }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } + }, { "in": "path", "name": "sessionID", @@ -3251,6 +3867,13 @@ "type": "string" } }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } + }, { "in": "path", "name": "sessionID", @@ -3313,6 +3936,13 @@ "type": "string" } }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } + }, { "in": "path", "name": "sessionID", @@ -3400,6 +4030,13 @@ "type": "string" } }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } + }, { "in": "path", "name": "requestID", @@ -3480,6 +4117,13 @@ "schema": { "type": "string" } + }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } } ], "summary": "List pending permissions", @@ -3517,6 +4161,13 @@ "schema": { "type": "string" } + }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } } ], "summary": "List pending questions", @@ -3555,6 +4206,13 @@ "type": "string" } }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } + }, { "in": "path", "name": "requestID", @@ -3636,6 +4294,13 @@ "type": "string" } }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } + }, { "in": "path", "name": "requestID", @@ -3697,6 +4362,13 @@ "schema": { "type": "string" } + }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } } ], "summary": "List providers", @@ -3959,6 +4631,13 @@ "schema": { "type": "string" } + }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } } ], "summary": "Get provider auth methods", @@ -4003,6 +4682,13 @@ "type": "string" } }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } + }, { "in": "path", "name": "providerID", @@ -4072,6 +4758,13 @@ "type": "string" } }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } + }, { "in": "path", "name": "providerID", @@ -4145,6 +4838,13 @@ "type": "string" } }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } + }, { "in": "query", "name": "pattern", @@ -4241,6 +4941,13 @@ "type": "string" } }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } + }, { "in": "query", "name": "query", @@ -4311,6 +5018,13 @@ "type": "string" } }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } + }, { "in": "query", "name": "query", @@ -4356,6 +5070,13 @@ "type": "string" } }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } + }, { "in": "query", "name": "path", @@ -4401,6 +5122,13 @@ "type": "string" } }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } + }, { "in": "query", "name": "path", @@ -4442,6 +5170,13 @@ "schema": { "type": "string" } + }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } } ], "summary": "Get file status", @@ -4479,6 +5214,13 @@ "schema": { "type": "string" } + }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } } ], "summary": "Get MCP status", @@ -4517,6 +5259,13 @@ "schema": { "type": "string" } + }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } } ], "summary": "Add MCP server", @@ -4593,6 +5342,13 @@ "type": "string" } }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } + }, { "schema": { "type": "string" @@ -4660,6 +5416,13 @@ "type": "string" } }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } + }, { "schema": { "type": "string" @@ -4719,6 +5482,13 @@ "type": "string" } }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } + }, { "schema": { "type": "string" @@ -4797,6 +5567,13 @@ "type": "string" } }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } + }, { "schema": { "type": "string" @@ -4859,6 +5636,13 @@ "type": "string" } }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } + }, { "in": "path", "name": "name", @@ -4900,6 +5684,13 @@ "type": "string" } }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } + }, { "in": "path", "name": "name", @@ -4940,6 +5731,13 @@ "schema": { "type": "string" } + }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } } ], "summary": "Append TUI prompt", @@ -4999,6 +5797,13 @@ "schema": { "type": "string" } + }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } } ], "summary": "Open help dialog", @@ -5033,6 +5838,13 @@ "schema": { "type": "string" } + }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } } ], "summary": "Open sessions dialog", @@ -5067,6 +5879,13 @@ "schema": { "type": "string" } + }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } } ], "summary": "Open themes dialog", @@ -5101,6 +5920,13 @@ "schema": { "type": "string" } + }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } } ], "summary": "Open models dialog", @@ -5135,6 +5961,13 @@ "schema": { "type": "string" } + }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } } ], "summary": "Submit TUI prompt", @@ -5169,6 +6002,13 @@ "schema": { "type": "string" } + }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } } ], "summary": "Clear TUI prompt", @@ -5203,6 +6043,13 @@ "schema": { "type": "string" } + }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } } ], "summary": "Execute TUI command", @@ -5262,6 +6109,13 @@ "schema": { "type": "string" } + }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } } ], "summary": "Show TUI toast", @@ -5323,6 +6177,13 @@ "schema": { "type": "string" } + }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } } ], "summary": "Publish TUI event", @@ -5389,6 +6250,13 @@ "schema": { "type": "string" } + }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } } ], "summary": "Select session", @@ -5460,6 +6328,13 @@ "schema": { "type": "string" } + }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } } ], "summary": "Get next TUI request", @@ -5501,6 +6376,13 @@ "schema": { "type": "string" } + }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } } ], "summary": "Submit TUI response", @@ -5542,6 +6424,13 @@ "schema": { "type": "string" } + }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } } ], "summary": "Dispose instance", @@ -5576,6 +6465,13 @@ "schema": { "type": "string" } + }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } } ], "summary": "Get paths", @@ -5610,6 +6506,13 @@ "schema": { "type": "string" } + }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } } ], "summary": "Get VCS info", @@ -5644,6 +6547,13 @@ "schema": { "type": "string" } + }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } } ], "summary": "List commands", @@ -5681,6 +6591,13 @@ "schema": { "type": "string" } + }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } } ], "summary": "Write log", @@ -5758,6 +6675,13 @@ "schema": { "type": "string" } + }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } } ], "summary": "List agents", @@ -5795,6 +6719,13 @@ "schema": { "type": "string" } + }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } } ], "summary": "List skills", @@ -5847,6 +6778,13 @@ "schema": { "type": "string" } + }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } } ], "summary": "Get LSP status", @@ -5884,6 +6822,13 @@ "schema": { "type": "string" } + }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } } ], "summary": "Get formatter status", @@ -5921,6 +6866,13 @@ "schema": { "type": "string" } + }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } } ], "summary": "Subscribe to events", @@ -7368,6 +8320,9 @@ }, "auto": { "type": "boolean" + }, + "overflow": { + "type": "boolean" } }, "required": ["id", "sessionID", "messageID", "type", "auto"] @@ -8124,6 +9079,9 @@ "projectID": { "type": "string" }, + "workspaceID": { + "type": "string" + }, "directory": { "type": "string" }, @@ -8352,6 +9310,44 @@ }, "required": ["type", "properties"] }, + "Event.workspace.ready": { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "workspace.ready" + }, + "properties": { + "type": "object", + "properties": { + "name": { + "type": "string" + } + }, + "required": ["name"] + } + }, + "required": ["type", "properties"] + }, + "Event.workspace.failed": { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "workspace.failed" + }, + "properties": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + }, + "required": ["message"] + } + }, + "required": ["type", "properties"] + }, "Pty": { "type": "object", "properties": { @@ -8619,6 +9615,12 @@ { "$ref": "#/components/schemas/Event.vcs.branch.updated" }, + { + "$ref": "#/components/schemas/Event.workspace.ready" + }, + { + "$ref": "#/components/schemas/Event.workspace.failed" + }, { "$ref": "#/components/schemas/Event.pty.created" }, @@ -8651,483 +9653,6 @@ }, "required": ["directory", "payload"] }, - "KeybindsConfig": { - "description": "Custom keybind configurations", - "type": "object", - "properties": { - "leader": { - "description": "Leader key for keybind combinations", - "default": "ctrl+x", - "type": "string" - }, - "app_exit": { - "description": "Exit the application", - "default": "ctrl+c,ctrl+d,<leader>q", - "type": "string" - }, - "editor_open": { - "description": "Open external editor", - "default": "<leader>e", - "type": "string" - }, - "theme_list": { - "description": "List available themes", - "default": "<leader>t", - "type": "string" - }, - "sidebar_toggle": { - "description": "Toggle sidebar", - "default": "<leader>b", - "type": "string" - }, - "scrollbar_toggle": { - "description": "Toggle session scrollbar", - "default": "none", - "type": "string" - }, - "username_toggle": { - "description": "Toggle username visibility", - "default": "none", - "type": "string" - }, - "status_view": { - "description": "View status", - "default": "<leader>s", - "type": "string" - }, - "session_export": { - "description": "Export session to editor", - "default": "<leader>x", - "type": "string" - }, - "session_new": { - "description": "Create a new session", - "default": "<leader>n", - "type": "string" - }, - "session_list": { - "description": "List all sessions", - "default": "<leader>l", - "type": "string" - }, - "session_timeline": { - "description": "Show session timeline", - "default": "<leader>g", - "type": "string" - }, - "session_fork": { - "description": "Fork session from message", - "default": "none", - "type": "string" - }, - "session_rename": { - "description": "Rename session", - "default": "ctrl+r", - "type": "string" - }, - "session_delete": { - "description": "Delete session", - "default": "ctrl+d", - "type": "string" - }, - "stash_delete": { - "description": "Delete stash entry", - "default": "ctrl+d", - "type": "string" - }, - "model_provider_list": { - "description": "Open provider list from model dialog", - "default": "ctrl+a", - "type": "string" - }, - "model_favorite_toggle": { - "description": "Toggle model favorite status", - "default": "ctrl+f", - "type": "string" - }, - "session_share": { - "description": "Share current session", - "default": "none", - "type": "string" - }, - "session_unshare": { - "description": "Unshare current session", - "default": "none", - "type": "string" - }, - "session_interrupt": { - "description": "Interrupt current session", - "default": "escape", - "type": "string" - }, - "session_compact": { - "description": "Compact the session", - "default": "<leader>c", - "type": "string" - }, - "messages_page_up": { - "description": "Scroll messages up by one page", - "default": "pageup,ctrl+alt+b", - "type": "string" - }, - "messages_page_down": { - "description": "Scroll messages down by one page", - "default": "pagedown,ctrl+alt+f", - "type": "string" - }, - "messages_line_up": { - "description": "Scroll messages up by one line", - "default": "ctrl+alt+y", - "type": "string" - }, - "messages_line_down": { - "description": "Scroll messages down by one line", - "default": "ctrl+alt+e", - "type": "string" - }, - "messages_half_page_up": { - "description": "Scroll messages up by half page", - "default": "ctrl+alt+u", - "type": "string" - }, - "messages_half_page_down": { - "description": "Scroll messages down by half page", - "default": "ctrl+alt+d", - "type": "string" - }, - "messages_first": { - "description": "Navigate to first message", - "default": "ctrl+g,home", - "type": "string" - }, - "messages_last": { - "description": "Navigate to last message", - "default": "ctrl+alt+g,end", - "type": "string" - }, - "messages_next": { - "description": "Navigate to next message", - "default": "none", - "type": "string" - }, - "messages_previous": { - "description": "Navigate to previous message", - "default": "none", - "type": "string" - }, - "messages_last_user": { - "description": "Navigate to last user message", - "default": "none", - "type": "string" - }, - "messages_copy": { - "description": "Copy message", - "default": "<leader>y", - "type": "string" - }, - "messages_undo": { - "description": "Undo message", - "default": "<leader>u", - "type": "string" - }, - "messages_redo": { - "description": "Redo message", - "default": "<leader>r", - "type": "string" - }, - "messages_toggle_conceal": { - "description": "Toggle code block concealment in messages", - "default": "<leader>h", - "type": "string" - }, - "tool_details": { - "description": "Toggle tool details visibility", - "default": "none", - "type": "string" - }, - "model_list": { - "description": "List available models", - "default": "<leader>m", - "type": "string" - }, - "model_cycle_recent": { - "description": "Next recently used model", - "default": "f2", - "type": "string" - }, - "model_cycle_recent_reverse": { - "description": "Previous recently used model", - "default": "shift+f2", - "type": "string" - }, - "model_cycle_favorite": { - "description": "Next favorite model", - "default": "none", - "type": "string" - }, - "model_cycle_favorite_reverse": { - "description": "Previous favorite model", - "default": "none", - "type": "string" - }, - "command_list": { - "description": "List available commands", - "default": "ctrl+p", - "type": "string" - }, - "agent_list": { - "description": "List agents", - "default": "<leader>a", - "type": "string" - }, - "agent_cycle": { - "description": "Next agent", - "default": "tab", - "type": "string" - }, - "agent_cycle_reverse": { - "description": "Previous agent", - "default": "shift+tab", - "type": "string" - }, - "variant_cycle": { - "description": "Cycle model variants", - "default": "ctrl+t", - "type": "string" - }, - "input_clear": { - "description": "Clear input field", - "default": "ctrl+c", - "type": "string" - }, - "input_paste": { - "description": "Paste from clipboard", - "default": "ctrl+v", - "type": "string" - }, - "input_submit": { - "description": "Submit input", - "default": "return", - "type": "string" - }, - "input_newline": { - "description": "Insert newline in input", - "default": "shift+return,ctrl+return,alt+return,ctrl+j", - "type": "string" - }, - "input_move_left": { - "description": "Move cursor left in input", - "default": "left,ctrl+b", - "type": "string" - }, - "input_move_right": { - "description": "Move cursor right in input", - "default": "right,ctrl+f", - "type": "string" - }, - "input_move_up": { - "description": "Move cursor up in input", - "default": "up", - "type": "string" - }, - "input_move_down": { - "description": "Move cursor down in input", - "default": "down", - "type": "string" - }, - "input_select_left": { - "description": "Select left in input", - "default": "shift+left", - "type": "string" - }, - "input_select_right": { - "description": "Select right in input", - "default": "shift+right", - "type": "string" - }, - "input_select_up": { - "description": "Select up in input", - "default": "shift+up", - "type": "string" - }, - "input_select_down": { - "description": "Select down in input", - "default": "shift+down", - "type": "string" - }, - "input_line_home": { - "description": "Move to start of line in input", - "default": "ctrl+a", - "type": "string" - }, - "input_line_end": { - "description": "Move to end of line in input", - "default": "ctrl+e", - "type": "string" - }, - "input_select_line_home": { - "description": "Select to start of line in input", - "default": "ctrl+shift+a", - "type": "string" - }, - "input_select_line_end": { - "description": "Select to end of line in input", - "default": "ctrl+shift+e", - "type": "string" - }, - "input_visual_line_home": { - "description": "Move to start of visual line in input", - "default": "alt+a", - "type": "string" - }, - "input_visual_line_end": { - "description": "Move to end of visual line in input", - "default": "alt+e", - "type": "string" - }, - "input_select_visual_line_home": { - "description": "Select to start of visual line in input", - "default": "alt+shift+a", - "type": "string" - }, - "input_select_visual_line_end": { - "description": "Select to end of visual line in input", - "default": "alt+shift+e", - "type": "string" - }, - "input_buffer_home": { - "description": "Move to start of buffer in input", - "default": "home", - "type": "string" - }, - "input_buffer_end": { - "description": "Move to end of buffer in input", - "default": "end", - "type": "string" - }, - "input_select_buffer_home": { - "description": "Select to start of buffer in input", - "default": "shift+home", - "type": "string" - }, - "input_select_buffer_end": { - "description": "Select to end of buffer in input", - "default": "shift+end", - "type": "string" - }, - "input_delete_line": { - "description": "Delete line in input", - "default": "ctrl+shift+d", - "type": "string" - }, - "input_delete_to_line_end": { - "description": "Delete to end of line in input", - "default": "ctrl+k", - "type": "string" - }, - "input_delete_to_line_start": { - "description": "Delete to start of line in input", - "default": "ctrl+u", - "type": "string" - }, - "input_backspace": { - "description": "Backspace in input", - "default": "backspace,shift+backspace", - "type": "string" - }, - "input_delete": { - "description": "Delete character in input", - "default": "ctrl+d,delete,shift+delete", - "type": "string" - }, - "input_undo": { - "description": "Undo in input", - "default": "ctrl+-,super+z", - "type": "string" - }, - "input_redo": { - "description": "Redo in input", - "default": "ctrl+.,super+shift+z", - "type": "string" - }, - "input_word_forward": { - "description": "Move word forward in input", - "default": "alt+f,alt+right,ctrl+right", - "type": "string" - }, - "input_word_backward": { - "description": "Move word backward in input", - "default": "alt+b,alt+left,ctrl+left", - "type": "string" - }, - "input_select_word_forward": { - "description": "Select word forward in input", - "default": "alt+shift+f,alt+shift+right", - "type": "string" - }, - "input_select_word_backward": { - "description": "Select word backward in input", - "default": "alt+shift+b,alt+shift+left", - "type": "string" - }, - "input_delete_word_forward": { - "description": "Delete word forward in input", - "default": "alt+d,alt+delete,ctrl+delete", - "type": "string" - }, - "input_delete_word_backward": { - "description": "Delete word backward in input", - "default": "ctrl+w,ctrl+backspace,alt+backspace", - "type": "string" - }, - "history_previous": { - "description": "Previous history item", - "default": "up", - "type": "string" - }, - "history_next": { - "description": "Next history item", - "default": "down", - "type": "string" - }, - "session_child_cycle": { - "description": "Next child session", - "default": "<leader>right", - "type": "string" - }, - "session_child_cycle_reverse": { - "description": "Previous child session", - "default": "<leader>left", - "type": "string" - }, - "session_parent": { - "description": "Go to parent session", - "default": "<leader>up", - "type": "string" - }, - "terminal_suspend": { - "description": "Suspend terminal", - "default": "ctrl+z", - "type": "string" - }, - "terminal_title_toggle": { - "description": "Toggle terminal title", - "default": "none", - "type": "string" - }, - "tips_toggle": { - "description": "Toggle tips on home screen", - "default": "<leader>h", - "type": "string" - }, - "display_thinking": { - "description": "Toggle thinking blocks visibility", - "default": "none", - "type": "string" - } - }, - "additionalProperties": false - }, "LogLevel": { "description": "Log level", "type": "string", @@ -9707,43 +10232,9 @@ "description": "JSON schema reference for configuration validation", "type": "string" }, - "theme": { - "description": "Theme name to use for the interface", - "type": "string" - }, - "keybinds": { - "$ref": "#/components/schemas/KeybindsConfig" - }, "logLevel": { "$ref": "#/components/schemas/LogLevel" }, - "tui": { - "description": "TUI specific settings", - "type": "object", - "properties": { - "scroll_speed": { - "description": "TUI scroll speed", - "type": "number", - "minimum": 0.001 - }, - "scroll_acceleration": { - "description": "Scroll acceleration settings", - "type": "object", - "properties": { - "enabled": { - "description": "Enable scroll acceleration", - "type": "boolean" - } - }, - "required": ["enabled"] - }, - "diff_style": { - "description": "Control diff rendering style: 'auto' adapts to terminal width, 'stacked' always shows single column", - "type": "string", - "enum": ["auto", "stacked"] - } - } - }, "server": { "$ref": "#/components/schemas/ServerConfig" }, @@ -10540,6 +11031,60 @@ "$ref": "#/components/schemas/ToolListItem" } }, + "Workspace": { + "type": "object", + "properties": { + "id": { + "type": "string", + "pattern": "^wrk.*" + }, + "type": { + "type": "string" + }, + "branch": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "directory": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "extra": { + "anyOf": [ + {}, + { + "type": "null" + } + ] + }, + "projectID": { + "type": "string" + } + }, + "required": ["id", "type", "branch", "name", "directory", "extra", "projectID"] + }, "Worktree": { "type": "object", "properties": { @@ -10613,6 +11158,9 @@ "projectID": { "type": "string" }, + "workspaceID": { + "type": "string" + }, "directory": { "type": "string" }, diff --git a/packages/slack/package.json b/packages/slack/package.json index d000cb4799..4ed7386e8a 100644 --- a/packages/slack/package.json +++ b/packages/slack/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/slack", - "version": "1.2.10", + "version": "1.2.24", "type": "module", "license": "MIT", "scripts": { diff --git a/packages/storybook/.gitignore b/packages/storybook/.gitignore new file mode 100644 index 0000000000..b122737adf --- /dev/null +++ b/packages/storybook/.gitignore @@ -0,0 +1,3 @@ +node_modules/ +storybook-static/ +.storybook-cache/ diff --git a/packages/storybook/.storybook/main.ts b/packages/storybook/.storybook/main.ts new file mode 100644 index 0000000000..a6423530f6 --- /dev/null +++ b/packages/storybook/.storybook/main.ts @@ -0,0 +1,66 @@ +import { defineMain } from "storybook-solidjs-vite" +import path from "node:path" +import { fileURLToPath } from "node:url" +import tailwindcss from "@tailwindcss/vite" + +const here = path.dirname(fileURLToPath(import.meta.url)) +const ui = path.resolve(here, "../../ui") +const app = path.resolve(here, "../../app/src") +const mocks = path.resolve(here, "./mocks") + +export default defineMain({ + framework: { + name: "storybook-solidjs-vite", + options: {}, + }, + addons: [ + "@storybook/addon-onboarding", + "@storybook/addon-docs", + "@storybook/addon-links", + "@storybook/addon-a11y", + "@storybook/addon-vitest", + ], + stories: ["../../ui/src/**/*.stories.@(js|jsx|mjs|ts|tsx)"], + async viteFinal(config) { + const { mergeConfig, searchForWorkspaceRoot } = await import("vite") + return mergeConfig(config, { + plugins: [tailwindcss()], + resolve: { + dedupe: ["solid-js", "solid-js/web", "@solidjs/meta"], + alias: [ + { find: "@solidjs/router", replacement: path.resolve(mocks, "solid-router.tsx") }, + { find: /^@\/context\/local$/, replacement: path.resolve(mocks, "app/context/local.ts") }, + { find: /^@\/context\/file$/, replacement: path.resolve(mocks, "app/context/file.ts") }, + { find: /^@\/context\/prompt$/, replacement: path.resolve(mocks, "app/context/prompt.ts") }, + { find: /^@\/context\/layout$/, replacement: path.resolve(mocks, "app/context/layout.ts") }, + { find: /^@\/context\/sdk$/, replacement: path.resolve(mocks, "app/context/sdk.ts") }, + { find: /^@\/context\/sync$/, replacement: path.resolve(mocks, "app/context/sync.ts") }, + { find: /^@\/context\/comments$/, replacement: path.resolve(mocks, "app/context/comments.ts") }, + { find: /^@\/context\/command$/, replacement: path.resolve(mocks, "app/context/command.ts") }, + { find: /^@\/context\/permission$/, replacement: path.resolve(mocks, "app/context/permission.ts") }, + { find: /^@\/context\/language$/, replacement: path.resolve(mocks, "app/context/language.ts") }, + { find: /^@\/context\/platform$/, replacement: path.resolve(mocks, "app/context/platform.ts") }, + { find: /^@\/context\/global-sync$/, replacement: path.resolve(mocks, "app/context/global-sync.ts") }, + { find: /^@\/hooks\/use-providers$/, replacement: path.resolve(mocks, "app/hooks/use-providers.ts") }, + { + find: /^@\/components\/dialog-select-model$/, + replacement: path.resolve(mocks, "app/components/dialog-select-model.tsx"), + }, + { + find: /^@\/components\/dialog-select-model-unpaid$/, + replacement: path.resolve(mocks, "app/components/dialog-select-model-unpaid.tsx"), + }, + { find: "@", replacement: app }, + ], + }, + worker: { + format: "es", + }, + server: { + fs: { + allow: [searchForWorkspaceRoot(process.cwd()), ui, app, mocks], + }, + }, + }) + }, +}) diff --git a/packages/storybook/.storybook/manager.ts b/packages/storybook/.storybook/manager.ts new file mode 100644 index 0000000000..9af9ba0a82 --- /dev/null +++ b/packages/storybook/.storybook/manager.ts @@ -0,0 +1,11 @@ +import { addons, types } from "storybook/manager-api" +import { ThemeTool } from "./theme-tool" + +addons.register("opencode/theme-toggle", () => { + addons.add("opencode/theme-toggle/tool", { + type: types.TOOL, + title: "Theme", + match: ({ viewMode }) => viewMode === "story" || viewMode === "docs", + render: ThemeTool, + }) +}) diff --git a/packages/storybook/.storybook/mocks/app/components/dialog-select-model-unpaid.tsx b/packages/storybook/.storybook/mocks/app/components/dialog-select-model-unpaid.tsx new file mode 100644 index 0000000000..8496c59a71 --- /dev/null +++ b/packages/storybook/.storybook/mocks/app/components/dialog-select-model-unpaid.tsx @@ -0,0 +1,3 @@ +export function DialogSelectModelUnpaid() { + return <div data-component="dialog-select-model-unpaid">Select model</div> +} diff --git a/packages/storybook/.storybook/mocks/app/components/dialog-select-model.tsx b/packages/storybook/.storybook/mocks/app/components/dialog-select-model.tsx new file mode 100644 index 0000000000..584924f02f --- /dev/null +++ b/packages/storybook/.storybook/mocks/app/components/dialog-select-model.tsx @@ -0,0 +1,7 @@ +import { splitProps } from "solid-js" + +export function ModelSelectorPopover(props: { triggerAs: any; triggerProps?: Record<string, unknown>; children: any }) { + const [local] = splitProps(props, ["triggerAs", "triggerProps", "children"]) + const Trigger = local.triggerAs + return <Trigger {...(local.triggerProps ?? {})}>{local.children}</Trigger> +} diff --git a/packages/storybook/.storybook/mocks/app/context/command.ts b/packages/storybook/.storybook/mocks/app/context/command.ts new file mode 100644 index 0000000000..1aa0423d3c --- /dev/null +++ b/packages/storybook/.storybook/mocks/app/context/command.ts @@ -0,0 +1,22 @@ +const keybinds: Record<string, string> = { + "file.attach": "mod+u", + "prompt.mode.shell": "mod+shift+x", + "prompt.mode.normal": "mod+shift+e", + "permissions.autoaccept": "mod+shift+a", + "agent.cycle": "mod+.", + "model.choose": "mod+m", + "model.variant.cycle": "mod+shift+m", +} + +export function useCommand() { + return { + options: [], + register() { + return () => undefined + }, + trigger() {}, + keybind(id: string) { + return keybinds[id] + }, + } +} diff --git a/packages/storybook/.storybook/mocks/app/context/comments.ts b/packages/storybook/.storybook/mocks/app/context/comments.ts new file mode 100644 index 0000000000..6c01d203b8 --- /dev/null +++ b/packages/storybook/.storybook/mocks/app/context/comments.ts @@ -0,0 +1,34 @@ +import { createSignal } from "solid-js" + +type Comment = { + id: string + file: string + selection: { start: number; end: number } + comment: string + time: number +} + +const [list, setList] = createSignal<Comment[]>([]) +const [focus, setFocus] = createSignal<{ file: string; id: string } | null>(null) +const [active, setActive] = createSignal<{ file: string; id: string } | null>(null) + +export function useComments() { + return { + all: list, + replace(next: Comment[]) { + setList(next) + }, + remove(file: string, id: string) { + setList((current) => current.filter((item) => !(item.file === file && item.id === id))) + }, + clear() { + setList([]) + setFocus(null) + setActive(null) + }, + focus, + setFocus, + active, + setActive, + } +} diff --git a/packages/storybook/.storybook/mocks/app/context/file.ts b/packages/storybook/.storybook/mocks/app/context/file.ts new file mode 100644 index 0000000000..db2158a5cd --- /dev/null +++ b/packages/storybook/.storybook/mocks/app/context/file.ts @@ -0,0 +1,47 @@ +export type FileSelection = { + startLine: number + startChar: number + endLine: number + endChar: number +} + +export type SelectedLineRange = { + start: number + end: number +} + +export function selectionFromLines(selection?: SelectedLineRange): FileSelection | undefined { + if (!selection) return undefined + return { + startLine: selection.start, + startChar: 0, + endLine: selection.end, + endChar: 0, + } +} + +const pool = [ + "src/session/timeline.tsx", + "src/session/composer.tsx", + "src/components/prompt-input.tsx", + "src/components/session-todo-dock.tsx", + "README.md", +] + +export function useFile() { + return { + tab(path: string) { + return `file:${path}` + }, + pathFromTab(tab: string) { + if (!tab.startsWith("file:")) return "" + return tab.slice(5) + }, + load: async () => undefined, + async searchFilesAndDirectories(query: string) { + const text = query.trim().toLowerCase() + if (!text) return pool + return pool.filter((path) => path.toLowerCase().includes(text)) + }, + } +} diff --git a/packages/storybook/.storybook/mocks/app/context/global-sync.ts b/packages/storybook/.storybook/mocks/app/context/global-sync.ts new file mode 100644 index 0000000000..2eb134d37c --- /dev/null +++ b/packages/storybook/.storybook/mocks/app/context/global-sync.ts @@ -0,0 +1,42 @@ +import { createStore } from "solid-js/store" + +const provider = { + all: [ + { + id: "anthropic", + models: { + "claude-3-7-sonnet": { + id: "claude-3-7-sonnet", + name: "Claude 3.7 Sonnet", + cost: { input: 1, output: 1 }, + }, + }, + }, + ], + connected: ["anthropic"], + default: { anthropic: "claude-3-7-sonnet" }, +} + +const [store, setStore] = createStore({ + todo: {} as Record<string, any[]>, + provider, + session: [] as any[], + config: { permission: {} }, +}) + +export function useGlobalSync() { + return { + data: { + provider, + session_todo: store.todo, + }, + child() { + return [store, setStore] as const + }, + todo: { + set(sessionID: string, todos: any[]) { + setStore("todo", sessionID, todos) + }, + }, + } +} diff --git a/packages/storybook/.storybook/mocks/app/context/language.ts b/packages/storybook/.storybook/mocks/app/context/language.ts new file mode 100644 index 0000000000..8744655422 --- /dev/null +++ b/packages/storybook/.storybook/mocks/app/context/language.ts @@ -0,0 +1,74 @@ +const dict: Record<string, string> = { + "session.todo.title": "Todos", + "session.todo.collapse": "Collapse todos", + "session.todo.expand": "Expand todos", + "prompt.loading": "Loading prompt...", + "prompt.placeholder.normal": "Ask anything...", + "prompt.placeholder.simple": "Ask anything...", + "prompt.placeholder.shell": "Run a shell command...", + "prompt.placeholder.summarizeComment": "Summarize this comment", + "prompt.placeholder.summarizeComments": "Summarize these comments", + "prompt.action.attachFile": "Attach file", + "prompt.action.send": "Send", + "prompt.action.stop": "Stop", + "prompt.attachment.remove": "Remove attachment", + "prompt.dropzone.label": "Drop image to attach", + "prompt.dropzone.file.label": "Drop file to attach", + "prompt.mode.shell": "Shell", + "prompt.mode.normal": "Prompt", + "dialog.model.select.title": "Select model", + "common.default": "Default", + "common.key.esc": "Esc", + "command.category.file": "File", + "command.category.session": "Session", + "command.agent.cycle": "Cycle agent", + "command.model.choose": "Choose model", + "command.model.variant.cycle": "Cycle model variant", + "command.prompt.mode.shell": "Switch to shell mode", + "command.prompt.mode.normal": "Switch to prompt mode", + "command.permissions.autoaccept.enable": "Enable auto-accept", + "command.permissions.autoaccept.disable": "Disable auto-accept", + "prompt.example.1": "Refactor this function and keep behavior the same", + "prompt.example.2": "Find the root cause of this error", + "prompt.example.3": "Write tests for this module", + "prompt.example.4": "Explain this diff", + "prompt.example.5": "Optimize this query", + "prompt.example.6": "Clean up this component", + "prompt.example.7": "Summarize the recent changes", + "prompt.example.8": "Add accessibility checks", + "prompt.example.9": "Review this API design", + "prompt.example.10": "Generate migration notes", + "prompt.example.11": "Patch this bug", + "prompt.example.12": "Make this animation smoother", + "prompt.example.13": "Improve error handling", + "prompt.example.14": "Document this feature", + "prompt.example.15": "Refine these styles", + "prompt.example.16": "Check edge cases", + "prompt.example.17": "Help me write a commit message", + "prompt.example.18": "Reduce re-renders in this component", + "prompt.example.19": "Verify keyboard navigation", + "prompt.example.20": "Make this copy clearer", + "prompt.example.21": "Add telemetry for this flow", + "prompt.example.22": "Compare these two implementations", + "prompt.example.23": "Create a minimal reproduction", + "prompt.example.24": "Suggest naming improvements", + "prompt.example.25": "What should we test next?", +} + +function render(template: string, params?: Record<string, unknown>) { + if (!params) return template + return template.replace(/\{\{([^}]+)\}\}/g, (_, key: string) => { + const value = params[key.trim()] + if (value === undefined || value === null) return "" + return String(value) + }) +} + +export function useLanguage() { + return { + locale: () => "en" as const, + t(key: string, params?: Record<string, unknown>) { + return render(dict[key] ?? key, params) + }, + } +} diff --git a/packages/storybook/.storybook/mocks/app/context/layout.ts b/packages/storybook/.storybook/mocks/app/context/layout.ts new file mode 100644 index 0000000000..0c5d6e97c9 --- /dev/null +++ b/packages/storybook/.storybook/mocks/app/context/layout.ts @@ -0,0 +1,41 @@ +import { createSignal } from "solid-js" + +const [all, setAll] = createSignal<string[]>([]) +const [active, setActive] = createSignal<string | undefined>(undefined) +const [reviewOpen, setReviewOpen] = createSignal(false) + +const tabs = { + all, + active, + open(tab: string) { + setAll((current) => (current.includes(tab) ? current : [...current, tab])) + }, + setActive(tab: string) { + if (!all().includes(tab)) { + tabs.open(tab) + } + setActive(tab) + }, +} + +const view = { + reviewPanel: { + opened: reviewOpen, + open() { + setReviewOpen(true) + }, + }, +} + +export function useLayout() { + return { + tabs: () => tabs, + view: () => view, + fileTree: { + setTab() {}, + }, + handoff: { + setTabs() {}, + }, + } +} diff --git a/packages/storybook/.storybook/mocks/app/context/local.ts b/packages/storybook/.storybook/mocks/app/context/local.ts new file mode 100644 index 0000000000..d1f02e5bb3 --- /dev/null +++ b/packages/storybook/.storybook/mocks/app/context/local.ts @@ -0,0 +1,41 @@ +import { createSignal } from "solid-js" + +const model = { + id: "claude-3-7-sonnet", + name: "Claude 3.7 Sonnet", + provider: { id: "anthropic" }, + variants: { fast: {}, thinking: {} }, +} + +const agents = [{ name: "build" }, { name: "review" }, { name: "plan" }] + +const [agent, setAgent] = createSignal(agents[0].name) +const [variant, setVariant] = createSignal<string | undefined>(undefined) + +export function useLocal() { + return { + slug: () => "c3Rvcnk=", + agent: { + list: () => agents, + current: () => agents.find((item) => item.name === agent()) ?? agents[0], + set(value?: string) { + if (!value) { + setAgent(agents[0].name) + return + } + const hit = agents.find((item) => item.name === value) + setAgent(hit?.name ?? agents[0].name) + }, + }, + model: { + current: () => model, + variant: { + list: () => Object.keys(model.variants), + current: () => variant(), + set(next?: string) { + setVariant(next) + }, + }, + }, + } +} diff --git a/packages/storybook/.storybook/mocks/app/context/permission.ts b/packages/storybook/.storybook/mocks/app/context/permission.ts new file mode 100644 index 0000000000..b6fb37d96b --- /dev/null +++ b/packages/storybook/.storybook/mocks/app/context/permission.ts @@ -0,0 +1,24 @@ +const accepted = new Set<string>() + +function key(sessionID: string, directory?: string) { + return `${directory ?? ""}:${sessionID}` +} + +export function usePermission() { + return { + autoResponds() { + return false + }, + isAutoAccepting(sessionID: string, directory?: string) { + return accepted.has(key(sessionID, directory)) + }, + toggleAutoAccept(sessionID: string, directory?: string) { + const next = key(sessionID, directory) + if (accepted.has(next)) { + accepted.delete(next) + return + } + accepted.add(next) + }, + } +} diff --git a/packages/storybook/.storybook/mocks/app/context/platform.ts b/packages/storybook/.storybook/mocks/app/context/platform.ts new file mode 100644 index 0000000000..74233cd1e5 --- /dev/null +++ b/packages/storybook/.storybook/mocks/app/context/platform.ts @@ -0,0 +1,16 @@ +import type { Platform } from "../../../../../app/src/context/platform" + +const value: Platform = { + platform: "web", + openLink() {}, + restart: async () => {}, + back() {}, + forward() {}, + notify: async () => {}, + fetch: globalThis.fetch.bind(globalThis), + parseMarkdown: async (markdown: string) => markdown, +} + +export function usePlatform() { + return value +} diff --git a/packages/storybook/.storybook/mocks/app/context/prompt.ts b/packages/storybook/.storybook/mocks/app/context/prompt.ts new file mode 100644 index 0000000000..e5e0e5d335 --- /dev/null +++ b/packages/storybook/.storybook/mocks/app/context/prompt.ts @@ -0,0 +1,117 @@ +import { createSignal } from "solid-js" + +interface PartBase { + content: string + start: number + end: number +} + +export interface TextPart extends PartBase { + type: "text" +} + +export interface FileAttachmentPart extends PartBase { + type: "file" + path: string +} + +export interface AgentPart extends PartBase { + type: "agent" + name: string +} + +export interface ImageAttachmentPart { + type: "image" + id: string + filename: string + mime: string + dataUrl: string +} + +export type ContentPart = TextPart | FileAttachmentPart | AgentPart | ImageAttachmentPart +export type Prompt = ContentPart[] + +type ContextItem = { + key: string + type: "file" + path: string + selection?: { startLine: number; startChar: number; endLine: number; endChar: number } + comment?: string + commentID?: string + commentOrigin?: "review" | "file" + preview?: string +} + +export const DEFAULT_PROMPT: Prompt = [{ type: "text", content: "", start: 0, end: 0 }] + +function clonePart(part: ContentPart): ContentPart { + if (part.type === "image") return { ...part } + if (part.type === "agent") return { ...part } + if (part.type === "file") return { ...part } + return { ...part } +} + +function clonePrompt(prompt: Prompt) { + return prompt.map(clonePart) +} + +export function isPromptEqual(a: Prompt, b: Prompt) { + if (a.length !== b.length) return false + return a.every((part, i) => JSON.stringify(part) === JSON.stringify(b[i])) +} + +let index = 0 +const [prompt, setPrompt] = createSignal<Prompt>(clonePrompt(DEFAULT_PROMPT)) +const [cursor, setCursor] = createSignal<number>(0) +const [items, setItems] = createSignal<ContextItem[]>([]) + +const withKey = (item: Omit<ContextItem, "key"> & { key?: string }): ContextItem => ({ + ...item, + key: item.key ?? `ctx:${++index}`, +}) + +export function usePrompt() { + return { + ready: () => true, + current: prompt, + cursor, + dirty: () => !isPromptEqual(prompt(), DEFAULT_PROMPT), + set(next: Prompt, cursorPosition?: number) { + setPrompt(clonePrompt(next)) + if (cursorPosition !== undefined) setCursor(cursorPosition) + }, + reset() { + setPrompt(clonePrompt(DEFAULT_PROMPT)) + setCursor(0) + setItems((current) => current.filter((item) => !!item.comment?.trim())) + }, + context: { + items, + add(item: Omit<ContextItem, "key"> & { key?: string }) { + const next = withKey(item) + if (items().some((current) => current.key === next.key)) return + setItems((current) => [...current, next]) + }, + remove(key: string) { + setItems((current) => current.filter((item) => item.key !== key)) + }, + removeComment(path: string, commentID: string) { + setItems((current) => + current.filter((item) => !(item.type === "file" && item.path === path && item.commentID === commentID)), + ) + }, + updateComment(path: string, commentID: string, next: Partial<ContextItem>) { + setItems((current) => + current.map((item) => { + if (item.type !== "file" || item.path !== path || item.commentID !== commentID) return item + return withKey({ ...item, ...next }) + }), + ) + }, + replaceComments(next: Array<Omit<ContextItem, "key"> & { key?: string }>) { + const nonComment = items().filter((item) => !item.comment?.trim()) + setItems([...nonComment, ...next.map(withKey)]) + }, + }, + } +} diff --git a/packages/storybook/.storybook/mocks/app/context/sdk.ts b/packages/storybook/.storybook/mocks/app/context/sdk.ts new file mode 100644 index 0000000000..c37d682496 --- /dev/null +++ b/packages/storybook/.storybook/mocks/app/context/sdk.ts @@ -0,0 +1,25 @@ +const make = (directory: string) => ({ + session: { + create: async () => ({ data: { id: "story-session" } }), + prompt: async () => ({ data: undefined }), + shell: async () => ({ data: undefined }), + command: async () => ({ data: undefined }), + abort: async () => ({ data: undefined }), + }, + worktree: { + create: async () => ({ data: { directory: `${directory}/worktree-1` } }), + }, +}) + +const root = "/tmp/story" + +export function useSDK() { + return { + directory: root, + url: "http://localhost:4096", + client: make(root), + createClient(input: { directory: string }) { + return make(input.directory) + }, + } +} diff --git a/packages/storybook/.storybook/mocks/app/context/sync.ts b/packages/storybook/.storybook/mocks/app/context/sync.ts new file mode 100644 index 0000000000..bfc49dc83a --- /dev/null +++ b/packages/storybook/.storybook/mocks/app/context/sync.ts @@ -0,0 +1,32 @@ +import { createStore } from "solid-js/store" + +const [data, setData] = createStore({ + session: [] as Array<{ id: string; parentID?: string }>, + permission: {} as Record<string, Array<{ id: string; sessionID: string; permission: string; patterns: string[] }>>, + question: {} as Record<string, Array<{ id: string; questions: unknown[] }>>, + session_diff: {} as Record<string, Array<{ file: string }>>, + message: { + "story-session": [] as Array<{ id: string; role: string }>, + } as Record<string, Array<{ id: string; role: string }>>, + session_status: {} as Record<string, { type: "idle" | "busy" }>, + agent: [{ name: "build", mode: "task", hidden: false }], + command: [{ name: "fix", description: "Run fix command", source: "project" }], +}) + +export function useSync() { + return { + data, + set(...input: unknown[]) { + ;(setData as (...args: unknown[]) => void)(...input) + }, + session: { + get(id: string) { + return { id } + }, + optimistic: { + add() {}, + remove() {}, + }, + }, + } +} diff --git a/packages/storybook/.storybook/mocks/app/hooks/use-providers.ts b/packages/storybook/.storybook/mocks/app/hooks/use-providers.ts new file mode 100644 index 0000000000..04bd2b485c --- /dev/null +++ b/packages/storybook/.storybook/mocks/app/hooks/use-providers.ts @@ -0,0 +1,23 @@ +const model_id = "claude-3-7-sonnet" + +const provider = { + id: "anthropic", + models: { + [model_id]: { + id: model_id, + name: "Claude 3.7 Sonnet", + cost: { input: 1, output: 1 }, + variants: { fast: {}, thinking: {} }, + }, + }, +} + +export function useProviders() { + return { + all: () => [provider], + default: () => ({ anthropic: model_id }), + connected: () => [provider], + paid: () => [provider], + popular: () => [provider], + } +} diff --git a/packages/storybook/.storybook/mocks/solid-router.tsx b/packages/storybook/.storybook/mocks/solid-router.tsx new file mode 100644 index 0000000000..c1bda30f4b --- /dev/null +++ b/packages/storybook/.storybook/mocks/solid-router.tsx @@ -0,0 +1,28 @@ +import type { ParentProps } from "solid-js" + +export function useParams() { + return { + dir: "c3Rvcnk=", + id: "story-session", + } +} + +export function useNavigate() { + return () => undefined +} + +export function useLocation() { + return { + pathname: "/story/session/story-session", + search: "", + hash: "", + } +} + +export function MemoryRouter(props: ParentProps) { + return props.children +} + +export function Route(props: ParentProps) { + return props.children +} diff --git a/packages/storybook/.storybook/preview.tsx b/packages/storybook/.storybook/preview.tsx new file mode 100644 index 0000000000..4e28e43039 --- /dev/null +++ b/packages/storybook/.storybook/preview.tsx @@ -0,0 +1,98 @@ +import "@opencode-ai/ui/styles/tailwind" + +import { createEffect, onCleanup, onMount } from "solid-js" +import addonA11y from "@storybook/addon-a11y" +import addonDocs from "@storybook/addon-docs" +import { MetaProvider } from "@solidjs/meta" +import { addons } from "storybook/preview-api" +import { GLOBALS_UPDATED } from "storybook/internal/core-events" +import { createJSXDecorator, definePreview } from "storybook-solidjs-vite" +import { DialogProvider } from "@opencode-ai/ui/context/dialog" +import { MarkedProvider } from "@opencode-ai/ui/context/marked" +import { ThemeProvider, useTheme, type ColorScheme } from "@opencode-ai/ui/theme" +import { Font } from "@opencode-ai/ui/font" + +function resolveScheme(value: unknown): ColorScheme { + if (value === "light" || value === "dark" || value === "system") return value + return "system" +} + +const channel = addons.getChannel() + +const Scheme = (props: { value?: unknown }) => { + const theme = useTheme() + const apply = (value?: unknown) => { + theme.setColorScheme(resolveScheme(value)) + } + createEffect(() => { + apply(props.value) + }) + createEffect(() => { + const root = document.documentElement + root.classList.remove("light", "dark") + root.classList.add(theme.mode()) + }) + onMount(() => { + const handler = (event: { globals?: Record<string, unknown> }) => { + apply(event.globals?.theme) + } + channel.on(GLOBALS_UPDATED, handler) + onCleanup(() => channel.off(GLOBALS_UPDATED, handler)) + }) + return null +} + +const frame = createJSXDecorator((Story, context) => { + const override = context.parameters?.themes?.themeOverride + const selected = context.globals?.theme + const pick = override === "light" || override === "dark" ? override : selected + const scheme = resolveScheme(pick) + return ( + <MetaProvider> + <Font /> + <ThemeProvider> + <Scheme value={scheme} /> + <DialogProvider> + <MarkedProvider> + <div + style={{ + "min-height": "100vh", + padding: "24px", + "background-color": "var(--background-base)", + color: "var(--text-base)", + }} + > + <Story /> + </div> + </MarkedProvider> + </DialogProvider> + </ThemeProvider> + </MetaProvider> + ) +}) + +export default definePreview({ + addons: [addonDocs(), addonA11y()], + decorators: [frame], + globalTypes: { + theme: { + name: "Theme", + description: "Global theme", + defaultValue: "light", + }, + }, + parameters: { + actions: { + argTypesRegex: "^on.*", + }, + controls: { + matchers: { + color: /(background|color)$/i, + date: /Date$/i, + }, + }, + a11y: { + test: "todo", + }, + }, +}) diff --git a/packages/storybook/.storybook/theme-tool.ts b/packages/storybook/.storybook/theme-tool.ts new file mode 100644 index 0000000000..3dac777cd7 --- /dev/null +++ b/packages/storybook/.storybook/theme-tool.ts @@ -0,0 +1,21 @@ +import { createElement } from "react" +import { useGlobals } from "storybook/manager-api" +import { ToggleButton } from "storybook/internal/components" + +export function ThemeTool() { + const [globals, updateGlobals] = useGlobals() + const mode = globals.theme === "dark" ? "dark" : "light" + const toggle = () => { + const next = mode === "dark" ? "light" : "dark" + updateGlobals({ theme: next }) + } + return createElement( + ToggleButton, + { + title: "Toggle theme", + active: mode === "dark", + onClick: toggle, + }, + mode === "dark" ? "Dark" : "Light", + ) +} diff --git a/packages/storybook/debug-storybook.log b/packages/storybook/debug-storybook.log new file mode 100644 index 0000000000..e13d40c8e8 --- /dev/null +++ b/packages/storybook/debug-storybook.log @@ -0,0 +1,307 @@ +[14:25:48.462] [INFO] storybook v10.2.10 +[14:25:48.749] [DEBUG] Getting package.json info for /Users/davidhill/Documents/Local/opencode/packages/storybook/package.json... +[14:25:48.997] [INFO] Starting... +[14:25:49.095] [DEBUG] Starting preview.. +[14:25:49.098] [WARN] 🚨 Unable to index files: +- ./../ui/src/components/accordion.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/accordion.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/app-icon.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/app-icon.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/avatar.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/avatar.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/basic-tool.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/basic-tool.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/checkbox.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/checkbox.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/code.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/code.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/collapsible.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/collapsible.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/context-menu.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/context-menu.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/dialog.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/dialog.stories.tsx (line 10, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/diff-changes.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/diff-changes.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/diff-ssr.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/diff-ssr.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/diff.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/diff.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/dock-prompt.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/dock-prompt.stories.tsx (line 15, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/dropdown-menu.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/dropdown-menu.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/favicon.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/favicon.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/file-icon.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/file-icon.stories.tsx (line 13, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/font.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/font.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/hover-card.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/hover-card.stories.tsx (line 13, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/icon-button.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/icon-button.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/icon.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/icon.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/image-preview.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/image-preview.stories.tsx (line 13, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/inline-input.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/inline-input.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/keybind.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/keybind.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/line-comment.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/line-comment.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/list.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/list.stories.tsx (line 15, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/logo.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/logo.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/markdown.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/markdown.stories.tsx (line 12, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/message-nav.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/message-nav.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/message-part.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/message-part.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/popover.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/popover.stories.tsx (line 16, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/progress-circle.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/progress-circle.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/progress.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/progress.stories.tsx (line 15, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/provider-icon.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/provider-icon.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/radio-group.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/radio-group.stories.tsx (line 13, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/resize-handle.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/resize-handle.stories.tsx (line 17, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/select.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/select.stories.tsx (line 16, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/session-review.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/session-review.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/session-turn.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/session-turn.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/spinner.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/spinner.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/sticky-accordion-header.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/sticky-accordion-header.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/switch.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/switch.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/tabs.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/tabs.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/tag.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/tag.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/text-field.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/text-field.stories.tsx (line 14, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/text-shimmer.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/text-shimmer.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/toast.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/toast.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/tooltip.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/tooltip.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/typewriter.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/typewriter.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +[14:25:49.109] [ERROR] Failed to build the preview +[14:25:49.110] [ERROR] Error: Unable to index files: +- ./../ui/src/components/accordion.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/accordion.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/app-icon.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/app-icon.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/avatar.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/avatar.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/basic-tool.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/basic-tool.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/checkbox.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/checkbox.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/code.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/code.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/collapsible.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/collapsible.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/context-menu.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/context-menu.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/dialog.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/dialog.stories.tsx (line 10, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/diff-changes.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/diff-changes.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/diff-ssr.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/diff-ssr.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/diff.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/diff.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/dock-prompt.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/dock-prompt.stories.tsx (line 15, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/dropdown-menu.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/dropdown-menu.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/favicon.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/favicon.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/file-icon.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/file-icon.stories.tsx (line 13, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/font.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/font.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/hover-card.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/hover-card.stories.tsx (line 13, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/icon-button.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/icon-button.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/icon.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/icon.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/image-preview.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/image-preview.stories.tsx (line 13, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/inline-input.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/inline-input.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/keybind.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/keybind.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/line-comment.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/line-comment.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/list.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/list.stories.tsx (line 15, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/logo.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/logo.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/markdown.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/markdown.stories.tsx (line 12, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/message-nav.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/message-nav.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/message-part.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/message-part.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/popover.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/popover.stories.tsx (line 16, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/progress-circle.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/progress-circle.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/progress.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/progress.stories.tsx (line 15, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/provider-icon.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/provider-icon.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/radio-group.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/radio-group.stories.tsx (line 13, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/resize-handle.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/resize-handle.stories.tsx (line 17, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/select.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/select.stories.tsx (line 16, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/session-review.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/session-review.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/session-turn.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/session-turn.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/spinner.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/spinner.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/sticky-accordion-header.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/sticky-accordion-header.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/switch.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/switch.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/tabs.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/tabs.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/tag.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/tag.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/text-field.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/text-field.stories.tsx (line 14, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/text-shimmer.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/text-shimmer.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/toast.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/toast.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/tooltip.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/tooltip.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export +- ./../ui/src/components/typewriter.stories.tsx: CSF: default export must be an object /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/typewriter.stories.tsx (line 6, col 0) + +More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export + at _StoryIndexGenerator.getIndexAndStats (file:///Users/davidhill/Documents/Local/opencode/node_modules/.bun/storybook@10.2.10+4edd68b244e756bb/node_modules/storybook/dist/core-server/index.js:6085:15) + at async _StoryIndexGenerator.getIndex (file:///Users/davidhill/Documents/Local/opencode/node_modules/.bun/storybook@10.2.10+4edd68b244e756bb/node_modules/storybook/dist/core-server/index.js:6074:13) + at async getOptimizeDeps (file:///Users/davidhill/Documents/Local/opencode/node_modules/.bun/@storybook+builder-vite@10.2.10+a2a25316dbcddd7f/node_modules/@storybook/builder-vite/dist/index.js:1862:15) + at async createViteServer (file:///Users/davidhill/Documents/Local/opencode/node_modules/.bun/@storybook+builder-vite@10.2.10+a2a25316dbcddd7f/node_modules/@storybook/builder-vite/dist/index.js:1888:19) + at async Module.start (file:///Users/davidhill/Documents/Local/opencode/node_modules/.bun/@storybook+builder-vite@10.2.10+a2a25316dbcddd7f/node_modules/@storybook/builder-vite/dist/index.js:1923:17) + at async storybookDevServer (file:///Users/davidhill/Documents/Local/opencode/node_modules/.bun/storybook@10.2.10+4edd68b244e756bb/node_modules/storybook/dist/core-server/index.js:7241:83) + at async buildOrThrow (file:///Users/davidhill/Documents/Local/opencode/node_modules/.bun/storybook@10.2.10+4edd68b244e756bb/node_modules/storybook/dist/core-server/index.js:4504:12) + at async buildDevStandalone (file:///Users/davidhill/Documents/Local/opencode/node_modules/.bun/storybook@10.2.10+4edd68b244e756bb/node_modules/storybook/dist/core-server/index.js:7611:66) + at async withTelemetry (file:///Users/davidhill/Documents/Local/opencode/node_modules/.bun/storybook@10.2.10+4edd68b244e756bb/node_modules/storybook/dist/_node-chunks/chunk-S3MWHNYJ.js:218:12) + at async dev (file:///Users/davidhill/Documents/Local/opencode/node_modules/.bun/storybook@10.2.10+4edd68b244e756bb/node_modules/storybook/dist/bin/core.js:2734:3) +[14:25:49.118] [WARN] Broken build, fix the error above. +You may need to refresh the browser. \ No newline at end of file diff --git a/packages/storybook/package.json b/packages/storybook/package.json new file mode 100644 index 0000000000..b1dae1c956 --- /dev/null +++ b/packages/storybook/package.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://json.schemastore.org/package.json", + "name": "@opencode-ai/storybook", + "private": true, + "type": "module", + "scripts": { + "storybook": "storybook dev -p 6006", + "build": "storybook build" + }, + "devDependencies": { + "@tailwindcss/vite": "catalog:", + "@opencode-ai/ui": "workspace:*", + "@solidjs/meta": "catalog:", + "@storybook/addon-a11y": "^10.2.13", + "@storybook/addon-docs": "^10.2.13", + "@storybook/addon-links": "^10.2.13", + "@storybook/addon-onboarding": "^10.2.13", + "@storybook/addon-vitest": "^10.2.13", + "@tsconfig/node22": "catalog:", + "@types/node": "catalog:", + "@types/react": "18.0.25", + "react": "18.2.0", + "solid-js": "catalog:", + "storybook": "^10.2.13", + "storybook-solidjs-vite": "^10.0.9", + "typescript": "catalog:", + "vite": "catalog:" + } +} diff --git a/packages/storybook/sst-env.d.ts b/packages/storybook/sst-env.d.ts new file mode 100644 index 0000000000..64441936d7 --- /dev/null +++ b/packages/storybook/sst-env.d.ts @@ -0,0 +1,10 @@ +/* This file is auto-generated by SST. Do not edit. */ +/* tslint:disable */ +/* eslint-disable */ +/* deno-fmt-ignore-file */ +/* biome-ignore-all lint: auto-generated */ + +/// <reference path="../../sst-env.d.ts" /> + +import "sst" +export {} \ No newline at end of file diff --git a/packages/storybook/tsconfig.json b/packages/storybook/tsconfig.json new file mode 100644 index 0000000000..68ae315d2b --- /dev/null +++ b/packages/storybook/tsconfig.json @@ -0,0 +1,16 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "extends": "@tsconfig/node22/tsconfig.json", + "compilerOptions": { + "jsx": "preserve", + "jsxImportSource": "solid-js", + "target": "ESNext", + "lib": ["es2023", "dom", "dom.iterable"], + "module": "ESNext", + "moduleResolution": "bundler", + "noEmit": true, + "strict": true, + "types": ["vite/client", "node"] + }, + "include": [".storybook/**/*.ts", ".storybook/**/*.tsx"] +} diff --git a/packages/ui/package.json b/packages/ui/package.json index 3519996085..06c699f24e 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,9 +1,10 @@ { "name": "@opencode-ai/ui", - "version": "1.2.10", + "version": "1.2.24", "type": "module", "license": "MIT", "exports": { + "./package.json": "./package.json", "./*": "./src/components/*.tsx", "./i18n/*": "./src/i18n/*.ts", "./pierre": "./src/pierre/index.ts", @@ -33,6 +34,7 @@ "@types/bun": "catalog:", "@types/katex": "0.16.7", "@types/luxon": "catalog:", + "@typescript/native-preview": "catalog:", "tailwindcss": "catalog:", "typescript": "catalog:", "vite": "catalog:", @@ -49,7 +51,7 @@ "@solid-primitives/media": "2.3.3", "@solid-primitives/resize-observer": "2.1.3", "@solidjs/meta": "catalog:", - "@typescript/native-preview": "catalog:", + "@solidjs/router": "catalog:", "dompurify": "3.3.1", "fuzzysort": "catalog:", "katex": "0.16.27", @@ -58,6 +60,9 @@ "marked-katex-extension": "5.1.6", "marked-shiki": "catalog:", "morphdom": "2.7.8", + "motion": "12.34.5", + "motion-dom": "12.34.3", + "motion-utils": "12.29.2", "remeda": "catalog:", "shiki": "catalog:", "solid-js": "catalog:", diff --git a/packages/ui/script/colors.txt b/packages/ui/script/colors.txt index f849668536..2581b0e3e3 100644 --- a/packages/ui/script/colors.txt +++ b/packages/ui/script/colors.txt @@ -114,6 +114,7 @@ --border-weak-selected: var(--cobalt-light-alpha-5); --border-weak-disabled: var(--smoke-light-alpha-6); --border-weak-focus: var(--smoke-light-alpha-7); +--border-weaker-base: var(--smoke-light-alpha-3); --border-interactive-base: var(--cobalt-light-7); --border-interactive-hover: var(--cobalt-light-8); --border-interactive-active: var(--cobalt-light-9); @@ -224,11 +225,5 @@ --markdown-image-text: #318795; --markdown-code-block: #1A1A1A; --border-color: #FFFFFF; ---border-weaker-base: var(--smoke-light-alpha-3); ---border-weaker-hover: var(--smoke-light-alpha-4); ---border-weaker-active: var(--smoke-light-alpha-6); ---border-weaker-selected: var(--cobalt-light-alpha-4); ---border-weaker-disabled: var(--smoke-light-alpha-2); ---border-weaker-focus: var(--smoke-light-alpha-6); --button-ghost-hover: var(--smoke-light-alpha-2); --button-ghost-hover2: var(--smoke-light-alpha-3); diff --git a/packages/ui/src/assets/icons/app/warp.png b/packages/ui/src/assets/icons/app/warp.png new file mode 100644 index 0000000000..753e4d9118 Binary files /dev/null and b/packages/ui/src/assets/icons/app/warp.png differ diff --git a/packages/ui/src/assets/icons/provider/302ai.svg b/packages/ui/src/assets/icons/provider/302ai.svg new file mode 100644 index 0000000000..46f2e4315e --- /dev/null +++ b/packages/ui/src/assets/icons/provider/302ai.svg @@ -0,0 +1,7 @@ +<svg version="1.1" xmlns="http://www.w3.org/2000/svg" style="display: block;" viewBox="0 0 2048 2048" width="1046" height="1046" preserveAspectRatio="none"> +<path transform="translate(0,0)" fill="rgb(156,155,155)" d="M 388.193 1682.23 C 380.878 1674.23 349.014 1650.79 338.487 1642.13 C 148.161 1485.91 28.1107 1260.14 5.01063 1015 C -18.4493 771.014 55.9168 527.694 211.767 338.509 C 367.861 148.455 593.42 28.6444 838.288 5.7197 C 1092.75 -18.7181 1345.95 63.524 1537.48 232.828 C 1567.76 259.726 1596.32 288.496 1623 318.968 C 1631.78 329.058 1640.32 339.36 1648.6 349.865 C 1654.15 356.824 1662.64 368.871 1669.4 374.06 C 1866.4 518.124 1998.49 734.204 2036.88 975.222 C 2041.98 1007.66 2045.11 1039.38 2046.62 1072.12 C 2046.85 1077.09 2047.16 1082.22 2048 1087.12 L 2048 1155.79 L 2047.85 1156.71 C 2045.71 1170.93 2045.27 1196.57 2043.86 1212.22 C 2040.62 1246.59 2035.38 1280.75 2028.17 1314.51 C 1981.27 1534.16 1856.1 1729.25 1675.99 1863.43 C 1479.61 2010.02 1232.99 2072.49 990.498 2037.07 C 801.767 2009.86 626.135 1924.74 487.842 1793.46 C 455.956 1763.37 418.158 1722.72 392.022 1687.5 C 390.729 1685.76 389.452 1684 388.193 1682.23 z"/> +<path transform="translate(0,0)" fill="rgb(117,116,116)" d="M 1669.4 374.06 C 1866.4 518.124 1998.49 734.204 2036.88 975.222 C 2041.98 1007.66 2045.11 1039.38 2046.62 1072.12 C 2046.85 1077.09 2047.16 1082.22 2048 1087.12 L 2048 1155.79 L 2047.85 1156.71 C 2045.71 1170.93 2045.27 1196.57 2043.86 1212.22 C 2040.62 1246.59 2035.38 1280.75 2028.17 1314.51 C 1981.27 1534.16 1856.1 1729.25 1675.99 1863.43 C 1479.61 2010.02 1232.99 2072.49 990.498 2037.07 C 801.767 2009.86 626.135 1924.74 487.842 1793.46 C 455.956 1763.37 418.158 1722.72 392.022 1687.5 C 390.729 1685.76 389.452 1684 388.193 1682.23 C 394.373 1684.07 421.092 1702.62 428.047 1707.15 C 439.611 1714.6 451.324 1721.83 463.177 1728.82 C 490.564 1744.99 528.003 1763.59 557.361 1776.32 C 782.899 1873.92 1037.96 1878.01 1266.51 1787.69 C 1495.36 1696.62 1678.57 1518.24 1775.72 1291.9 C 1877.79 1053.06 1875.1 782.375 1768.31 545.611 C 1753.03 511.993 1733.8 474.565 1714.15 443.177 C 1706.81 431.355 1699.2 419.704 1691.32 408.231 C 1685.67 400.055 1672.56 382.889 1669.4 374.06 z"/> +<path transform="translate(0,0)" fill="rgb(254,254,254)" d="M 907.581 300.401 C 923.66 299.084 947.483 300.532 962.897 302.556 C 1041.39 313.102 1112.41 354.577 1160.17 417.755 C 1202.42 473.452 1228.57 555 1218.78 624.854 C 1256.03 619.819 1285.79 618.643 1323.38 625.442 C 1401.3 639.582 1470.3 684.357 1514.95 749.754 C 1560.04 815.479 1576.85 896.56 1561.6 974.792 C 1546.59 1052.29 1501.28 1120.59 1435.71 1164.55 C 1366.19 1211.67 1287.89 1223.85 1206.7 1207.99 L 1208.16 1225.92 C 1213.72 1304.44 1187.72 1381.94 1135.93 1441.23 C 1080.14 1505.71 1008.69 1536.8 924.661 1542.84 C 910.37 1543.02 898.883 1543.12 884.551 1541.84 C 806.009 1534.5 733.606 1496.24 683.294 1435.48 C 630.495 1371.76 609.152 1293.49 617.004 1211.82 C 577.182 1218.28 543.704 1219.15 503.598 1211.31 C 425.862 1195.87 357.514 1150.02 313.752 1083.94 C 269.997 1017.95 254.398 937.224 270.419 859.682 C 286.452 782.387 332.522 714.62 398.502 671.28 C 468.674 625.191 546.96 613.555 628.149 630.32 C 625.459 583.013 627.036 545.389 643.173 499.662 C 684.204 383.394 785.737 308.984 907.581 300.401 z"/> +<path transform="translate(0,0)" fill="rgb(156,155,155)" d="M 907.659 407.406 C 928.022 404.422 959.425 408.947 978.901 414.989 C 1028.11 429.972 1069.15 464.261 1092.65 510.025 C 1116.27 555.792 1120.24 609.2 1103.65 657.957 C 1098.74 672.384 1090.33 686.336 1086.3 699.186 C 1082.14 712.53 1083.57 726.994 1090.26 739.265 C 1100.24 757.657 1118.84 768.259 1139.57 767.119 C 1155.78 766.227 1164.63 759.273 1178.02 751.678 C 1221.56 726.903 1273.23 720.668 1321.41 734.376 C 1370.6 748.209 1412.18 781.215 1436.82 825.985 C 1461.35 870.569 1467.02 923.112 1452.58 971.905 C 1438.06 1020.82 1404.54 1061.88 1359.51 1085.9 C 1280.31 1128.12 1181.39 1108.75 1124.87 1039.74 C 1113.7 1026.12 1105.83 1013.42 1087.4 1008.03 C 1041 993.798 1000.36 1044.75 1026.36 1086.49 C 1041.95 1111.53 1062.76 1127.17 1078.18 1153.03 C 1090.26 1175.57 1097.84 1197.66 1100.84 1223.2 C 1107.04 1273.73 1092.65 1324.64 1060.9 1364.44 C 1029.42 1404.28 983.238 1429.79 932.752 1435.23 C 882.189 1440.86 831.491 1425.87 792.121 1393.65 C 752.588 1361.54 727.605 1314.91 722.781 1264.21 C 718.894 1225.82 727.653 1167.83 758.478 1141.35 C 771.141 1130.47 781.921 1118.81 792.404 1105.84 C 869.373 1010.12 879.456 876.886 817.771 770.669 C 809.316 756.055 799.574 742.224 788.661 729.342 C 782.235 721.815 773.191 712.791 767.461 705.187 C 749.008 680.699 737.483 646.859 734.444 616.659 C 729.188 565.849 744.584 515.06 777.168 475.721 C 810.289 435.451 856.055 412.394 907.659 407.406 z"/> +<path transform="translate(0,0)" fill="rgb(156,155,155)" d="M 554.228 729.711 C 659.104 725.931 747.227 807.802 751.164 912.672 C 755.1 1017.54 673.362 1105.79 568.498 1109.88 C 463.411 1113.98 374.937 1032.03 370.992 926.942 C 367.047 821.849 449.129 733.498 554.228 729.711 z"/> +</svg> \ No newline at end of file diff --git a/packages/ui/src/assets/icons/provider/berget.svg b/packages/ui/src/assets/icons/provider/berget.svg new file mode 100644 index 0000000000..831547a59e --- /dev/null +++ b/packages/ui/src/assets/icons/provider/berget.svg @@ -0,0 +1,3 @@ +<svg width="24" height="24" viewBox="0 0 463 419" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M208.739 17L255.261 17L446 403L398 403L313.5 255L261.5 176L233.163 96.1677L237.815 98.6522H226.185L230.837 96.1677L113 331L64.5 403L18 403L208.739 17Z" fill="currentColor"/> +</svg> \ No newline at end of file diff --git a/packages/ui/src/assets/icons/provider/cloudferro-sherlock.svg b/packages/ui/src/assets/icons/provider/cloudferro-sherlock.svg new file mode 100644 index 0000000000..6f09a794e6 --- /dev/null +++ b/packages/ui/src/assets/icons/provider/cloudferro-sherlock.svg @@ -0,0 +1,5 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" fill="currentColor"> +<path d="M12,24l-8.996,-8.996l8.996,-8.997l2.996,2.997l-5.999,6l2.996,2.997l6,-5.999l2.997,2.996l-8.99,8.996Z" opacity="0.01"/> +<path d="M9,15l6,-6l-3,-3l-9,9l-3,-3l12,-12l12,12l-3,3l-3,-3l-6,6l-3,-3Z"/> +<path d="M0,12L12,0L24,12L12,24L0,12Z" fill="none" stroke="currentColor" stroke-width="0.2"/> +</svg> \ No newline at end of file diff --git a/packages/ui/src/assets/icons/provider/evroc.svg b/packages/ui/src/assets/icons/provider/evroc.svg new file mode 100644 index 0000000000..7597820a19 --- /dev/null +++ b/packages/ui/src/assets/icons/provider/evroc.svg @@ -0,0 +1,3 @@ +<svg fill="inherit" viewBox="0 0 100 25"> + <path d="M79.01 5.863c-4.066 0-6.511 2.92-6.511 6.535 0 3.635 2.445 6.555 6.511 6.555 4.046 0 6.512-2.92 6.512-6.555s-2.466-6.535-6.512-6.535Zm0 10.968c-2.633 0-4.172-1.933-4.172-4.433s1.539-4.455 4.172-4.455c2.635 0 4.151 1.933 4.151 4.434 0 2.521-1.516 4.454-4.15 4.454Zm14.393 2.096c3.393 0 5.542-1.808 5.837-4.539h-2.36c-.316 1.555-1.517 2.437-3.477 2.437-2.423 0-3.878-1.68-3.878-4.433 0-2.774 1.476-4.434 3.878-4.434 1.96 0 3.14.862 3.477 2.5h2.36c-.295-2.773-2.444-4.622-5.837-4.622-3.856 0-6.217 2.669-6.217 6.535 0 3.887 2.36 6.556 6.217 6.556Zm-29.543-.311h2.36v-6.01c0-2.752 1.348-4.244 3.772-4.244h2.276V6.177h-2.255c-2.128 0-3.288.735-3.898 2.605l-.443-.063.527-2.542h-2.36v12.439h.02Zm-24.445-7.332c.106-2.101 1.517-3.53 3.793-3.53 2.276 0 3.646 1.345 3.646 3.53h-7.439Zm9.778.4c0-3.426-2.381-5.821-5.943-5.821-3.73 0-6.174 2.563-6.174 6.535 0 4.013 2.423 6.555 6.28 6.555 2.929 0 5.247-1.597 5.669-3.887h-2.36c-.507 1.156-1.666 1.828-3.31 1.828-2.38 0-3.877-1.408-3.94-3.803h9.694c.042-.588.084-.861.084-1.408Zm5.69 6.932h1.939l5.5-12.44h-2.529L56 15.99l-.316.021-3.793-9.833h-2.508l5.5 12.439ZM32.23 12.35c0-.882-.359-1.701-.99-2.437a8.594 8.594 0 0 1-1.497 1.093c.337.42.527.861.527 1.345 0 2.731-5.837 4.811-14.14 4.811-8.281.021-14.118-2.059-14.118-4.811 0-.463.168-.925.505-1.345a8.13 8.13 0 0 1-1.475-1.093c-.632.736-.99 1.555-.99 2.438 0 4.034 7.207 6.534 16.1 6.534 8.87.021 16.078-2.5 16.078-6.535Zm-3.351 1.534c-.906-.462-1.96-.861-3.16-1.197-1.37.378-2.909.672-4.553.861 2.318.294 4.341.778 5.9 1.408.76-.336 1.37-.693 1.813-1.072Zm-17.849-.357a31.902 31.902 0 0 1-4.467-.84c-1.18.336-2.255.735-3.16 1.197.42.379 1.01.715 1.748 1.05 1.539-.63 3.52-1.113 5.88-1.407Zm21.2-6.808c0-4.013-7.207-6.534-16.079-6.534C7.26.185.051 2.706.051 6.719c0 4.035 7.208 6.535 16.1 6.535 8.872.021 16.079-2.5 16.079-6.535Zm-1.94 0c0 2.732-5.836 4.812-14.139 4.812-8.302.021-14.14-2.06-14.14-4.812 0-2.731 5.838-4.811 14.14-4.811 7.86 0 14.14 2.08 14.14 4.811Zm-3.223 2.564c.758-.336 1.37-.694 1.812-1.072-2.95-1.513-7.544-2.353-12.728-2.353s-9.799.84-12.728 2.353c.422.378 1.012.715 1.75 1.05 2.507-1.05 6.363-1.68 10.978-1.68 4.404 0 8.324.651 10.916 1.702ZM1.042 15.628c-.632.736-.99 1.534-.99 2.438 0 4.034 7.207 6.534 16.1 6.534 8.892 0 16.099-2.521 16.099-6.534 0-.883-.359-1.702-.99-2.438-.422.4-.907.757-1.497 1.093.337.42.527.861.527 1.345 0 2.731-5.837 4.811-14.14 4.811-8.302 0-14.14-2.08-14.14-4.811 0-.463.17-.925.506-1.345a10.73 10.73 0 0 1-1.475-1.093Z"></path> +</svg> \ No newline at end of file diff --git a/packages/ui/src/assets/icons/provider/firmware.svg b/packages/ui/src/assets/icons/provider/firmware.svg new file mode 100644 index 0000000000..baa524ba2d --- /dev/null +++ b/packages/ui/src/assets/icons/provider/firmware.svg @@ -0,0 +1,18 @@ +<svg + width="24" + height="24" + viewBox="0 0 40 40" + xmlns="http://www.w3.org/2000/svg" + > + <g + transform="matrix(1.149971,0,0,1.149971,-166.19831,2.0845471)" + > + <path + fill-rule="evenodd" + clip-rule="evenodd" + d="m 172.24982,31.21868 h 7.05286 l -1.46587,-2.792842 -2.50031,-0.56255 -2.45857,-4.899805 3.20956,-5.39366 -1.27352,-2.509532 h 0.94075 l 1.69977,-1.097102 v -1.003566 h 0.71098 V 9.2006456 L 174.88883,8.1743823 174.04436,7.011809 h -4.20939 l -3.18164,3.546614 -3.17106,-6.3194202 -18.92307,-4.2721087 12.5905,14.1419309 h -1.44316 l -5.16203,3.661439 -2.60981,5.055178 -1.10108,0.311349 v -4.257417 l 1.09698,-0.720257 -2.41204,-3.676132 V 24.87269 l 3.32207,-0.936862 2.7234,-5.278272 2.87418,-2.038852 -4.19705,8.442439 v 3.325965 l 1.15171,2.831572 h 4.45518 v -1.428443 l -0.53832,-1.131806 -1.25751,-0.768529 v -0.657318 l 2.58945,-4.280136 v 2.792842 l 2.26644,2.614989 0.9823,1.749313 v 1.109088 h 5.15662 v -1.420438 l -0.56666,-1.276122 -1.34817,-0.728284 -1.59828,-2.366603 1.227,-2.275513 3.72559,0.583754 -0.87541,4.810663 -0.0108,2.672543 h 5.18498 v -1.362885 l -0.2419,-0.956983 -0.7378,-0.720063 0.56233,-1.122936 1.88194,2.918767 z m 1.89753,-17.471965 h 1.21987 l 0.77242,-0.49844 v -0.288652 h -0.6333 v -1.313575 h 1.34557 V 10.16544 L 174.0805,9.298183 173.37493,8.3253836 h -1.97867 z m -4.04409,-5.0676393 -0.923,1.0293789 4.59754,9.1729964 0.81029,-1.362407 z m -2.81664,3.1414493 0.95115,-1.060904 4.74272,9.462472 -0.80185,1.347868 z m -10.78667,3.601874 -4.94523,9.945983 V 28.1305 l 0.72157,1.773328 h 2.17144 l -0.15644,-0.32736 -1.55263,-0.948762 v -1.761212 l 3.65462,-6.042799 12.81381,2.008454 4.35629,6.754921 v 0.316758 h 3.56526 l -0.17244,-0.328875 -2.51502,-0.566443 -0.14021,-0.27803 -8.12582,-16.195842 -7.43798,2.887761 z m 9.08324,-4.067925 -2.99624,-5.9715919 -3.20783,-0.7241093 4.77108,7.2521282 z m -2.68532,1.04275 -5.3652,-8.1552571 -3.82404,-0.8631672 7.71645,9.5903223 z m -2.75757,1.070727 -8.49168,-10.5541849 -3.38785,-0.7647211 10.52054,11.818147 -0.0569,0.0506 z m -2.18485,11.788137 v -2.857102 l 3.42916,0.537235 -1.38344,2.567173 2.2223,3.292645 1.23739,0.668135 0.19517,0.439654 h -2.45208 V 29.76622 l -1.21619,-2.164949 z m 11.58527,0.51668 -1.11818,-1.733951 -0.63784,-0.09996 -0.86936,4.784916 v 1.180055 h 2.52692 l -0.0816,-0.324764 -1.15994,-1.130508 z m 0.29555,-21.8290604 h -0.001 v 2.1928393 h 4.20916 V 3.9437076 h -0.003 l -1.04894,1.0503231 -1.05046,-1.0503231 h -0.005 l -1.05046,1.0503231 z" + fill="currentColor" + /> + </g> + +</svg> diff --git a/packages/ui/src/assets/icons/provider/gitlab.svg b/packages/ui/src/assets/icons/provider/gitlab.svg new file mode 100644 index 0000000000..eef04ace2b --- /dev/null +++ b/packages/ui/src/assets/icons/provider/gitlab.svg @@ -0,0 +1,3 @@ +<svg width="24" height="24" viewBox="0 0 380 380" xmlns="http://www.w3.org/2000/svg"> +<path d="M265.26416,174.37243l-.2134-.55822-21.19899-55.30908c-.4236-1.08359-1.18542-1.99642-2.17699-2.62689-.98837-.63373-2.14749-.93253-3.32305-.87014-1.1689.06239-2.29195.48925-3.20809,1.21821-.90957.73554-1.56629,1.73047-1.87493,2.85346l-14.31327,43.80662h-57.90965l-14.31327-43.80662c-.30864-1.12299-.96536-2.11791-1.87493-2.85346-.91614-.72895-2.03911-1.15582-3.20809-1.21821-1.17548-.06239-2.33468.23641-3.32297.87014-.99166.63047-1.75348,1.5433-2.17707,2.62689l-21.19891,55.31237-.21348.55493c-6.28158,16.38521-.92929,34.90803,13.05891,45.48782.02621.01641.04922.03611.07552.05582l.18719.14119,32.29094,24.17392,15.97151,12.09024,9.71951,7.34871c2.34117,1.77316,5.57877,1.77316,7.92002,0l9.71943-7.34871,15.96822-12.09024,32.48142-24.31511c.02958-.02299.05588-.04269.08538-.06568,13.97834-10.57977,19.32735-29.09604,13.04905-45.47796Z" fill="currentColor"/> +</svg> diff --git a/packages/ui/src/assets/icons/provider/jiekou.svg b/packages/ui/src/assets/icons/provider/jiekou.svg new file mode 100644 index 0000000000..7fe6378e56 --- /dev/null +++ b/packages/ui/src/assets/icons/provider/jiekou.svg @@ -0,0 +1,4 @@ +<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M16 4H4V20H16C18.2091 20 20 18.2091 20 16V8H24V16C24 20.4183 20.4183 24 16 24H4C1.79086 24 1.61064e-08 22.2091 0 20V0H16V4Z" fill="currentColor"/> +<path d="M20 4H24V0H20V4Z" fill="currentColor"/> +</svg> diff --git a/packages/ui/src/assets/icons/provider/kilo.svg b/packages/ui/src/assets/icons/provider/kilo.svg new file mode 100644 index 0000000000..0a761347a8 --- /dev/null +++ b/packages/ui/src/assets/icons/provider/kilo.svg @@ -0,0 +1,4 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"> + <path d="M5 3v18" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"/> + <path d="M17.5 4.5 9.5 12l8 7.5" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"/> +</svg> diff --git a/packages/ui/src/assets/icons/provider/kuae-cloud-coding-plan.svg b/packages/ui/src/assets/icons/provider/kuae-cloud-coding-plan.svg new file mode 100644 index 0000000000..3d0d0c4557 --- /dev/null +++ b/packages/ui/src/assets/icons/provider/kuae-cloud-coding-plan.svg @@ -0,0 +1,3 @@ +<svg width="24" height="24" viewBox="0 0 40 40" xmlns="http://www.w3.org/2000/svg"> +<path d="M20.1312 7.5L17.4088 11.1912H5.81625L8.5375 7.5H20.1325H20.1312ZM34.0675 28.81L31.3475 32.5H19.795L22.5125 28.81H34.0675ZM35 7.5L16.58 32.5H5L23.42 7.5H35Z" fill="currentColor"/> +</svg> diff --git a/packages/ui/src/assets/icons/provider/meganova.svg b/packages/ui/src/assets/icons/provider/meganova.svg new file mode 100644 index 0000000000..59e8b3a1f2 --- /dev/null +++ b/packages/ui/src/assets/icons/provider/meganova.svg @@ -0,0 +1,3 @@ +<svg width="24" height="24" viewBox="0 0 1000 1000" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M534 154C541.732 154 548 160.268 548 168C548 170.518 547.334 172.881 546.17 174.923L602.021 240.338C603.835 239.48 605.861 239 608 239C615.732 239 622 245.268 622 253C622 254.065 621.88 255.102 621.655 256.099L706.818 300.431C709.276 298.294 712.487 297 716 297C723.732 297 730 303.268 730 311C730 311.443 729.978 311.882 729.938 312.314L863.375 379.883C865.943 376.893 869.75 375 874 375C881.732 375 888 381.268 888 389C888 391.789 887.183 394.387 885.777 396.569L946.472 464.134C948.168 463.404 950.037 463 952 463C959.732 463 966 469.268 966 477C966 484.732 959.732 491 952 491C945.627 491 940.248 486.741 938.555 480.914L856.912 472.417C854.794 477.459 849.811 481 844 481C839.112 481 834.811 478.495 832.307 474.699L729.884 506.808C728.997 513.686 723.119 519 716 519C713.249 519 710.684 518.206 708.52 516.835L621.863 571.045C621.953 571.684 622 572.336 622 573C622 580.732 615.732 587 608 587C606.913 587 605.854 586.876 604.838 586.642L545.427 672.909C547.047 675.194 548 677.986 548 681C548 685.573 545.806 689.633 542.415 692.188L562.436 761.104C567.278 761.8 571 765.965 571 771C571 772.011 570.848 772.986 570.569 773.906L603.281 804.182C604.687 803.428 606.293 803 608 803C611.041 803 613.763 804.359 615.597 806.5L702.076 770.468C702.026 769.985 702 769.496 702 769C702 761.268 708.268 755 716 755C723.732 755 730 761.268 730 769C730 776.732 723.732 783 716 783C712.501 783 709.301 781.716 706.847 779.594L617.979 836.371C617.991 836.579 618 836.789 618 837C618 842.523 613.523 847 608 847C602.477 847 598 842.523 598 837C598 836.723 598.014 836.449 598.036 836.178L513.258 779.798C511.544 781.175 509.369 782 507 782C501.477 782 497 777.523 497 772C497 769.373 498.014 766.983 499.671 765.198L467.477 694.922C466.991 694.973 466.499 695 466 695C458.268 695 452 688.732 452 681C452 677.846 453.043 674.935 454.803 672.595L395.197 586.633C394.17 586.873 393.1 587 392 587C384.268 587 378 580.732 378 573C378 572.271 378.055 571.555 378.162 570.856L292.756 515.923C290.358 517.847 287.314 519 284 519C276.58 519 270.509 513.228 270.031 505.929L167.816 474.509C165.332 478.411 160.969 481 156 481C150.213 481 145.246 477.489 143.113 472.48L61.3994 481.062C59.6582 486.813 54.319 491 48 491C40.268 491 34 484.732 34 477C34 469.268 40.268 463 48 463C50.289 463 52.4497 463.549 54.3574 464.523L113.915 396.071C112.698 393.996 112 391.58 112 389C112 381.268 118.268 375 126 375C130.139 375 133.858 376.796 136.421 379.651L270.236 313.574C270.081 312.74 270 311.879 270 311C270 303.268 276.268 297 284 297C287.987 297 291.584 298.667 294.134 301.341L378.38 256.251C378.132 255.208 378 254.119 378 253C378 245.268 384.268 239 392 239C394.155 239 396.197 239.487 398.021 240.357L454.009 175.23C452.734 173.12 452 170.646 452 168C452 160.268 458.268 154 466 154C473.732 154 480 160.268 480 168C480 175.732 473.732 182 466 182C465.903 182 465.806 181.997 465.71 181.995L456.335 215.262C458.572 217.096 460 219.881 460 223C460 223.476 459.964 223.943 459.899 224.401L490.157 243.044C492.686 240.544 496.163 239 500 239C503.689 239 507.043 240.427 509.544 242.759L540.088 224.312C540.032 223.882 540 223.445 540 223C540 219.852 541.455 217.045 543.729 215.212L534.666 181.983C534.445 181.994 534.223 182 534 182C526.268 182 520 175.732 520 168C520 160.268 526.268 154 534 154ZM601.857 829.11C603.553 827.789 605.684 827 608 827C610.386 827 612.575 827.836 614.294 829.23L675.14 790.358L617.926 814.197C617.334 819.155 613.118 823 608 823C602.477 823 598 818.523 598 813C598 812.133 598.11 811.291 598.317 810.488L565.37 779.995C564.05 780.638 562.567 781 561 781C556.709 781 553.05 778.296 551.631 774.5H519.738L601.857 829.11ZM534.745 694.979L512.811 763.863C513.81 764.579 514.673 765.473 515.351 766.5H552.07C552.714 765.226 553.62 764.108 554.72 763.219L534.893 694.97C534.843 694.973 534.794 694.977 534.745 694.979ZM479.419 685C478.611 687.716 477.001 690.086 474.863 691.836L505.827 759.428L526.949 693.097C523.912 691.323 521.604 688.438 520.581 685H479.419ZM472.819 668.771C475.97 670.531 478.37 673.475 479.419 677H520.581C521.664 673.363 524.184 670.345 527.483 668.606L499.583 566.045L472.819 668.771ZM506.869 556.264C506.448 556.662 505.992 557.025 505.507 557.346L535.354 667.064C536.67 667.191 537.934 667.499 539.119 667.965L597.867 582.66C596.132 580.841 594.883 578.555 594.325 576.011L506.869 556.264ZM405.68 575.984C405.128 578.527 403.885 580.811 402.158 582.632L461.236 667.831C462.425 667.401 463.689 667.128 465.003 667.035L493.727 556.786C493.457 556.568 493.198 556.338 492.952 556.094L405.68 575.984ZM508.761 544.178C509.515 545.545 509.956 547.106 509.994 548.769L594.938 567.95C595.639 566.14 596.705 564.512 598.046 563.156L557.757 476.993C557.023 476.976 556.309 476.88 555.622 476.713L508.761 544.178ZM445.066 476.519C444.466 476.712 443.841 476.849 443.197 476.926L402.037 563.241C403.332 564.573 404.364 566.161 405.05 567.922L490.011 548.559C490.068 547.243 490.38 545.994 490.898 544.857L445.066 476.519ZM565.856 473.183C565.642 473.455 565.413 473.716 565.172 473.965L605.076 559.306C606.019 559.105 606.997 559 608 559C612.173 559 615.919 560.826 618.483 563.723L703.216 510.716C702.671 509.5 702.295 508.192 702.117 506.822L565.856 473.183ZM297.766 507.556C297.653 508.166 297.501 508.762 297.312 509.342L381.642 563.581C384.202 560.766 387.895 559 392 559C393.044 559 394.061 559.114 395.039 559.331L435.461 474.562C435.054 474.21 434.675 473.828 434.329 473.415L297.766 507.556ZM451.235 463.162C451.727 464.344 452 465.64 452 467C452 468.48 451.675 469.884 451.098 471.148L496.927 539.482C497.895 539.17 498.928 539 500 539C500.832 539 501.64 539.103 502.412 539.294L549.257 471.854C548.457 470.416 548 468.762 548 467C548 465.371 548.392 463.834 549.083 462.475L501.213 398.924C500.815 398.972 500.411 399 500 399C499.329 399 498.673 398.933 498.039 398.807L451.235 463.162ZM346.938 397.694C345.907 398.281 344.763 398.691 343.546 398.88L295.016 496.359C295.772 497.322 296.404 498.386 296.89 499.528L432.083 465.729C432.175 465.006 432.341 464.306 432.579 463.639L346.938 397.694ZM567.637 464.329C567.737 464.692 567.819 465.062 567.878 465.44L703.396 498.896C704.247 497.143 705.453 495.595 706.92 494.344L659.017 398.948C658.682 398.982 658.343 399 658 399C656.789 399 655.629 398.785 654.555 398.391L567.637 464.329ZM773.415 398.4C772.743 398.645 772.037 398.816 771.307 398.911L726.722 495.999C727.447 496.862 728.07 497.814 728.572 498.836L830 467.039C830 467.026 830 467.013 830 467C830 464.574 830.617 462.293 831.702 460.304L773.415 398.4ZM168.537 460.766C169.446 462.59 169.968 464.64 169.997 466.811L271.812 498.106C272.696 496.546 273.872 495.173 275.265 494.06L230.778 398.967C230.521 398.987 230.262 399 230 399C229.342 399 228.699 398.934 228.076 398.812L168.537 460.766ZM667.337 385.418C667.764 386.53 668 387.737 668 389C668 391.257 667.252 393.338 665.991 395.012L713.5 489.621V324.776C713.053 324.696 712.614 324.594 712.184 324.473L667.337 385.418ZM290.106 323.6C289.907 323.697 289.705 323.789 289.5 323.877V489.49L335.673 396.743C333.431 394.909 332 392.122 332 389C332 386.919 332.636 384.987 333.724 383.387L290.106 323.6ZM239.209 385.098C239.718 386.297 240 387.615 240 389C240 391.341 239.194 393.492 237.847 395.195L281.5 488.509V324.776C281.224 324.727 280.951 324.668 280.681 324.603L239.209 385.098ZM721.5 323.877V488.205L763.549 396.639C761.379 394.804 760 392.064 760 389C760 386.918 760.637 384.985 761.726 383.384L721.64 323.815C721.593 323.836 721.547 323.857 721.5 323.877ZM60.1543 470.048C60.6859 470.975 61.113 471.97 61.4229 473.015L142.217 464.529C142.869 460.867 144.945 457.698 147.852 455.614L125.642 402.995C123.533 402.942 121.541 402.422 119.764 401.536L60.1543 470.048ZM879.71 401.785C877.966 402.565 876.034 403 874 403C873.859 403 873.72 402.996 873.58 402.992L852.339 455.754C855.128 457.825 857.119 460.91 857.77 464.463L938.617 472.877C939.015 471.584 939.595 470.37 940.328 469.267L879.71 401.785ZM508.659 394C508.497 394.28 508.321 394.551 508.133 394.813L555.263 457.382C556.133 457.135 557.051 457 558 457C559.655 457 561.215 457.404 562.59 458.116L647.109 394H508.659ZM438.096 457.791C439.295 457.282 440.615 457 442 457C443.192 457 444.335 457.209 445.396 457.592L491.476 394.23C491.429 394.155 491.385 394.077 491.341 394H355.251L438.096 457.791ZM139.08 394C137.987 396.857 135.986 399.263 133.429 400.867L155.438 453.012C155.624 453.004 155.812 453 156 453C158.578 453 160.993 453.698 163.067 454.913L221.44 394.174C221.406 394.117 221.374 394.058 221.341 394H139.08ZM837.377 454.662C839.349 453.601 841.604 453 844 453C844.273 453 844.544 453.008 844.812 453.023L865.972 400.47C863.702 398.878 861.926 396.63 860.92 394H780.261L837.377 454.662ZM561.53 324.356C560.432 324.771 559.243 325 558 325C557.329 325 556.673 324.933 556.039 324.807L508.931 384.504C509.172 384.982 509.379 385.481 509.542 386H646.656L561.53 324.356ZM768.495 379.112C768.986 379.038 769.489 379 770 379C774.478 379 778.268 381.943 779.542 386H857.747L729.39 321.004L768.495 379.112ZM355.696 386H490.458C490.55 385.708 490.655 385.423 490.771 385.144L444.67 324.637C443.82 324.872 442.925 325 442 325C441.036 325 440.105 324.861 439.223 324.606L355.696 386ZM141.636 386H220.458C221.732 381.943 225.522 379 230 379C231.159 379 232.271 379.199 233.306 379.562L273.545 320.864L141.636 386ZM617.724 263.07C617.275 263.503 616.799 263.906 616.296 264.276L659.187 379.072C660.037 379.173 660.854 379.38 661.625 379.68L705.419 320.167C703.289 317.711 702 314.506 702 311C702 309.687 702.18 308.415 702.519 307.21L617.724 263.07ZM451.826 313.151C451.938 313.751 452 314.368 452 315C452 316.655 451.595 318.215 450.883 319.59L496.599 379.593C497.66 379.209 498.806 379 500 379C500.963 379 501.893 379.139 502.773 379.393L549.469 320.219C548.537 318.699 548 316.913 548 315C548 314.117 548.115 313.26 548.33 312.444L505.47 265.89C503.789 266.604 501.941 267 500 267C497.866 267 495.844 266.521 494.034 265.667L451.826 313.151ZM297.771 308.468C297.921 309.289 298 310.135 298 311C298 313.614 297.283 316.06 296.035 318.154L340.507 379.111C340.994 379.038 341.493 379 342 379C342.385 379 342.765 379.024 343.139 379.066L383.879 264.404C383.354 264.03 382.857 263.62 382.39 263.179L297.771 308.468ZM397.089 266.046C395.512 266.662 393.795 267 392 267C391.816 267 391.634 266.994 391.452 266.987L351.633 379.058L432.961 319.28C432.345 317.983 432 316.532 432 315C432 313.273 432.437 311.648 433.208 310.23L397.089 266.046ZM567.117 310.896C567.682 312.148 568 313.537 568 315C568 316.293 567.751 317.527 567.305 318.661L650.615 378.989L608.765 266.979C608.511 266.992 608.257 267 608 267C606.25 267 604.576 266.678 603.031 266.092L567.117 310.896ZM405.818 250.75C405.937 251.483 406 252.234 406 253C406 256.03 405.037 258.836 403.4 261.127L439.519 305.31C440.312 305.107 441.143 305 442 305C443.87 305 445.62 305.515 447.117 306.408L488.073 260.334C486.759 258.201 486 255.689 486 253C486 251.995 486.106 251.014 486.308 250.069L455.703 231.212C454.085 232.338 452.12 233 450 233C447.634 233 445.462 232.177 443.75 230.804L405.818 250.75ZM556.249 230.805C554.537 232.177 552.365 233 550 233C547.847 233 545.855 232.317 544.224 231.16L513.598 249.657C513.86 250.728 514 251.848 514 253C514 255.88 513.129 258.556 511.639 260.781L553.387 306.128C554.767 305.409 556.336 305 558 305C559.11 305 560.177 305.183 561.175 305.517L596.675 261.23C594.993 258.92 594 256.076 594 253C594 252.234 594.061 251.483 594.18 250.751L556.249 230.805ZM551.447 213.105C556.284 213.807 560 217.969 560 223C560 223.243 559.988 223.485 559.971 223.724L591.452 240.279L543.561 184.188L551.447 213.105ZM408.715 240.19L440.028 223.724C440.011 223.485 440 223.243 440 223C440 217.94 443.758 213.761 448.635 213.095L456.745 184.319L408.715 240.19Z" fill="currentColor"/> +</svg> diff --git a/packages/ui/src/assets/icons/provider/minimax-cn-coding-plan.svg b/packages/ui/src/assets/icons/provider/minimax-cn-coding-plan.svg new file mode 100644 index 0000000000..086e9aa1fc --- /dev/null +++ b/packages/ui/src/assets/icons/provider/minimax-cn-coding-plan.svg @@ -0,0 +1,24 @@ +<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> + <path + shape-rendering="geometricPrecision" + d="M9.8132 15.9038L9 18.75L8.1868 15.9038C7.75968 14.4089 6.59112 13.2403 5.09619 12.8132L2.25 12L5.09619 11.1868C6.59113 10.7597 7.75968 9.59112 8.1868 8.09619L9 5.25L9.8132 8.09619C10.2403 9.59113 11.4089 10.7597 12.9038 11.1868L15.75 12L12.9038 12.8132C11.4089 13.2403 10.2403 14.4089 9.8132 15.9038Z" + stroke="currentColor" + stroke-width="1.5" + stroke-linecap="round" + stroke-linejoin="round" + /> + <path + d="M18.2589 8.71454L18 9.75L17.7411 8.71454C17.4388 7.50533 16.4947 6.56117 15.2855 6.25887L14.25 6L15.2855 5.74113C16.4947 5.43883 17.4388 4.49467 17.7411 3.28546L18 2.25L18.2589 3.28546C18.5612 4.49467 19.5053 5.43883 20.7145 5.74113L21.75 6L20.7145 6.25887C19.5053 6.56117 18.5612 7.50533 18.2589 8.71454Z" + stroke="currentColor" + stroke-width="1.5" + stroke-linecap="round" + stroke-linejoin="round" + /> + <path + d="M16.8942 20.5673L16.5 21.75L16.1058 20.5673C15.8818 19.8954 15.3546 19.3682 14.6827 19.1442L13.5 18.75L14.6827 18.3558C15.3546 18.1318 15.8818 17.6046 16.1058 16.9327L16.5 15.75L16.8942 16.9327C17.1182 17.6046 17.6454 18.1318 18.3173 18.3558L19.5 18.75L18.3173 19.1442C17.6454 19.3682 17.1182 19.8954 16.8942 20.5673Z" + stroke="currentColor" + stroke-width="1.5" + stroke-linecap="round" + stroke-linejoin="round" + /> +</svg> diff --git a/packages/ui/src/assets/icons/provider/minimax-coding-plan.svg b/packages/ui/src/assets/icons/provider/minimax-coding-plan.svg new file mode 100644 index 0000000000..086e9aa1fc --- /dev/null +++ b/packages/ui/src/assets/icons/provider/minimax-coding-plan.svg @@ -0,0 +1,24 @@ +<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> + <path + shape-rendering="geometricPrecision" + d="M9.8132 15.9038L9 18.75L8.1868 15.9038C7.75968 14.4089 6.59112 13.2403 5.09619 12.8132L2.25 12L5.09619 11.1868C6.59113 10.7597 7.75968 9.59112 8.1868 8.09619L9 5.25L9.8132 8.09619C10.2403 9.59113 11.4089 10.7597 12.9038 11.1868L15.75 12L12.9038 12.8132C11.4089 13.2403 10.2403 14.4089 9.8132 15.9038Z" + stroke="currentColor" + stroke-width="1.5" + stroke-linecap="round" + stroke-linejoin="round" + /> + <path + d="M18.2589 8.71454L18 9.75L17.7411 8.71454C17.4388 7.50533 16.4947 6.56117 15.2855 6.25887L14.25 6L15.2855 5.74113C16.4947 5.43883 17.4388 4.49467 17.7411 3.28546L18 2.25L18.2589 3.28546C18.5612 4.49467 19.5053 5.43883 20.7145 5.74113L21.75 6L20.7145 6.25887C19.5053 6.56117 18.5612 7.50533 18.2589 8.71454Z" + stroke="currentColor" + stroke-width="1.5" + stroke-linecap="round" + stroke-linejoin="round" + /> + <path + d="M16.8942 20.5673L16.5 21.75L16.1058 20.5673C15.8818 19.8954 15.3546 19.3682 14.6827 19.1442L13.5 18.75L14.6827 18.3558C15.3546 18.1318 15.8818 17.6046 16.1058 16.9327L16.5 15.75L16.8942 16.9327C17.1182 17.6046 17.6454 18.1318 18.3173 18.3558L19.5 18.75L18.3173 19.1442C17.6454 19.3682 17.1182 19.8954 16.8942 20.5673Z" + stroke="currentColor" + stroke-width="1.5" + stroke-linecap="round" + stroke-linejoin="round" + /> +</svg> diff --git a/packages/ui/src/assets/icons/provider/moark.svg b/packages/ui/src/assets/icons/provider/moark.svg new file mode 100644 index 0000000000..dc84a9191c --- /dev/null +++ b/packages/ui/src/assets/icons/provider/moark.svg @@ -0,0 +1,3 @@ +<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path fill-rule="evenodd" clip-rule="evenodd" d="M25.132 24.3947C25.497 25.7527 25.8984 27.1413 26.3334 28.5834C26.7302 29.8992 25.5459 30.4167 25.0752 29.1758C24.571 27.8466 24.0885 26.523 23.6347 25.1729C21.065 26.4654 18.5025 27.5424 15.5961 28.7541C16.7581 33.0256 17.8309 36.5984 19.4952 39.9935C19.4953 39.9936 19.4953 39.9937 19.4954 39.9938C19.6631 39.9979 19.8313 40 20 40C31.0457 40 40 31.0457 40 20C40 16.0335 38.8453 12.3366 36.8537 9.22729C31.6585 9.69534 27.0513 10.4562 22.8185 11.406C22.8882 12.252 22.9677 13.0739 23.0555 13.855C23.3824 16.7604 23.9112 19.5281 24.6137 22.3836C27.0581 21.2848 29.084 20.3225 30.6816 19.522C32.2154 18.7535 33.6943 18.7062 31.2018 20.6594C29.0388 22.1602 27.0644 23.3566 25.132 24.3947ZM36.1559 8.20846C33.0001 3.89184 28.1561 0.887462 22.5955 0.166882C22.4257 2.86234 22.4785 6.26344 22.681 9.50447C26.7473 8.88859 31.1721 8.46032 36.1559 8.20846ZM19.9369 9.73661e-05C19.7594 2.92694 19.8384 6.65663 20.19 9.91293C17.3748 10.4109 14.7225 11.0064 12.1592 11.7038C12.0486 10.4257 11.9927 9.25764 11.9927 8.24178C11.9927 7.5054 11.3957 6.90844 10.6593 6.90844C9.92296 6.90844 9.32601 7.5054 9.32601 8.24178C9.32601 9.47868 9.42873 10.898 9.61402 12.438C8.33567 12.8278 7.07397 13.2443 5.81918 13.688C5.12493 13.9336 4.76118 14.6954 5.0067 15.3896C5.25223 16.0839 6.01406 16.4476 6.7083 16.2021C7.7931 15.8185 8.88482 15.4388 9.98927 15.0659C10.5222 18.3344 11.3344 21.9428 12.2703 25.4156C12.4336 26.0218 12.6062 26.6262 12.7863 27.2263C9.34168 28.4135 5.82612 29.3782 2.61128 29.8879C0.949407 26.9716 0 23.5967 0 20C0 8.97534 8.92023 0.0341108 19.9369 9.73661e-05ZM4.19152 32.2527C7.45069 36.4516 12.3458 39.3173 17.9204 39.8932C16.5916 37.455 14.9338 33.717 13.5405 29.5901C10.4404 30.7762 7.25883 31.6027 4.19152 32.2527ZM22.9735 23.1135C22.1479 20.41 21.4462 17.5441 20.9225 14.277C20.746 13.5841 20.5918 12.8035 20.4593 11.9636C17.6508 12.6606 14.9992 13.4372 12.4356 14.2598C12.8479 17.4766 13.5448 21.1334 14.5118 24.7218C14.662 25.2792 14.8081 25.8248 14.9514 26.3594L14.9516 26.3603L14.9524 26.3634L14.9526 26.3639L14.973 26.4401C16.1833 25.9872 17.3746 25.5123 18.53 25.0259C20.1235 24.3552 21.6051 23.7165 22.9735 23.1135Z" fill="currentColor"/> +</svg> diff --git a/packages/ui/src/assets/icons/provider/nova.svg b/packages/ui/src/assets/icons/provider/nova.svg new file mode 100644 index 0000000000..9fcae228c0 --- /dev/null +++ b/packages/ui/src/assets/icons/provider/nova.svg @@ -0,0 +1,3 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"> + <path d="M13.48 17.46L14.64 18.62C14.69 18.67 14.71 18.75 14.68 18.82L12.87 23.41C12.73 23.76 12.38 24 12 24C11.62 24 11.27 23.76 11.13 23.41L8.52 16.80L4.31 21.02C4.24 21.09 4.12 21.09 4.05 21.02L2.98 19.95C2.91 19.88 2.91 19.76 2.98 19.69L8.18 14.49C8.35 14.32 8.58 14.21 8.81 14.19C9.23 14.17 9.60 14.42 9.74 14.78L12.00 20.51L13.18 17.52C13.23 17.40 13.39 17.37 13.49 17.46H13.48ZM19.69 2.98L15.48 7.20L12.87 0.59C12.71 0.17 12.26 -0.08 11.79 0.02C11.48 0.09 11.23 0.33 11.12 0.63L9.32 5.18C9.29 5.25 9.31 5.33 9.36 5.38L10.52 6.54C10.61 6.63 10.77 6.60 10.82 6.47L12 3.49L14.26 9.21C14.37 9.51 14.63 9.72 14.94 9.79C15.00 9.80 15.07 9.81 15.13 9.81C15.38 9.81 15.62 9.71 15.79 9.53L21.02 4.31C21.09 4.24 21.09 4.12 21.02 4.04L19.96 2.98C19.88 2.91 19.76 2.91 19.69 2.98L19.69 2.98ZM6.47 13.17L3.49 12.00L9.21 9.74C9.58 9.59 9.83 9.23 9.81 8.81C9.79 8.57 9.68 8.35 9.51 8.18L4.31 2.98C4.24 2.91 4.12 2.91 4.05 2.98L2.98 4.05C2.91 4.12 2.91 4.24 2.98 4.31L7.20 8.52L0.59 11.13C0.24 11.27 0 11.62 0 12.00C0 12.38 0.24 12.73 0.59 12.87L5.18 14.68C5.25 14.71 5.33 14.69 5.38 14.64L6.54 13.48C6.64 13.39 6.60 13.23 6.48 13.17H6.47ZM23.41 11.13L18.82 9.32C18.75 9.29 18.67 9.31 18.62 9.36L17.46 10.52C17.36 10.61 17.40 10.77 17.52 10.82L20.51 12.00L14.78 14.26C14.42 14.40 14.17 14.77 14.19 15.19C14.21 15.42 14.32 15.65 14.49 15.82L19.69 21.02C19.76 21.09 19.88 21.09 19.95 21.02L21.02 19.95C21.09 19.88 21.09 19.76 21.02 19.69L16.80 15.48L23.41 12.87C23.76 12.73 24 12.38 24 12.00C24 11.62 23.76 11.27 23.41 11.13V11.13Z"/> +</svg> diff --git a/packages/ui/src/assets/icons/provider/novita-ai.svg b/packages/ui/src/assets/icons/provider/novita-ai.svg new file mode 100644 index 0000000000..ac537b8dd4 --- /dev/null +++ b/packages/ui/src/assets/icons/provider/novita-ai.svg @@ -0,0 +1,10 @@ +<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg"> +<g clip-path="url(#clip0_3135_1230)"> +<path d="M15.5564 8.26172V16.5239L2.1875 29.8928H15.5564V21.6302L23.8194 29.8928H37.1875L15.5564 8.26172Z" fill="black"/> +</g> +<defs> +<clipPath id="clip0_3135_1230"> +<rect width="35" height="21.6311" fill="white" transform="translate(2.1875 8.26172)"/> +</clipPath> +</defs> +</svg> diff --git a/packages/ui/src/assets/icons/provider/opencode-go.svg b/packages/ui/src/assets/icons/provider/opencode-go.svg new file mode 100644 index 0000000000..e0833b9230 --- /dev/null +++ b/packages/ui/src/assets/icons/provider/opencode-go.svg @@ -0,0 +1,3 @@ +<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M19.4004 21H5V3H19.4004V6.59961H8.59961V17.4004H15.7998V13.7998H12.2002V10.2002H19.4004V21Z" fill="currentColor"/> +</svg> diff --git a/packages/ui/src/assets/icons/provider/opencode.svg b/packages/ui/src/assets/icons/provider/opencode.svg index 9e336ef2d7..9508465821 100644 --- a/packages/ui/src/assets/icons/provider/opencode.svg +++ b/packages/ui/src/assets/icons/provider/opencode.svg @@ -1,4 +1,3 @@ <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> -<path opacity="0.2" d="M19.2002 17.4H8.40017V13.8H15.6002V10.2H19.2002V17.4ZM8.40017 13.8H4.80017V10.2H8.40017V13.8Z" fill="currentColor"/> <path d="M8.40005 17.4H19.2001V21H4.80005V13.8H8.40005V17.4ZM15.6001 10.2V13.8H8.40005V10.2H15.6001ZM19.2001 10.2H15.6001V6.6H4.80005V3H19.2001V10.2Z" fill="currentColor"/> </svg> diff --git a/packages/ui/src/assets/icons/provider/privatemode-ai.svg b/packages/ui/src/assets/icons/provider/privatemode-ai.svg new file mode 100644 index 0000000000..edb5a6d764 --- /dev/null +++ b/packages/ui/src/assets/icons/provider/privatemode-ai.svg @@ -0,0 +1,5 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="61" height="63" viewBox="0 0 61 63" fill="none"> +<path d="M13.2167 6.71884C13.2167 10.4296 10.258 13.4377 6.60833 13.4377C2.95865 13.4377 0 10.4296 0 6.71884C0 3.00813 2.95865 0 6.60833 0C10.258 0 13.2167 3.00813 13.2167 6.71884Z" fill="currentColor"/> +<path d="M16.2667 22.7407H28.4667V62.0201H16.2667V22.7407Z" fill="currentColor"/> +<path fill-rule="evenodd" clip-rule="evenodd" d="M38.6333 33.0774C44.2482 33.0774 48.8 28.4495 48.8 22.7407C48.8 17.0319 44.2482 12.404 38.6333 12.404C33.0184 12.404 28.4667 17.0319 28.4667 22.7407C28.4667 28.4495 33.0184 33.0774 38.6333 33.0774ZM38.6333 45.4814C50.9861 45.4814 61 35.3 61 22.7407C61 10.1814 50.9861 0 38.6333 0C26.2806 0 16.2667 10.1814 16.2667 22.7407C16.2667 35.3 26.2806 45.4814 38.6333 45.4814Z" fill="currentColor"/> +</svg> \ No newline at end of file diff --git a/packages/ui/src/assets/icons/provider/qihang-ai.svg b/packages/ui/src/assets/icons/provider/qihang-ai.svg new file mode 100644 index 0000000000..3b356637a1 --- /dev/null +++ b/packages/ui/src/assets/icons/provider/qihang-ai.svg @@ -0,0 +1,9 @@ +<svg width="24" height="24" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg"> + <path + d="M20 2L36.4 11V29L20 38L3.6 29V11L20 2Z M20 20V2 M20 20L36.4 11 M20 20L36.4 29 M20 20V38 M20 20L3.6 29 M20 20L3.6 11" + stroke="currentColor" + stroke-width="3" + stroke-linecap="round" + stroke-linejoin="round" + /> +</svg> \ No newline at end of file diff --git a/packages/ui/src/assets/icons/provider/qiniu-ai.svg b/packages/ui/src/assets/icons/provider/qiniu-ai.svg new file mode 100644 index 0000000000..858560f9ff --- /dev/null +++ b/packages/ui/src/assets/icons/provider/qiniu-ai.svg @@ -0,0 +1,7 @@ +<svg viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> + <g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> + <g fill="currentColor" fill-rule="nonzero"> + <path d="M23.568,4.37284513 C23.180619,4.24052218 22.8592977,4.40224993 22.6756964,4.54008596 C20.1236928,7.55961616 16.310265,9.47645197 12.0489207,9.47645197 C10.5856349,9.47645197 9.17375432,9.25040654 7.84814258,8.82954254 C7.5029753,7.57615888 7.25878488,6.68481809 7.25878488,6.68481809 C7.25878488,6.68481809 6.97237307,5.81185554 6.00112785,5.96071698 L6.28019714,8.22306831 C4.39829587,7.36296976 2.74038351,6.09854994 1.42029592,4.53641031 C1.23669698,4.39857428 0.915396329,4.23684654 0.528,4.36916956 C1.62959981,7.32069904 3.8328071,9.73559053 6.63638202,11.1121076 L7.40015707,17.309184 C7.40015707,17.309184 7.74165693,19.68 9.96508874,19.68 L14.7184659,19.68 C16.9418594,19.68 17.2833592,17.309184 17.2833592,17.309184 L17.8212733,12.8690689 C16.3782427,12.7514113 15.4693667,13.7585665 15.1829548,14.7509761 C14.7001288,16.4233728 14.7001288,16.5318144 14.6046071,16.8221952 C14.4100343,17.4194688 13.7692329,17.4912 13.7692329,17.4912 L10.9179278,17.4912 C10.9179278,17.4912 10.2772032,17.4194688 10.0825536,16.8221952 C9.95772321,16.4381184 9.32981155,14.1868033 8.69821712,11.9023719 C9.76307366,12.2037505 10.8885424,12.3654913 12.0507621,12.3654913 C17.3237162,12.3710209 21.8219851,9.04456718 23.568,4.37284513 Z"></path> + </g> + </g> +</svg> diff --git a/packages/ui/src/assets/icons/provider/stackit.svg b/packages/ui/src/assets/icons/provider/stackit.svg new file mode 100644 index 0000000000..0d78b781ac --- /dev/null +++ b/packages/ui/src/assets/icons/provider/stackit.svg @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="UTF-8"?> +<svg id="STACKIT" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 41.536063 41.536063"> + <path d="M13.9510149,10.4421038h20.8374634l-1.1608887,5.4412842h-14.5545654l-1.3522339,6.3352661h-6.2828369l2.5130615-11.7765503ZM22.5114397,25.652614H7.9081072l-1.1605225,5.4413452h20.8855591l2.5210571-11.8130493h-6.2828979l-1.3598633,6.3717041Z" fill="currentColor"/> +</svg> diff --git a/packages/ui/src/assets/icons/provider/stepfun.svg b/packages/ui/src/assets/icons/provider/stepfun.svg new file mode 100644 index 0000000000..086e9aa1fc --- /dev/null +++ b/packages/ui/src/assets/icons/provider/stepfun.svg @@ -0,0 +1,24 @@ +<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> + <path + shape-rendering="geometricPrecision" + d="M9.8132 15.9038L9 18.75L8.1868 15.9038C7.75968 14.4089 6.59112 13.2403 5.09619 12.8132L2.25 12L5.09619 11.1868C6.59113 10.7597 7.75968 9.59112 8.1868 8.09619L9 5.25L9.8132 8.09619C10.2403 9.59113 11.4089 10.7597 12.9038 11.1868L15.75 12L12.9038 12.8132C11.4089 13.2403 10.2403 14.4089 9.8132 15.9038Z" + stroke="currentColor" + stroke-width="1.5" + stroke-linecap="round" + stroke-linejoin="round" + /> + <path + d="M18.2589 8.71454L18 9.75L17.7411 8.71454C17.4388 7.50533 16.4947 6.56117 15.2855 6.25887L14.25 6L15.2855 5.74113C16.4947 5.43883 17.4388 4.49467 17.7411 3.28546L18 2.25L18.2589 3.28546C18.5612 4.49467 19.5053 5.43883 20.7145 5.74113L21.75 6L20.7145 6.25887C19.5053 6.56117 18.5612 7.50533 18.2589 8.71454Z" + stroke="currentColor" + stroke-width="1.5" + stroke-linecap="round" + stroke-linejoin="round" + /> + <path + d="M16.8942 20.5673L16.5 21.75L16.1058 20.5673C15.8818 19.8954 15.3546 19.3682 14.6827 19.1442L13.5 18.75L14.6827 18.3558C15.3546 18.1318 15.8818 17.6046 16.1058 16.9327L16.5 15.75L16.8942 16.9327C17.1182 17.6046 17.6454 18.1318 18.3173 18.3558L19.5 18.75L18.3173 19.1442C17.6454 19.3682 17.1182 19.8954 16.8942 20.5673Z" + stroke="currentColor" + stroke-width="1.5" + stroke-linecap="round" + stroke-linejoin="round" + /> +</svg> diff --git a/packages/ui/src/assets/icons/provider/vivgrid.svg b/packages/ui/src/assets/icons/provider/vivgrid.svg new file mode 100644 index 0000000000..928fa3ff1e --- /dev/null +++ b/packages/ui/src/assets/icons/provider/vivgrid.svg @@ -0,0 +1,4 @@ +<svg width="24px" height="24px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M 10.921 1.266 C 11.477 0.952 12.161 0.952 12.717 1.266 L 14.079 2.037 C 12.108 3.127 9.934 4.437 8.274 5.788 C 7.425 6.479 6.706 7.185 6.216 7.879 C 5.727 8.574 5.458 9.268 5.53 9.935 C 5.625 10.839 6.133 11.432 6.825 11.858 C 7.512 12.283 8.388 12.55 9.232 12.809 C 9.968 13.033 10.681 13.253 11.245 13.56 C 11.808 13.868 12.214 14.257 12.353 14.819 C 12.492 15.384 12.369 16.145 11.825 17.206 C 11.286 18.255 10.342 19.586 8.861 21.293 L 2.91 17.924 C 2.356 17.608 2.013 17.028 2.013 16.398 L 2.013 7.327 C 2.013 6.697 2.356 6.116 2.91 5.802 L 10.921 1.266 Z" fill="currentColor" stroke="currentColor"/> +<path d="M 21.122 6.009 C 21.677 6.324 22.019 6.904 22.019 7.534 L 22.019 16.606 C 22.019 17.235 21.677 17.816 21.122 18.131 L 13.11 22.667 C 12.555 22.981 11.872 22.981 11.314 22.667 L 10.388 22.142 C 10.772 21.78 11.159 21.413 11.55 21.047 C 12.722 19.945 13.901 18.834 14.928 17.765 C 15.953 16.698 16.825 15.667 17.382 14.721 C 17.936 13.778 18.187 12.902 17.93 12.154 C 17.671 11.401 16.913 10.813 15.54 10.415 C 13.986 9.966 12.92 9.457 12.272 8.908 C 11.628 8.362 11.403 7.78 11.507 7.17 C 11.617 6.55 12.069 5.883 12.824 5.18 C 13.572 4.488 14.606 3.77 15.874 3.039 L 21.122 6.009 Z" fill="currentColor" stroke="currentColor"/> +</svg> diff --git a/packages/ui/src/components/accordion.stories.tsx b/packages/ui/src/components/accordion.stories.tsx new file mode 100644 index 0000000000..c53b6d3da9 --- /dev/null +++ b/packages/ui/src/components/accordion.stories.tsx @@ -0,0 +1,149 @@ +// @ts-nocheck +import { createEffect, createSignal } from "solid-js" +import * as mod from "./accordion" +import { create } from "../storybook/scaffold" + +const docs = `### Overview +Accordion for collapsible content sections with optional multi-open behavior. + +Use one trigger per item; keep content concise. + +### API +- Root supports Kobalte Accordion props: \`value\`, \`multiple\`, \`collapsible\`, \`onChange\`. +- Compose with \`Accordion.Item\`, \`Header\`, \`Trigger\`, \`Content\`. + +### Variants and states +- Single or multiple open items. +- Collapsible or fixed-open behavior. + +### Behavior +- Controlled via \`value\`/\`onChange\` when provided. + +### Accessibility +- TODO: confirm keyboard navigation from Kobalte Accordion. + +### Theming/tokens +- Uses \`data-component="accordion"\` and slot data attributes. + +` + +const story = create({ title: "UI/Accordion", mod }) +export default { + title: "UI/Accordion", + id: "components-accordion", + component: story.meta.component, + tags: ["autodocs"], + parameters: { + docs: { + description: { + component: docs, + }, + }, + }, +} +export const Basic = { + args: { + collapsible: true, + multiple: false, + value: "first", + }, + argTypes: { + collapsible: { control: "boolean" }, + multiple: { control: "boolean" }, + value: { + control: "select", + options: ["first", "second", "none"], + mapping: { + none: undefined, + }, + }, + }, + render: (props) => { + const [value, setValue] = createSignal(props.value) + createEffect(() => { + setValue(props.value) + }) + + const current = () => { + if (props.multiple) { + if (Array.isArray(value())) return value() + if (value()) return [value()] + return [] + } + + if (Array.isArray(value())) return value()[0] + return value() + } + + return ( + <div style={{ display: "grid", gap: "8px", width: "420px" }}> + <mod.Accordion collapsible={props.collapsible} multiple={props.multiple} value={current()} onChange={setValue}> + <mod.Accordion.Item value="first"> + <mod.Accordion.Header> + <mod.Accordion.Trigger>First</mod.Accordion.Trigger> + </mod.Accordion.Header> + <mod.Accordion.Content> + <div style={{ color: "var(--text-weak)", padding: "8px 0" }}>Accordion content.</div> + </mod.Accordion.Content> + </mod.Accordion.Item> + <mod.Accordion.Item value="second"> + <mod.Accordion.Header> + <mod.Accordion.Trigger>Second</mod.Accordion.Trigger> + </mod.Accordion.Header> + <mod.Accordion.Content> + <div style={{ color: "var(--text-weak)", padding: "8px 0" }}>More content.</div> + </mod.Accordion.Content> + </mod.Accordion.Item> + </mod.Accordion> + </div> + ) + }, +} + +export const Multiple = { + args: { + collapsible: true, + multiple: true, + value: ["first", "second"], + }, + render: (props) => ( + <mod.Accordion collapsible={props.collapsible} multiple={props.multiple} value={props.value}> + <mod.Accordion.Item value="first"> + <mod.Accordion.Header> + <mod.Accordion.Trigger>First</mod.Accordion.Trigger> + </mod.Accordion.Header> + <mod.Accordion.Content> + <div style={{ color: "var(--text-weak)", padding: "8px 0" }}>Accordion content.</div> + </mod.Accordion.Content> + </mod.Accordion.Item> + <mod.Accordion.Item value="second"> + <mod.Accordion.Header> + <mod.Accordion.Trigger>Second</mod.Accordion.Trigger> + </mod.Accordion.Header> + <mod.Accordion.Content> + <div style={{ color: "var(--text-weak)", padding: "8px 0" }}>More content.</div> + </mod.Accordion.Content> + </mod.Accordion.Item> + </mod.Accordion> + ), +} + +export const NonCollapsible = { + args: { + collapsible: false, + multiple: false, + value: "first", + }, + render: (props) => ( + <mod.Accordion collapsible={props.collapsible} multiple={props.multiple} value={props.value}> + <mod.Accordion.Item value="first"> + <mod.Accordion.Header> + <mod.Accordion.Trigger>First</mod.Accordion.Trigger> + </mod.Accordion.Header> + <mod.Accordion.Content> + <div style={{ color: "var(--text-weak)", padding: "8px 0" }}>Accordion content.</div> + </mod.Accordion.Content> + </mod.Accordion.Item> + </mod.Accordion> + ), +} diff --git a/packages/ui/src/components/animated-number.css b/packages/ui/src/components/animated-number.css new file mode 100644 index 0000000000..022b347e96 --- /dev/null +++ b/packages/ui/src/components/animated-number.css @@ -0,0 +1,75 @@ +[data-component="animated-number"] { + display: inline-flex; + align-items: baseline; + vertical-align: baseline; + line-height: inherit; + font-variant-numeric: tabular-nums; + + [data-slot="animated-number-value"] { + display: inline-flex; + flex-direction: row-reverse; + align-items: baseline; + justify-content: flex-end; + line-height: inherit; + width: var(--animated-number-width, 1ch); + overflow: hidden; + transition: width var(--tool-motion-spring-ms, 560ms) var(--tool-motion-ease, cubic-bezier(0.22, 1, 0.36, 1)); + } + + [data-slot="animated-number-digit"] { + display: inline-block; + width: 1ch; + height: 1em; + line-height: 1em; + overflow: hidden; + vertical-align: baseline; + -webkit-mask-image: linear-gradient( + to bottom, + transparent 0%, + #000 var(--tool-motion-mask, 18%), + #000 calc(100% - var(--tool-motion-mask, 18%)), + transparent 100% + ); + mask-image: linear-gradient( + to bottom, + transparent 0%, + #000 var(--tool-motion-mask, 18%), + #000 calc(100% - var(--tool-motion-mask, 18%)), + transparent 100% + ); + -webkit-mask-repeat: no-repeat; + mask-repeat: no-repeat; + } + + [data-slot="animated-number-strip"] { + display: inline-flex; + flex-direction: column; + transform: translateY(calc(var(--animated-number-offset, 10) * -1em)); + transition-property: transform; + transition-duration: var(--animated-number-duration, 560ms); + transition-timing-function: var(--tool-motion-ease, cubic-bezier(0.22, 1, 0.36, 1)); + } + + [data-slot="animated-number-strip"][data-animating="false"] { + transition-duration: 0ms; + } + + [data-slot="animated-number-cell"] { + display: inline-flex; + align-items: center; + justify-content: center; + width: 1ch; + height: 1em; + line-height: 1em; + } +} + +@media (prefers-reduced-motion: reduce) { + [data-component="animated-number"] [data-slot="animated-number-value"] { + transition-duration: 0ms; + } + + [data-component="animated-number"] [data-slot="animated-number-strip"] { + transition-duration: 0ms; + } +} diff --git a/packages/ui/src/components/animated-number.tsx b/packages/ui/src/components/animated-number.tsx new file mode 100644 index 0000000000..b5fceba256 --- /dev/null +++ b/packages/ui/src/components/animated-number.tsx @@ -0,0 +1,100 @@ +import { For, Index, createEffect, createMemo, createSignal, on } from "solid-js" + +const TRACK = Array.from({ length: 30 }, (_, index) => index % 10) +const DURATION = 600 + +function normalize(value: number) { + return ((value % 10) + 10) % 10 +} + +function spin(from: number, to: number, direction: 1 | -1) { + if (from === to) return 0 + if (direction > 0) return (to - from + 10) % 10 + return -((from - to + 10) % 10) +} + +function Digit(props: { value: number; direction: 1 | -1 }) { + const [step, setStep] = createSignal(props.value + 10) + const [animating, setAnimating] = createSignal(false) + let last = props.value + + createEffect( + on( + () => props.value, + (next) => { + const delta = spin(last, next, props.direction) + last = next + if (!delta) { + setAnimating(false) + setStep(next + 10) + return + } + + setAnimating(true) + setStep((value) => value + delta) + }, + { defer: true }, + ), + ) + + return ( + <span data-slot="animated-number-digit"> + <span + data-slot="animated-number-strip" + data-animating={animating() ? "true" : "false"} + onTransitionEnd={() => { + setAnimating(false) + setStep((value) => normalize(value) + 10) + }} + style={{ + "--animated-number-offset": `${step()}`, + "--animated-number-duration": `var(--tool-motion-odometer-ms, ${DURATION}ms)`, + }} + > + <For each={TRACK}>{(value) => <span data-slot="animated-number-cell">{value}</span>}</For> + </span> + </span> + ) +} + +export function AnimatedNumber(props: { value: number; class?: string }) { + const target = createMemo(() => { + if (!Number.isFinite(props.value)) return 0 + return Math.max(0, Math.round(props.value)) + }) + + const [value, setValue] = createSignal(target()) + const [direction, setDirection] = createSignal<1 | -1>(1) + + createEffect( + on( + target, + (next) => { + const current = value() + if (next === current) return + + setDirection(next > current ? 1 : -1) + setValue(next) + }, + { defer: true }, + ), + ) + + const label = createMemo(() => value().toString()) + const digits = createMemo(() => + Array.from(label(), (char) => { + const code = char.charCodeAt(0) - 48 + if (code < 0 || code > 9) return 0 + return code + }).reverse(), + ) + const width = createMemo(() => `${digits().length}ch`) + + return ( + <span data-component="animated-number" class={props.class} aria-label={label()}> + <span data-slot="animated-number-value" style={{ "--animated-number-width": width() }}> + <Index each={digits()}>{(digit) => <Digit value={digit()} direction={direction()} />}</Index> + </span> + </span> + ) +} diff --git a/packages/ui/src/components/app-icon.stories.tsx b/packages/ui/src/components/app-icon.stories.tsx new file mode 100644 index 0000000000..24460b6da2 --- /dev/null +++ b/packages/ui/src/components/app-icon.stories.tsx @@ -0,0 +1,69 @@ +// @ts-nocheck +import { iconNames } from "./app-icons/types" +import * as mod from "./app-icon" +import { create } from "../storybook/scaffold" + +const docs = `### Overview +Application icon renderer for known editor/terminal apps. + +Use in provider or app selection lists. + +### API +- Required: \`id\` (app icon name). +- Accepts standard img props except \`src\`. + +### Variants and states +- Auto-switches themed icons when available. + +### Behavior +- Watches color scheme changes to swap themed assets. + +### Accessibility +- Provide \`alt\` text when the icon conveys meaning. + +### Theming/tokens +- Uses \`data-component="app-icon"\`. + +` + +const story = create({ title: "UI/AppIcon", mod, args: { id: "vscode" } }) +export default { + title: "UI/AppIcon", + id: "components-app-icon", + component: story.meta.component, + tags: ["autodocs"], + parameters: { + docs: { + description: { + component: docs, + }, + }, + }, + argTypes: { + id: { + control: "select", + options: iconNames, + }, + }, +} + +export const Basic = story.Basic + +export const AllIcons = { + render: () => ( + <div + style={{ + display: "grid", + gap: "12px", + "grid-template-columns": "repeat(auto-fill, minmax(72px, 1fr))", + }} + > + {iconNames.map((id) => ( + <div style={{ display: "grid", gap: "6px", "justify-items": "center" }}> + <mod.AppIcon id={id} alt={id} /> + <div style={{ "font-size": "10px", color: "var(--text-weak)", "text-align": "center" }}>{id}</div> + </div> + ))} + </div> + ), +} diff --git a/packages/ui/src/components/app-icon.tsx b/packages/ui/src/components/app-icon.tsx index e91638b989..f8b587ff26 100644 --- a/packages/ui/src/components/app-icon.tsx +++ b/packages/ui/src/components/app-icon.tsx @@ -13,6 +13,7 @@ import powershell from "../assets/icons/app/powershell.svg" import terminal from "../assets/icons/app/terminal.png" import textmate from "../assets/icons/app/textmate.png" import vscode from "../assets/icons/app/vscode.svg" +import warp from "../assets/icons/app/warp.png" import xcode from "../assets/icons/app/xcode.png" import zed from "../assets/icons/app/zed.svg" import zedDark from "../assets/icons/app/zed-dark.svg" @@ -27,6 +28,7 @@ const icons = { terminal, iterm2, ghostty, + warp, xcode, "android-studio": androidStudio, antigravity, diff --git a/packages/ui/src/components/app-icons/types.ts b/packages/ui/src/components/app-icons/types.ts index a0343c25b7..4fb3abf39c 100644 --- a/packages/ui/src/components/app-icons/types.ts +++ b/packages/ui/src/components/app-icons/types.ts @@ -9,6 +9,7 @@ export const iconNames = [ "terminal", "iterm2", "ghostty", + "warp", "xcode", "android-studio", "antigravity", diff --git a/packages/ui/src/components/avatar.stories.tsx b/packages/ui/src/components/avatar.stories.tsx new file mode 100644 index 0000000000..044224ae8c --- /dev/null +++ b/packages/ui/src/components/avatar.stories.tsx @@ -0,0 +1,76 @@ +// @ts-nocheck +import * as mod from "./avatar" +import { create } from "../storybook/scaffold" + +const docs = `### Overview +User avatar with image fallback to initials. + +Use in user lists and headers. + +### API +- Required: \`fallback\` string. +- Optional: \`src\`, \`background\`, \`foreground\`, \`size\`. + +### Variants and states +- Sizes: small, normal, large. +- Image vs fallback state. + +### Behavior +- Uses grapheme-aware fallback rendering. + +### Accessibility +- TODO: provide alt text when using images; currently image is decorative. + +### Theming/tokens +- Uses \`data-component="avatar"\` with size and image state attributes. + +` + +const story = create({ title: "UI/Avatar", mod, args: { fallback: "A" } }) + +export default { + title: "UI/Avatar", + id: "components-avatar", + component: story.meta.component, + tags: ["autodocs"], + parameters: { + docs: { + description: { + component: docs, + }, + }, + }, + argTypes: { + size: { + control: "select", + options: ["small", "normal", "large"], + }, + }, +} + +export const Basic = story.Basic + +export const WithImage = { + args: { + src: "https://placehold.co/80x80/png", + fallback: "J", + }, +} + +export const Sizes = { + render: () => ( + <div style={{ display: "flex", gap: "12px", "align-items": "center" }}> + <mod.Avatar size="small" fallback="S" /> + <mod.Avatar size="normal" fallback="N" /> + <mod.Avatar size="large" fallback="L" /> + </div> + ), +} + +export const CustomColors = { + args: { + fallback: "C", + background: "#1f2a44", + foreground: "#f2f5ff", + }, +} diff --git a/packages/ui/src/components/basic-tool.css b/packages/ui/src/components/basic-tool.css index 1240ad7b99..1dbfce26ec 100644 --- a/packages/ui/src/components/basic-tool.css +++ b/packages/ui/src/components/basic-tool.css @@ -64,7 +64,7 @@ [data-slot="basic-tool-tool-info-main"] { display: flex; - align-items: center; + align-items: baseline; gap: 8px; min-width: 0; overflow: hidden; @@ -97,6 +97,7 @@ text-overflow: ellipsis; white-space: nowrap; font-family: var(--font-family-sans); + font-variant-numeric: tabular-nums; font-size: 14px; font-style: normal; font-weight: var(--font-weight-regular); @@ -142,6 +143,7 @@ text-overflow: ellipsis; white-space: nowrap; font-family: var(--font-family-sans); + font-variant-numeric: tabular-nums; font-size: 14px; font-style: normal; font-weight: var(--font-weight-regular); diff --git a/packages/ui/src/components/basic-tool.stories.tsx b/packages/ui/src/components/basic-tool.stories.tsx new file mode 100644 index 0000000000..9d9d97acfe --- /dev/null +++ b/packages/ui/src/components/basic-tool.stories.tsx @@ -0,0 +1,133 @@ +// @ts-nocheck +import { createSignal } from "solid-js" +import * as mod from "./basic-tool" +import { create } from "../storybook/scaffold" + +const docs = `### Overview +Expandable tool panel with a structured trigger and optional details. + +Use structured triggers for consistent layout; custom triggers allowed. + +### API +- Required: \`icon\` and \`trigger\` (structured or custom JSX). +- Optional: \`status\`, \`defaultOpen\`, \`forceOpen\`, \`defer\`, \`locked\`. + +### Variants and states +- Pending/running status animates the title via TextShimmer. + +### Behavior +- Uses Collapsible; can defer content rendering until open. +- Locked state prevents closing. + +### Accessibility +- TODO: confirm trigger semantics and aria labeling. + +### Theming/tokens +- Uses \`data-component="tool-trigger"\` and related slots. + +` + +const story = create({ + title: "UI/Basic Tool", + mod, + args: { + icon: "mcp", + defaultOpen: true, + trigger: { + title: "Basic Tool", + subtitle: "Example subtitle", + args: ["--flag", "value"], + }, + children: "Details content", + }, +}) + +export default { + title: "UI/Basic Tool", + id: "components-basic-tool", + component: story.meta.component, + tags: ["autodocs"], + parameters: { + docs: { + description: { + component: docs, + }, + }, + }, +} + +export const Basic = story.Basic + +export const Pending = { + args: { + status: "pending", + trigger: { + title: "Running tool", + subtitle: "Working...", + }, + children: "Progress details", + }, +} + +export const Locked = { + args: { + locked: true, + trigger: { + title: "Locked tool", + subtitle: "Cannot close", + }, + children: "Locked details", + }, +} + +export const Deferred = { + args: { + defer: true, + defaultOpen: false, + trigger: { + title: "Deferred tool", + subtitle: "Content mounts on open", + }, + children: "Deferred content", + }, +} + +export const ForceOpen = { + args: { + forceOpen: true, + trigger: { + title: "Forced open", + subtitle: "Cannot close", + }, + children: "Forced content", + }, +} + +export const HideDetails = { + args: { + hideDetails: true, + trigger: { + title: "Summary only", + subtitle: "Details hidden", + }, + children: "Hidden content", + }, +} + +export const SubtitleAction = { + render: () => { + const [message, setMessage] = createSignal("Subtitle not clicked") + return ( + <div style={{ display: "grid", gap: "8px" }}> + <div style={{ "font-size": "12px", color: "var(--text-weak)" }}>{message()}</div> + <mod.BasicTool + icon="mcp" + trigger={{ title: "Clickable subtitle", subtitle: "Click me" }} + onSubtitleClick={() => setMessage("Subtitle clicked")} + > + Subtitle action details + </mod.BasicTool> + </div> + ) + }, +} diff --git a/packages/ui/src/components/basic-tool.tsx b/packages/ui/src/components/basic-tool.tsx index 53bdc9ce1e..4ad91824da 100644 --- a/packages/ui/src/components/basic-tool.tsx +++ b/packages/ui/src/components/basic-tool.tsx @@ -1,4 +1,5 @@ import { createEffect, createSignal, For, Match, on, onCleanup, Show, Switch, type JSX } from "solid-js" +import { animate, type AnimationPlaybackControls } from "motion" import { Collapsible } from "./collapsible" import type { IconProps } from "./icon" import { TextShimmer } from "./text-shimmer" @@ -29,9 +30,12 @@ export interface BasicToolProps { forceOpen?: boolean defer?: boolean locked?: boolean + animated?: boolean onSubtitleClick?: () => void } +const SPRING = { type: "spring" as const, visualDuration: 0.35, bounce: 0 } + export function BasicTool(props: BasicToolProps) { const [open, setOpen] = createSignal(props.defaultOpen ?? false) const [ready, setReady] = createSignal(open()) @@ -73,6 +77,38 @@ export function BasicTool(props: BasicToolProps) { ), ) + // Animated height for collapsible open/close + let contentRef: HTMLDivElement | undefined + let heightAnim: AnimationPlaybackControls | undefined + const initialOpen = open() + + createEffect( + on( + open, + (isOpen) => { + if (!props.animated || !contentRef) return + heightAnim?.stop() + if (isOpen) { + contentRef.style.overflow = "hidden" + heightAnim = animate(contentRef, { height: "auto" }, SPRING) + heightAnim.finished.then(() => { + if (!contentRef || !open()) return + contentRef.style.overflow = "visible" + contentRef.style.height = "auto" + }) + } else { + contentRef.style.overflow = "hidden" + heightAnim = animate(contentRef, { height: "0px" }, SPRING) + } + }, + { defer: true }, + ), + ) + + onCleanup(() => { + heightAnim?.stop() + }) + const handleOpenChange = (value: boolean) => { if (pending()) return if (props.locked && !value) return @@ -96,9 +132,7 @@ export function BasicTool(props: BasicToolProps) { [trigger().titleClass ?? ""]: !!trigger().titleClass, }} > - <Show when={pending()} fallback={trigger().title}> - <TextShimmer text={trigger().title} /> - </Show> + <TextShimmer text={trigger().title} active={pending()} /> </span> <Show when={!pending()}> <Show when={trigger().subtitle}> @@ -147,7 +181,20 @@ export function BasicTool(props: BasicToolProps) { </Show> </div> </Collapsible.Trigger> - <Show when={props.children && !props.hideDetails}> + <Show when={props.animated && props.children && !props.hideDetails}> + <div + ref={contentRef} + data-slot="collapsible-content" + data-animated + style={{ + height: initialOpen ? "auto" : "0px", + overflow: initialOpen ? "visible" : "hidden", + }} + > + {props.children} + </div> + </Show> + <Show when={!props.animated && props.children && !props.hideDetails}> <Collapsible.Content> <Show when={!props.defer || ready()}>{props.children}</Show> </Collapsible.Content> @@ -156,6 +203,41 @@ export function BasicTool(props: BasicToolProps) { ) } -export function GenericTool(props: { tool: string; status?: string; hideDetails?: boolean }) { - return <BasicTool icon="mcp" status={props.status} trigger={{ title: props.tool }} hideDetails={props.hideDetails} /> +function label(input: Record<string, unknown> | undefined) { + const keys = ["description", "query", "url", "filePath", "path", "pattern", "name"] + return keys.map((key) => input?.[key]).find((value): value is string => typeof value === "string" && value.length > 0) +} + +function args(input: Record<string, unknown> | undefined) { + if (!input) return [] + const skip = new Set(["description", "query", "url", "filePath", "path", "pattern", "name"]) + return Object.entries(input) + .filter(([key]) => !skip.has(key)) + .flatMap(([key, value]) => { + if (typeof value === "string") return [`${key}=${value}`] + if (typeof value === "number") return [`${key}=${value}`] + if (typeof value === "boolean") return [`${key}=${value}`] + return [] + }) + .slice(0, 3) +} + +export function GenericTool(props: { + tool: string + status?: string + hideDetails?: boolean + input?: Record<string, unknown> +}) { + return ( + <BasicTool + icon="mcp" + status={props.status} + trigger={{ + title: `Called \`${props.tool}\``, + subtitle: label(props.input), + args: args(props.input), + }} + hideDetails={props.hideDetails} + /> + ) } diff --git a/packages/ui/src/components/button.stories.tsx b/packages/ui/src/components/button.stories.tsx new file mode 100644 index 0000000000..24fad5c8a0 --- /dev/null +++ b/packages/ui/src/components/button.stories.tsx @@ -0,0 +1,108 @@ +// @ts-nocheck +import { Button } from "./button" + +const docs = `### Overview +Primary action button with size, variant, and optional icon support. + +Use \`IconButton\` for icon-only actions. + +### API +- \`variant\`: "primary" | "secondary" | "ghost". +- \`size\`: "small" | "normal" | "large". +- \`icon\`: Icon name for a leading icon. +- Inherits Kobalte Button props and native button attributes. + +### Variants and states +- Variants: primary, secondary, ghost. +- States: disabled. + +### Behavior +- Renders an Icon when \`icon\` is set. + +### Accessibility +- Provide clear label text; use \`aria-label\` for icon-only buttons. + +### Theming/tokens +- Uses \`data-component="button"\` with size/variant data attributes. + +` + +export default { + title: "UI/Button", + id: "components-button", + component: Button, + tags: ["autodocs"], + parameters: { + docs: { + description: { + component: docs, + }, + }, + }, + args: { + children: "Button", + variant: "secondary", + size: "normal", + }, + argTypes: { + variant: { + control: "select", + options: ["primary", "secondary", "ghost"], + }, + size: { + control: "select", + options: ["small", "normal", "large"], + }, + icon: { + control: "select", + options: ["none", "check", "plus", "arrow-right"], + mapping: { + none: undefined, + }, + }, + }, +} + +export const Primary = { + args: { + variant: "primary", + }, +} + +export const Secondary = {} + +export const Ghost = { + args: { + variant: "ghost", + }, +} + +export const WithIcon = { + args: { + children: "Continue", + icon: "arrow-right", + }, +} + +export const Disabled = { + args: { + variant: "primary", + disabled: true, + }, +} + +export const Sizes = { + render: () => ( + <div style={{ display: "flex", gap: "12px", "align-items": "center" }}> + <Button size="small" variant="secondary"> + Small + </Button> + <Button size="normal" variant="secondary"> + Normal + </Button> + <Button size="large" variant="secondary"> + Large + </Button> + </div> + ), +} diff --git a/packages/ui/src/components/card.stories.tsx b/packages/ui/src/components/card.stories.tsx new file mode 100644 index 0000000000..befb2d34fc --- /dev/null +++ b/packages/ui/src/components/card.stories.tsx @@ -0,0 +1,90 @@ +// @ts-nocheck +import { Card } from "./card" +import { Button } from "./button" + +const docs = `### Overview +Surface container for grouping related content and actions. + +Pair with \`Button\` or \`Tag\` for quick actions. + +### API +- Optional: \`variant\` (normal, error, warning, success, info). +- Accepts standard div props. + +### Variants and states +- Semantic variants for status-driven messaging. + +### Behavior +- Pure presentational container. + +### Accessibility +- Provide headings or aria labels when used in isolation. + +### Theming/tokens +- Uses \`data-component="card"\` with variant data attributes. + +` + +export default { + title: "UI/Card", + id: "components-card", + component: Card, + tags: ["autodocs"], + parameters: { + docs: { + description: { + component: docs, + }, + }, + }, + args: { + variant: "normal", + }, + argTypes: { + variant: { + control: "select", + options: ["normal", "error", "warning", "success", "info"], + }, + }, + render: (props: { variant?: "normal" | "error" | "warning" | "success" | "info" }) => { + return ( + <Card variant={props.variant}> + <div style={{ display: "flex", alignItems: "center", gap: "12px" }}> + <div style={{ flex: 1 }}> + <div style={{ fontWeight: 500 }}>Card title</div> + <div style={{ color: "var(--text-weak)", fontSize: "13px" }}>Small supporting text.</div> + </div> + <Button size="small" variant="ghost"> + Action + </Button> + </div> + </Card> + ) + }, +} + +export const Normal = {} + +export const Error = { + args: { + variant: "error", + }, +} + +export const Warning = { + args: { + variant: "warning", + }, +} + +export const Success = { + args: { + variant: "success", + }, +} + +export const Info = { + args: { + variant: "info", + }, +} diff --git a/packages/ui/src/components/checkbox.css b/packages/ui/src/components/checkbox.css index 82994bb88a..3041799659 100644 --- a/packages/ui/src/components/checkbox.css +++ b/packages/ui/src/components/checkbox.css @@ -28,6 +28,10 @@ flex-shrink: 0; border-radius: var(--radius-sm); border: 1px solid var(--border-weak-base); + transition: + border-color 220ms var(--tool-motion-ease, cubic-bezier(0.22, 1, 0.36, 1)), + background-color 220ms var(--tool-motion-ease, cubic-bezier(0.22, 1, 0.36, 1)), + box-shadow 220ms var(--tool-motion-ease, cubic-bezier(0.22, 1, 0.36, 1)); /* background-color: var(--surface-weak); */ } @@ -39,6 +43,10 @@ height: 100%; color: var(--icon-base); opacity: 0; + transform: scale(0.9); + transition: + opacity 180ms var(--tool-motion-ease, cubic-bezier(0.22, 1, 0.36, 1)), + transform 220ms var(--tool-motion-ease, cubic-bezier(0.22, 1, 0.36, 1)); } /* [data-slot="checkbox-checkbox-content"] { */ @@ -100,6 +108,7 @@ &[data-checked] [data-slot="checkbox-checkbox-indicator"], &[data-indeterminate] [data-slot="checkbox-checkbox-indicator"] { opacity: 1; + transform: scale(1); } &[data-disabled] { diff --git a/packages/ui/src/components/checkbox.stories.tsx b/packages/ui/src/components/checkbox.stories.tsx new file mode 100644 index 0000000000..ceb09f103e --- /dev/null +++ b/packages/ui/src/components/checkbox.stories.tsx @@ -0,0 +1,71 @@ +// @ts-nocheck +import { Icon } from "./icon" +import * as mod from "./checkbox" +import { create } from "../storybook/scaffold" + +const docs = `### Overview +Checkbox control for multi-select or agreement inputs. + +Use in forms and multi-select lists. + +### API +- Uses Kobalte Checkbox props (\`checked\`, \`defaultChecked\`, \`onChange\`). +- Optional: \`hideLabel\`, \`description\`, \`icon\`. +- Children render as the label. + +### Variants and states +- Checked/unchecked, indeterminate, disabled (via Kobalte). + +### Behavior +- Controlled or uncontrolled usage. + +### Accessibility +- TODO: confirm aria attributes from Kobalte. + +### Theming/tokens +- Uses \`data-component="checkbox"\` and related slots. + +` + +const story = create({ title: "UI/Checkbox", mod, args: { children: "Checkbox", defaultChecked: true } }) +export default { + title: "UI/Checkbox", + id: "components-checkbox", + component: story.meta.component, + tags: ["autodocs"], + parameters: { + docs: { + description: { + component: docs, + }, + }, + }, +} + +export const Basic = story.Basic + +export const States = { + render: () => ( + <div style={{ display: "grid", gap: "12px" }}> + <mod.Checkbox defaultChecked>Checked</mod.Checkbox> + <mod.Checkbox>Unchecked</mod.Checkbox> + <mod.Checkbox disabled>Disabled</mod.Checkbox> + <mod.Checkbox description="Helper text">With description</mod.Checkbox> + </div> + ), +} + +export const CustomIcon = { + render: () => ( + <mod.Checkbox icon={<Icon name="check" size="small" />} defaultChecked> + Custom icon + </mod.Checkbox> + ), +} + +export const HiddenLabel = { + args: { + children: "Hidden label", + hideLabel: true, + }, +} diff --git a/packages/ui/src/components/code.css b/packages/ui/src/components/code.css deleted file mode 100644 index 671b40512d..0000000000 --- a/packages/ui/src/components/code.css +++ /dev/null @@ -1,4 +0,0 @@ -[data-component="code"] { - content-visibility: auto; - overflow: hidden; -} diff --git a/packages/ui/src/components/code.tsx b/packages/ui/src/components/code.tsx deleted file mode 100644 index 837cc53376..0000000000 --- a/packages/ui/src/components/code.tsx +++ /dev/null @@ -1,1097 +0,0 @@ -import { - DEFAULT_VIRTUAL_FILE_METRICS, - type FileContents, - File, - FileOptions, - LineAnnotation, - type SelectedLineRange, - type VirtualFileMetrics, - VirtualizedFile, - Virtualizer, -} from "@pierre/diffs" -import { ComponentProps, createEffect, createMemo, createSignal, onCleanup, onMount, Show, splitProps } from "solid-js" -import { Portal } from "solid-js/web" -import { createDefaultOptions, styleVariables } from "../pierre" -import { getWorkerPool } from "../pierre/worker" -import { Icon } from "./icon" - -const VIRTUALIZE_BYTES = 500_000 -const codeMetrics = { - ...DEFAULT_VIRTUAL_FILE_METRICS, - lineHeight: 24, - fileGap: 0, -} satisfies Partial<VirtualFileMetrics> - -type SelectionSide = "additions" | "deletions" - -export type CodeProps<T = {}> = FileOptions<T> & { - file: FileContents - annotations?: LineAnnotation<T>[] - selectedLines?: SelectedLineRange | null - commentedLines?: SelectedLineRange[] - onRendered?: () => void - onLineSelectionEnd?: (selection: SelectedLineRange | null) => void - class?: string - classList?: ComponentProps<"div">["classList"] -} - -function findElement(node: Node | null): HTMLElement | undefined { - if (!node) return - if (node instanceof HTMLElement) return node - return node.parentElement ?? undefined -} - -function findLineNumber(node: Node | null): number | undefined { - const element = findElement(node) - if (!element) return - - const line = element.closest("[data-line]") - if (!(line instanceof HTMLElement)) return - - const value = parseInt(line.dataset.line ?? "", 10) - if (Number.isNaN(value)) return - - return value -} - -function findSide(node: Node | null): SelectionSide | undefined { - const element = findElement(node) - if (!element) return - - const code = element.closest("[data-code]") - if (!(code instanceof HTMLElement)) return - - if (code.hasAttribute("data-deletions")) return "deletions" - return "additions" -} - -type FindHost = { - element: () => HTMLElement | undefined - open: () => void - close: () => void - next: (dir: 1 | -1) => void - isOpen: () => boolean -} - -const findHosts = new Set<FindHost>() -let findTarget: FindHost | undefined -let findCurrent: FindHost | undefined -let findInstalled = false - -function isEditable(node: unknown): boolean { - if (!(node instanceof HTMLElement)) return false - if (node.closest("[data-prevent-autofocus]")) return true - if (node.isContentEditable) return true - return /^(INPUT|TEXTAREA|SELECT|BUTTON)$/.test(node.tagName) -} - -function hostForNode(node: unknown): FindHost | undefined { - if (!(node instanceof Node)) return - for (const host of findHosts) { - const el = host.element() - if (el && el.isConnected && el.contains(node)) return host - } -} - -function installFindShortcuts() { - if (findInstalled) return - if (typeof window === "undefined") return - findInstalled = true - - window.addEventListener( - "keydown", - (event) => { - if (event.defaultPrevented) return - - const mod = event.metaKey || event.ctrlKey - if (!mod) return - - const key = event.key.toLowerCase() - - if (key === "g") { - const host = findCurrent - if (!host || !host.isOpen()) return - event.preventDefault() - event.stopPropagation() - host.next(event.shiftKey ? -1 : 1) - return - } - - if (key !== "f") return - - const current = findCurrent - if (current && current.isOpen()) { - event.preventDefault() - event.stopPropagation() - current.open() - return - } - - const host = - hostForNode(document.activeElement) ?? hostForNode(event.target) ?? findTarget ?? Array.from(findHosts)[0] - if (!host) return - - event.preventDefault() - event.stopPropagation() - host.open() - }, - { capture: true }, - ) -} - -export function Code<T>(props: CodeProps<T>) { - let wrapper!: HTMLDivElement - let container!: HTMLDivElement - let findInput: HTMLInputElement | undefined - let findOverlay!: HTMLDivElement - let findOverlayFrame: number | undefined - let findOverlayScroll: HTMLElement[] = [] - let observer: MutationObserver | undefined - let renderToken = 0 - let selectionFrame: number | undefined - let dragFrame: number | undefined - let dragStart: number | undefined - let dragEnd: number | undefined - let dragMoved = false - let lastSelection: SelectedLineRange | null = null - let pendingSelectionEnd = false - - const [local, others] = splitProps(props, [ - "file", - "class", - "classList", - "annotations", - "selectedLines", - "commentedLines", - "onRendered", - ]) - - const [rendered, setRendered] = createSignal(0) - - const [findOpen, setFindOpen] = createSignal(false) - const [findQuery, setFindQuery] = createSignal("") - const [findIndex, setFindIndex] = createSignal(0) - const [findCount, setFindCount] = createSignal(0) - let findMode: "highlights" | "overlay" = "overlay" - let findHits: Range[] = [] - - const [findPos, setFindPos] = createSignal<{ top: number; right: number }>({ top: 8, right: 8 }) - - let instance: File<T> | VirtualizedFile<T> | undefined - let virtualizer: Virtualizer | undefined - let virtualRoot: Document | HTMLElement | undefined - - const bytes = createMemo(() => { - const value = local.file.contents as unknown - if (typeof value === "string") return value.length - if (Array.isArray(value)) { - return value.reduce( - (acc, part) => acc + (typeof part === "string" ? part.length + 1 : String(part).length + 1), - 0, - ) - } - if (value == null) return 0 - return String(value).length - }) - const virtual = createMemo(() => bytes() > VIRTUALIZE_BYTES) - - const options = createMemo(() => ({ - ...createDefaultOptions<T>("unified"), - ...others, - })) - - const getRoot = () => { - const host = container.querySelector("diffs-container") - if (!(host instanceof HTMLElement)) return - - const root = host.shadowRoot - if (!root) return - - return root - } - - const applyScheme = () => { - const host = container.querySelector("diffs-container") - if (!(host instanceof HTMLElement)) return - - const scheme = document.documentElement.dataset.colorScheme - if (scheme === "dark" || scheme === "light") { - host.dataset.colorScheme = scheme - return - } - - host.removeAttribute("data-color-scheme") - } - - const supportsHighlights = () => { - const g = globalThis as unknown as { CSS?: { highlights?: unknown }; Highlight?: unknown } - return typeof g.Highlight === "function" && g.CSS?.highlights != null - } - - const clearHighlightFind = () => { - const api = (globalThis as { CSS?: { highlights?: { delete: (name: string) => void } } }).CSS?.highlights - if (!api) return - api.delete("opencode-find") - api.delete("opencode-find-current") - } - - const clearOverlayScroll = () => { - for (const el of findOverlayScroll) el.removeEventListener("scroll", scheduleOverlay) - findOverlayScroll = [] - } - - const clearOverlay = () => { - if (findOverlayFrame !== undefined) { - cancelAnimationFrame(findOverlayFrame) - findOverlayFrame = undefined - } - findOverlay.innerHTML = "" - } - - const renderOverlay = () => { - if (findMode !== "overlay") { - clearOverlay() - return - } - - clearOverlay() - if (findHits.length === 0) return - - const base = wrapper.getBoundingClientRect() - const current = findIndex() - - const frag = document.createDocumentFragment() - for (let i = 0; i < findHits.length; i++) { - const range = findHits[i] - const active = i === current - - for (const rect of Array.from(range.getClientRects())) { - if (!rect.width || !rect.height) continue - - const el = document.createElement("div") - el.style.position = "absolute" - el.style.left = `${Math.round(rect.left - base.left)}px` - el.style.top = `${Math.round(rect.top - base.top)}px` - el.style.width = `${Math.round(rect.width)}px` - el.style.height = `${Math.round(rect.height)}px` - el.style.borderRadius = "2px" - el.style.backgroundColor = active ? "var(--surface-warning-strong)" : "var(--surface-warning-base)" - el.style.opacity = active ? "0.55" : "0.35" - if (active) el.style.boxShadow = "inset 0 0 0 1px var(--border-warning-base)" - frag.appendChild(el) - } - } - - findOverlay.appendChild(frag) - } - - function scheduleOverlay() { - if (findMode !== "overlay") return - if (!findOpen()) return - if (findOverlayFrame !== undefined) return - - findOverlayFrame = requestAnimationFrame(() => { - findOverlayFrame = undefined - renderOverlay() - }) - } - - const syncOverlayScroll = () => { - if (findMode !== "overlay") return - const root = getRoot() - - const next = root - ? Array.from(root.querySelectorAll("[data-code]")).filter( - (node): node is HTMLElement => node instanceof HTMLElement, - ) - : [] - if (next.length === findOverlayScroll.length && next.every((el, i) => el === findOverlayScroll[i])) return - - clearOverlayScroll() - findOverlayScroll = next - for (const el of findOverlayScroll) el.addEventListener("scroll", scheduleOverlay, { passive: true }) - } - - const clearFind = () => { - clearHighlightFind() - clearOverlay() - clearOverlayScroll() - findHits = [] - setFindCount(0) - setFindIndex(0) - } - - const getScrollParent = (el: HTMLElement): HTMLElement | undefined => { - let parent = el.parentElement - while (parent) { - const style = getComputedStyle(parent) - if (style.overflowY === "auto" || style.overflowY === "scroll") return parent - parent = parent.parentElement - } - } - - const positionFindBar = () => { - if (typeof window === "undefined") return - - const root = getScrollParent(wrapper) ?? wrapper - const rect = root.getBoundingClientRect() - const title = parseFloat(getComputedStyle(root).getPropertyValue("--session-title-height")) - const header = Number.isNaN(title) ? 0 : title - setFindPos({ - top: Math.round(rect.top) + header - 4, - right: Math.round(window.innerWidth - rect.right) + 8, - }) - } - - const scanFind = (root: ShadowRoot, query: string) => { - const needle = query.toLowerCase() - const out: Range[] = [] - - const cols = Array.from(root.querySelectorAll("[data-content] [data-line], [data-column-content]")).filter( - (node): node is HTMLElement => node instanceof HTMLElement, - ) - - for (const col of cols) { - const text = col.textContent - if (!text) continue - - const hay = text.toLowerCase() - let idx = hay.indexOf(needle) - if (idx === -1) continue - - const nodes: Text[] = [] - const ends: number[] = [] - const walker = document.createTreeWalker(col, NodeFilter.SHOW_TEXT) - let node = walker.nextNode() - let pos = 0 - - while (node) { - if (node instanceof Text) { - pos += node.data.length - nodes.push(node) - ends.push(pos) - } - node = walker.nextNode() - } - - if (nodes.length === 0) continue - - const locate = (at: number) => { - let lo = 0 - let hi = ends.length - 1 - while (lo < hi) { - const mid = (lo + hi) >> 1 - if (ends[mid] >= at) hi = mid - else lo = mid + 1 - } - const prev = lo === 0 ? 0 : ends[lo - 1] - return { node: nodes[lo], offset: at - prev } - } - - while (idx !== -1) { - const start = locate(idx) - const end = locate(idx + query.length) - const range = document.createRange() - range.setStart(start.node, start.offset) - range.setEnd(end.node, end.offset) - out.push(range) - idx = hay.indexOf(needle, idx + query.length) - } - } - - return out - } - - const scrollToRange = (range: Range) => { - const start = range.startContainer - const el = start instanceof Element ? start : start.parentElement - el?.scrollIntoView({ block: "center", inline: "center" }) - } - - const setHighlights = (ranges: Range[], index: number) => { - const api = (globalThis as unknown as { CSS?: { highlights?: any }; Highlight?: any }).CSS?.highlights - const Highlight = (globalThis as unknown as { Highlight?: any }).Highlight - if (!api || typeof Highlight !== "function") return false - - api.delete("opencode-find") - api.delete("opencode-find-current") - - const active = ranges[index] - if (active) api.set("opencode-find-current", new Highlight(active)) - - const rest = ranges.filter((_, i) => i !== index) - if (rest.length > 0) api.set("opencode-find", new Highlight(...rest)) - return true - } - - const applyFind = (opts?: { reset?: boolean; scroll?: boolean }) => { - if (!findOpen()) return - - const query = findQuery().trim() - if (!query) { - clearFind() - return - } - - const root = getRoot() - if (!root) return - - findMode = supportsHighlights() ? "highlights" : "overlay" - - const ranges = scanFind(root, query) - const total = ranges.length - const desired = opts?.reset ? 0 : findIndex() - const index = total ? Math.min(desired, total - 1) : 0 - - findHits = ranges - setFindCount(total) - setFindIndex(index) - - const active = ranges[index] - if (findMode === "highlights") { - clearOverlay() - clearOverlayScroll() - if (!setHighlights(ranges, index)) { - findMode = "overlay" - clearHighlightFind() - syncOverlayScroll() - scheduleOverlay() - } - if (opts?.scroll && active) { - scrollToRange(active) - } - return - } - - clearHighlightFind() - syncOverlayScroll() - if (opts?.scroll && active) { - scrollToRange(active) - } - scheduleOverlay() - } - - const closeFind = () => { - setFindOpen(false) - clearFind() - if (findCurrent === host) findCurrent = undefined - } - - const stepFind = (dir: 1 | -1) => { - if (!findOpen()) return - const total = findCount() - if (total <= 0) return - - const index = (findIndex() + dir + total) % total - setFindIndex(index) - - const active = findHits[index] - if (!active) return - - if (findMode === "highlights") { - if (!setHighlights(findHits, index)) { - findMode = "overlay" - applyFind({ reset: true, scroll: true }) - return - } - scrollToRange(active) - return - } - - clearHighlightFind() - syncOverlayScroll() - scrollToRange(active) - scheduleOverlay() - } - - const host: FindHost = { - element: () => wrapper, - isOpen: () => findOpen(), - next: stepFind, - open: () => { - if (findCurrent && findCurrent !== host) findCurrent.close() - findCurrent = host - findTarget = host - - if (!findOpen()) setFindOpen(true) - requestAnimationFrame(() => { - applyFind({ scroll: true }) - findInput?.focus() - findInput?.select() - }) - }, - close: closeFind, - } - - onMount(() => { - findMode = supportsHighlights() ? "highlights" : "overlay" - installFindShortcuts() - findHosts.add(host) - if (!findTarget) findTarget = host - - onCleanup(() => { - findHosts.delete(host) - if (findCurrent === host) { - findCurrent = undefined - clearHighlightFind() - } - if (findTarget === host) findTarget = undefined - }) - }) - - createEffect(() => { - if (!findOpen()) return - - const update = () => positionFindBar() - requestAnimationFrame(update) - window.addEventListener("resize", update, { passive: true }) - - const root = getScrollParent(wrapper) ?? wrapper - const observer = typeof ResizeObserver === "undefined" ? undefined : new ResizeObserver(() => update()) - observer?.observe(root) - - onCleanup(() => { - window.removeEventListener("resize", update) - observer?.disconnect() - }) - }) - - const applyCommentedLines = (ranges: SelectedLineRange[]) => { - const root = getRoot() - if (!root) return - - const existing = Array.from(root.querySelectorAll("[data-comment-selected]")) - for (const node of existing) { - if (!(node instanceof HTMLElement)) continue - node.removeAttribute("data-comment-selected") - } - - const annotations = Array.from(root.querySelectorAll("[data-line-annotation]")).filter( - (node): node is HTMLElement => node instanceof HTMLElement, - ) - - for (const range of ranges) { - const start = Math.max(1, Math.min(range.start, range.end)) - const end = Math.max(range.start, range.end) - - for (let line = start; line <= end; line++) { - const nodes = Array.from(root.querySelectorAll(`[data-line="${line}"], [data-column-number="${line}"]`)) - for (const node of nodes) { - if (!(node instanceof HTMLElement)) continue - node.setAttribute("data-comment-selected", "") - } - } - - for (const annotation of annotations) { - const line = parseInt(annotation.dataset.lineAnnotation?.split(",")[1] ?? "", 10) - if (Number.isNaN(line)) continue - if (line < start || line > end) continue - annotation.setAttribute("data-comment-selected", "") - } - } - } - - const text = () => { - const value = local.file.contents as unknown - if (typeof value === "string") return value - if (Array.isArray(value)) return value.join("\n") - if (value == null) return "" - return String(value) - } - - const lineCount = () => { - const value = text() - const total = value.split("\n").length - (value.endsWith("\n") ? 1 : 0) - return Math.max(1, total) - } - - const applySelection = (range: SelectedLineRange | null) => { - const current = instance - if (!current) return false - - if (virtual()) { - current.setSelectedLines(range) - return true - } - - const root = getRoot() - if (!root) return false - - const lines = lineCount() - if (root.querySelectorAll("[data-line]").length < lines) return false - - if (!range) { - current.setSelectedLines(null) - return true - } - - const start = Math.min(range.start, range.end) - const end = Math.max(range.start, range.end) - - if (start < 1 || end > lines) { - current.setSelectedLines(null) - return true - } - - if (!root.querySelector(`[data-line="${start}"]`) || !root.querySelector(`[data-line="${end}"]`)) { - current.setSelectedLines(null) - return true - } - - const normalized = (() => { - if (range.endSide != null) return { start: range.start, end: range.end } - if (range.side !== "deletions") return range - if (root.querySelector("[data-deletions]") != null) return range - return { start: range.start, end: range.end } - })() - - current.setSelectedLines(normalized) - return true - } - - const notifyRendered = () => { - observer?.disconnect() - observer = undefined - renderToken++ - - const token = renderToken - - const lines = virtual() ? undefined : lineCount() - - const isReady = (root: ShadowRoot) => - virtual() - ? root.querySelector("[data-line]") != null - : root.querySelectorAll("[data-line]").length >= (lines ?? 0) - - const notify = () => { - if (token !== renderToken) return - - observer?.disconnect() - observer = undefined - requestAnimationFrame(() => { - if (token !== renderToken) return - applySelection(lastSelection) - applyFind({ reset: true }) - local.onRendered?.() - }) - } - - const root = getRoot() - if (root && isReady(root)) { - notify() - return - } - - if (typeof MutationObserver === "undefined") return - - const observeRoot = (root: ShadowRoot) => { - if (isReady(root)) { - notify() - return - } - - observer?.disconnect() - observer = new MutationObserver(() => { - if (token !== renderToken) return - if (!isReady(root)) return - - notify() - }) - - observer.observe(root, { childList: true, subtree: true }) - } - - if (root) { - observeRoot(root) - return - } - - observer = new MutationObserver(() => { - if (token !== renderToken) return - - const root = getRoot() - if (!root) return - - observeRoot(root) - }) - - observer.observe(container, { childList: true, subtree: true }) - } - - const updateSelection = () => { - const root = getRoot() - if (!root) return - - const selection = - (root as unknown as { getSelection?: () => Selection | null }).getSelection?.() ?? window.getSelection() - if (!selection || selection.isCollapsed) return - - const domRange = - ( - selection as unknown as { - getComposedRanges?: (options?: { shadowRoots?: ShadowRoot[] }) => Range[] - } - ).getComposedRanges?.({ shadowRoots: [root] })?.[0] ?? - (selection.rangeCount > 0 ? selection.getRangeAt(0) : undefined) - - const startNode = domRange?.startContainer ?? selection.anchorNode - const endNode = domRange?.endContainer ?? selection.focusNode - if (!startNode || !endNode) return - - if (!root.contains(startNode) || !root.contains(endNode)) return - - const start = findLineNumber(startNode) - const end = findLineNumber(endNode) - if (start === undefined || end === undefined) return - - const startSide = findSide(startNode) - const endSide = findSide(endNode) - const side = startSide ?? endSide - - const selected: SelectedLineRange = { - start, - end, - } - - if (side) selected.side = side - if (endSide && side && endSide !== side) selected.endSide = endSide - - setSelectedLines(selected) - } - - const setSelectedLines = (range: SelectedLineRange | null) => { - lastSelection = range - applySelection(range) - } - - const scheduleSelectionUpdate = () => { - if (selectionFrame !== undefined) return - - selectionFrame = requestAnimationFrame(() => { - selectionFrame = undefined - updateSelection() - - if (!pendingSelectionEnd) return - pendingSelectionEnd = false - props.onLineSelectionEnd?.(lastSelection) - }) - } - - const updateDragSelection = () => { - if (dragStart === undefined || dragEnd === undefined) return - - const start = Math.min(dragStart, dragEnd) - const end = Math.max(dragStart, dragEnd) - - setSelectedLines({ start, end }) - } - - const scheduleDragUpdate = () => { - if (dragFrame !== undefined) return - - dragFrame = requestAnimationFrame(() => { - dragFrame = undefined - updateDragSelection() - }) - } - - const lineFromMouseEvent = (event: MouseEvent) => { - const path = event.composedPath() - - let numberColumn = false - let line: number | undefined - - for (const item of path) { - if (!(item instanceof HTMLElement)) continue - - numberColumn = numberColumn || item.dataset.columnNumber != null - - if (line === undefined && item.dataset.line) { - const parsed = parseInt(item.dataset.line, 10) - if (!Number.isNaN(parsed)) line = parsed - } - - if (numberColumn && line !== undefined) break - } - - return { line, numberColumn } - } - - const handleMouseDown = (event: MouseEvent) => { - if (props.enableLineSelection !== true) return - if (event.button !== 0) return - - const { line, numberColumn } = lineFromMouseEvent(event) - if (numberColumn) return - if (line === undefined) return - - dragStart = line - dragEnd = line - dragMoved = false - } - - const handleMouseMove = (event: MouseEvent) => { - if (props.enableLineSelection !== true) return - if (dragStart === undefined) return - - if ((event.buttons & 1) === 0) { - dragStart = undefined - dragEnd = undefined - dragMoved = false - return - } - - const { line } = lineFromMouseEvent(event) - if (line === undefined) return - - dragEnd = line - dragMoved = true - scheduleDragUpdate() - } - - const handleMouseUp = () => { - if (props.enableLineSelection !== true) return - if (dragStart === undefined) return - - if (!dragMoved) { - pendingSelectionEnd = false - const line = dragStart - setSelectedLines({ start: line, end: line }) - props.onLineSelectionEnd?.(lastSelection) - dragStart = undefined - dragEnd = undefined - dragMoved = false - return - } - - pendingSelectionEnd = true - scheduleDragUpdate() - scheduleSelectionUpdate() - - dragStart = undefined - dragEnd = undefined - dragMoved = false - } - - const handleSelectionChange = () => { - if (props.enableLineSelection !== true) return - if (dragStart === undefined) return - - const selection = window.getSelection() - if (!selection || selection.isCollapsed) return - - scheduleSelectionUpdate() - } - - createEffect(() => { - const opts = options() - const workerPool = getWorkerPool("unified") - const isVirtual = virtual() - - observer?.disconnect() - observer = undefined - - instance?.cleanUp() - instance = undefined - - if (!isVirtual && virtualizer) { - virtualizer.cleanUp() - virtualizer = undefined - virtualRoot = undefined - } - - const v = (() => { - if (!isVirtual) return - if (typeof document === "undefined") return - - const root = getScrollParent(wrapper) ?? document - if (virtualizer && virtualRoot === root) return virtualizer - - virtualizer?.cleanUp() - virtualizer = new Virtualizer() - virtualRoot = root - virtualizer.setup(root, root instanceof Document ? undefined : wrapper) - return virtualizer - })() - - instance = isVirtual && v ? new VirtualizedFile<T>(opts, v, codeMetrics, workerPool) : new File<T>(opts, workerPool) - - container.innerHTML = "" - const value = text() - instance.render({ - file: typeof local.file.contents === "string" ? local.file : { ...local.file, contents: value }, - lineAnnotations: local.annotations, - containerWrapper: container, - }) - - applyScheme() - - setRendered((value) => value + 1) - notifyRendered() - }) - - createEffect(() => { - if (typeof document === "undefined") return - if (typeof MutationObserver === "undefined") return - - const root = document.documentElement - const monitor = new MutationObserver(() => applyScheme()) - monitor.observe(root, { attributes: true, attributeFilter: ["data-color-scheme"] }) - applyScheme() - - onCleanup(() => monitor.disconnect()) - }) - - createEffect(() => { - rendered() - const ranges = local.commentedLines ?? [] - requestAnimationFrame(() => applyCommentedLines(ranges)) - }) - - createEffect(() => { - setSelectedLines(local.selectedLines ?? null) - }) - - createEffect(() => { - if (props.enableLineSelection !== true) return - - container.addEventListener("mousedown", handleMouseDown) - container.addEventListener("mousemove", handleMouseMove) - window.addEventListener("mouseup", handleMouseUp) - document.addEventListener("selectionchange", handleSelectionChange) - - onCleanup(() => { - container.removeEventListener("mousedown", handleMouseDown) - container.removeEventListener("mousemove", handleMouseMove) - window.removeEventListener("mouseup", handleMouseUp) - document.removeEventListener("selectionchange", handleSelectionChange) - }) - }) - - onCleanup(() => { - observer?.disconnect() - - instance?.cleanUp() - instance = undefined - - virtualizer?.cleanUp() - virtualizer = undefined - virtualRoot = undefined - - clearOverlayScroll() - clearOverlay() - if (findCurrent === host) { - findCurrent = undefined - clearHighlightFind() - } - - if (selectionFrame !== undefined) { - cancelAnimationFrame(selectionFrame) - selectionFrame = undefined - } - - if (dragFrame !== undefined) { - cancelAnimationFrame(dragFrame) - dragFrame = undefined - } - - dragStart = undefined - dragEnd = undefined - dragMoved = false - lastSelection = null - pendingSelectionEnd = false - }) - - const FindBar = (barProps: { class: string; style?: ComponentProps<"div">["style"] }) => ( - <div class={barProps.class} style={barProps.style} onPointerDown={(e) => e.stopPropagation()}> - <Icon name="magnifying-glass" size="small" class="text-text-weak shrink-0" /> - <input - ref={findInput} - placeholder="Find" - value={findQuery()} - class="w-40 bg-transparent outline-none text-14-regular text-text-strong placeholder:text-text-weak" - onInput={(e) => { - setFindQuery(e.currentTarget.value) - setFindIndex(0) - applyFind({ reset: true, scroll: true }) - }} - onKeyDown={(e) => { - if (e.key === "Escape") { - e.preventDefault() - closeFind() - return - } - if (e.key !== "Enter") return - e.preventDefault() - stepFind(e.shiftKey ? -1 : 1) - }} - /> - <div class="shrink-0 text-12-regular text-text-weak tabular-nums text-right" style={{ width: "10ch" }}> - {findCount() ? `${findIndex() + 1}/${findCount()}` : "0/0"} - </div> - <div class="flex items-center"> - <button - type="button" - class="size-6 grid place-items-center rounded text-text-weak hover:bg-surface-base-hover hover:text-text-strong disabled:opacity-40 disabled:pointer-events-none" - disabled={findCount() === 0} - aria-label="Previous match" - onClick={() => stepFind(-1)} - > - <Icon name="chevron-down" size="small" class="rotate-180" /> - </button> - <button - type="button" - class="size-6 grid place-items-center rounded text-text-weak hover:bg-surface-base-hover hover:text-text-strong disabled:opacity-40 disabled:pointer-events-none" - disabled={findCount() === 0} - aria-label="Next match" - onClick={() => stepFind(1)} - > - <Icon name="chevron-down" size="small" /> - </button> - </div> - <button - type="button" - class="size-6 grid place-items-center rounded text-text-weak hover:bg-surface-base-hover hover:text-text-strong" - aria-label="Close search" - onClick={closeFind} - > - <Icon name="close-small" size="small" /> - </button> - </div> - ) - - return ( - <div - data-component="code" - style={styleVariables} - class="relative outline-none" - classList={{ - ...(local.classList || {}), - [local.class ?? ""]: !!local.class, - }} - ref={wrapper} - tabIndex={0} - onPointerDown={() => { - findTarget = host - wrapper.focus({ preventScroll: true }) - }} - onFocus={() => { - findTarget = host - }} - > - <Show when={findOpen()}> - <Portal> - <FindBar - class="fixed z-50 flex h-8 items-center gap-2 rounded-md border border-border-base bg-background-base px-3 shadow-md" - style={{ - top: `${findPos().top}px`, - right: `${findPos().right}px`, - }} - /> - </Portal> - </Show> - <div ref={container} /> - <div ref={findOverlay} class="pointer-events-none absolute inset-0 z-0" /> - </div> - ) -} diff --git a/packages/ui/src/components/collapsible.stories.tsx b/packages/ui/src/components/collapsible.stories.tsx new file mode 100644 index 0000000000..67883b2299 --- /dev/null +++ b/packages/ui/src/components/collapsible.stories.tsx @@ -0,0 +1,86 @@ +// @ts-nocheck +import * as mod from "./collapsible" + +const docs = `### Overview +Toggleable content region with optional arrow indicator. + +Compose \`Collapsible.Trigger\`, \`Collapsible.Content\`, and \`Collapsible.Arrow\`. + +### API +- Root accepts Kobalte Collapsible props (\`open\`, \`defaultOpen\`, \`onOpenChange\`). +- \`variant\` controls styling ("normal" | "ghost"). + +### Variants and states +- Normal and ghost variants. +- Open/closed states. + +### Behavior +- Trigger toggles the content visibility. + +### Accessibility +- TODO: confirm ARIA attributes provided by Kobalte. + +### Theming/tokens +- Uses \`data-component="collapsible"\` and slots for trigger/content/arrow. + +` + +export default { + title: "UI/Collapsible", + id: "components-collapsible", + component: mod.Collapsible, + tags: ["autodocs"], + parameters: { + docs: { + description: { + component: docs, + }, + }, + }, + argTypes: { + variant: { + control: "select", + options: ["normal", "ghost"], + }, + }, +} + +export const Basic = { + args: { + variant: "normal", + defaultOpen: true, + }, + render: (props) => ( + <mod.Collapsible {...props}> + <mod.Collapsible.Trigger data-slot="collapsible-trigger"> + <div style={{ display: "flex", "align-items": "center", gap: "8px" }}> + <span>Details</span> + <mod.Collapsible.Arrow /> + </div> + </mod.Collapsible.Trigger> + <mod.Collapsible.Content data-slot="collapsible-content"> + <div style={{ color: "var(--text-weak)", "padding-top": "8px" }}>Optional details sit here.</div> + </mod.Collapsible.Content> + </mod.Collapsible> + ), +} + +export const Ghost = { + args: { + variant: "ghost", + defaultOpen: false, + }, + render: (props) => ( + <mod.Collapsible {...props}> + <mod.Collapsible.Trigger data-slot="collapsible-trigger"> + <div style={{ display: "flex", "align-items": "center", gap: "8px" }}> + <span>Ghost trigger</span> + <mod.Collapsible.Arrow /> + </div> + </mod.Collapsible.Trigger> + <mod.Collapsible.Content data-slot="collapsible-content"> + <div style={{ color: "var(--text-weak)", "padding-top": "8px" }}>Ghost content.</div> + </mod.Collapsible.Content> + </mod.Collapsible> + ), +} diff --git a/packages/ui/src/components/context-menu.stories.tsx b/packages/ui/src/components/context-menu.stories.tsx new file mode 100644 index 0000000000..bee5a55965 --- /dev/null +++ b/packages/ui/src/components/context-menu.stories.tsx @@ -0,0 +1,113 @@ +// @ts-nocheck +import * as mod from "./context-menu" + +const docs = `### Overview +Context menu for right-click interactions with composable items and submenus. + +Use \`ItemLabel\` and \`ItemDescription\` for rich items. + +### API +- Root accepts Kobalte ContextMenu props (\`open\`, \`defaultOpen\`, \`onOpenChange\`). +- Compose \`Trigger\`, \`Content\`, \`Item\`, \`Separator\`, and optional \`Sub\` sections. + +### Variants and states +- Supports grouped sections and nested submenus. + +### Behavior +- Opens on context menu gesture over the trigger element. + +### Accessibility +- TODO: confirm keyboard and focus behavior from Kobalte. + +### Theming/tokens +- Uses \`data-component="context-menu"\` and slot attributes for styling. + +` + +export default { + title: "UI/ContextMenu", + id: "components-context-menu", + component: mod.ContextMenu, + tags: ["autodocs"], + parameters: { + docs: { + description: { + component: docs, + }, + }, + }, +} + +export const Basic = { + render: () => ( + <mod.ContextMenu defaultOpen> + <mod.ContextMenu.Trigger> + <div + style={{ + padding: "20px", + border: "1px dashed var(--border-weak)", + "border-radius": "8px", + color: "var(--text-weak)", + }} + > + Right click (or open) here + </div> + </mod.ContextMenu.Trigger> + <mod.ContextMenu.Portal> + <mod.ContextMenu.Content> + <mod.ContextMenu.Group> + <mod.ContextMenu.GroupLabel>Actions</mod.ContextMenu.GroupLabel> + <mod.ContextMenu.Item> + <mod.ContextMenu.ItemLabel>Copy</mod.ContextMenu.ItemLabel> + </mod.ContextMenu.Item> + <mod.ContextMenu.Item> + <mod.ContextMenu.ItemLabel>Paste</mod.ContextMenu.ItemLabel> + </mod.ContextMenu.Item> + </mod.ContextMenu.Group> + <mod.ContextMenu.Separator /> + <mod.ContextMenu.Sub> + <mod.ContextMenu.SubTrigger>More</mod.ContextMenu.SubTrigger> + <mod.ContextMenu.SubContent> + <mod.ContextMenu.Item> + <mod.ContextMenu.ItemLabel>Duplicate</mod.ContextMenu.ItemLabel> + </mod.ContextMenu.Item> + <mod.ContextMenu.Item> + <mod.ContextMenu.ItemLabel>Move</mod.ContextMenu.ItemLabel> + </mod.ContextMenu.Item> + </mod.ContextMenu.SubContent> + </mod.ContextMenu.Sub> + </mod.ContextMenu.Content> + </mod.ContextMenu.Portal> + </mod.ContextMenu> + ), +} + +export const CheckboxRadio = { + render: () => ( + <mod.ContextMenu defaultOpen> + <mod.ContextMenu.Trigger> + <div + style={{ + padding: "20px", + border: "1px dashed var(--border-weak)", + "border-radius": "8px", + color: "var(--text-weak)", + }} + > + Right click (or open) here + </div> + </mod.ContextMenu.Trigger> + <mod.ContextMenu.Portal> + <mod.ContextMenu.Content> + <mod.ContextMenu.CheckboxItem checked>Show line numbers</mod.ContextMenu.CheckboxItem> + <mod.ContextMenu.CheckboxItem>Wrap lines</mod.ContextMenu.CheckboxItem> + <mod.ContextMenu.Separator /> + <mod.ContextMenu.RadioGroup value="compact"> + <mod.ContextMenu.RadioItem value="compact">Compact</mod.ContextMenu.RadioItem> + <mod.ContextMenu.RadioItem value="comfortable">Comfortable</mod.ContextMenu.RadioItem> + </mod.ContextMenu.RadioGroup> + </mod.ContextMenu.Content> + </mod.ContextMenu.Portal> + </mod.ContextMenu> + ), +} diff --git a/packages/ui/src/components/dialog.css b/packages/ui/src/components/dialog.css index 2e66b644fc..1e74763ae2 100644 --- a/packages/ui/src/components/dialog.css +++ b/packages/ui/src/components/dialog.css @@ -54,7 +54,7 @@ [data-slot="dialog-header"] { display: flex; - padding: 20px; + padding: 16px 20px; justify-content: space-between; align-items: center; flex-shrink: 0; diff --git a/packages/ui/src/components/dialog.stories.tsx b/packages/ui/src/components/dialog.stories.tsx new file mode 100644 index 0000000000..60cd0a1c19 --- /dev/null +++ b/packages/ui/src/components/dialog.stories.tsx @@ -0,0 +1,173 @@ +// @ts-nocheck +import { onMount } from "solid-js" +import * as mod from "./dialog" +import { Button } from "./button" +import { useDialog } from "../context/dialog" + +const docs = `### Overview +Dialog content wrapper used with the DialogProvider for modal flows. + +Provide concise title/description and keep body focused. + +### API +- Optional: \`title\`, \`description\`, \`action\`. +- \`size\`: normal | large | x-large. +- \`fit\` and \`transition\` control layout and animation. + +### Variants and states +- Sizes and optional header/action controls. + +### Behavior +- Intended to be rendered via \`useDialog().show\`. + +### Accessibility +- TODO: confirm focus trapping and aria attributes from Kobalte Dialog. + +### Theming/tokens +- Uses \`data-component="dialog"\` and slot attributes. + +` + +export default { + title: "UI/Dialog", + id: "components-dialog", + component: mod.Dialog, + tags: ["autodocs"], + parameters: { + docs: { + description: { + component: docs, + }, + }, + }, +} + +export const Basic = { + render: () => { + const dialog = useDialog() + const open = () => + dialog.show(() => ( + <mod.Dialog title="Dialog" description="Description"> + Dialog body content. + </mod.Dialog> + )) + + onMount(open) + + return ( + <Button variant="secondary" onClick={open}> + Open dialog + </Button> + ) + }, +} + +export const Sizes = { + render: () => { + const dialog = useDialog() + return ( + <div style={{ display: "flex", gap: "12px" }}> + <Button + variant="secondary" + onClick={() => + dialog.show(() => ( + <mod.Dialog title="Normal" description="Normal size"> + Normal dialog content. + </mod.Dialog> + )) + } + > + Normal + </Button> + <Button + variant="secondary" + onClick={() => + dialog.show(() => ( + <mod.Dialog size="large" title="Large" description="Large size"> + Large dialog content. + </mod.Dialog> + )) + } + > + Large + </Button> + <Button + variant="secondary" + onClick={() => + dialog.show(() => ( + <mod.Dialog size="x-large" title="Extra large" description="X-large size"> + X-large dialog content. + </mod.Dialog> + )) + } + > + X-Large + </Button> + </div> + ) + }, +} + +export const Transition = { + render: () => { + const dialog = useDialog() + return ( + <Button + variant="secondary" + onClick={() => + dialog.show(() => ( + <mod.Dialog title="Transition" description="Animated" transition> + Transition enabled. + </mod.Dialog> + )) + } + > + Open transition dialog + </Button> + ) + }, +} + +export const CustomAction = { + render: () => { + const dialog = useDialog() + return ( + <Button + variant="secondary" + onClick={() => + dialog.show(() => ( + <mod.Dialog + title="Custom action" + description="Dialog with a custom header action" + action={<Button variant="ghost">Help</Button>} + > + Dialog body content. + </mod.Dialog> + )) + } + > + Open action dialog + </Button> + ) + }, +} + +export const Fit = { + render: () => { + const dialog = useDialog() + return ( + <Button + variant="secondary" + onClick={() => + dialog.show(() => ( + <mod.Dialog title="Fit content" fit> + Dialog fits its content. + </mod.Dialog> + )) + } + > + Open fit dialog + </Button> + ) + }, +} diff --git a/packages/ui/src/components/diff-changes.stories.tsx b/packages/ui/src/components/diff-changes.stories.tsx new file mode 100644 index 0000000000..fe0ba6eb4f --- /dev/null +++ b/packages/ui/src/components/diff-changes.stories.tsx @@ -0,0 +1,81 @@ +// @ts-nocheck +import * as mod from "./diff-changes" +import { create } from "../storybook/scaffold" +import { changes } from "../storybook/fixtures" + +const docs = `### Overview +Summarize additions/deletions as text or compact bars. + +Pair with \`Diff\`/\`DiffSSR\` to contextualize a change set. + +### API +- Required: \`changes\` as { additions, deletions } or an array of those objects. +- Optional: \`variant\` ("default" | "bars"). + +### Variants and states +- Default text summary or bar visualization. +- Handles zero-change state (renders nothing in default variant). + +### Behavior +- Aggregates arrays into total additions/deletions. + +### Accessibility +- Ensure surrounding context conveys meaning of the counts/bars. + +### Theming/tokens +- Uses \`data-component="diff-changes"\` and diff color tokens. + +` + +const story = create({ + title: "UI/DiffChanges", + mod, + args: { + changes, + variant: "default", + }, +}) + +export default { + title: "UI/DiffChanges", + id: "components-diff-changes", + component: story.meta.component, + tags: ["autodocs"], + parameters: { + docs: { + description: { + component: docs, + }, + }, + }, + argTypes: { + variant: { + control: "select", + options: ["default", "bars"], + }, + }, +} + +export const Default = story.Basic + +export const Bars = { + args: { + variant: "bars", + }, +} + +export const MultipleFiles = { + args: { + changes: [ + { additions: 4, deletions: 1 }, + { additions: 8, deletions: 3 }, + { additions: 2, deletions: 0 }, + ], + }, +} + +export const Zero = { + args: { + changes: { additions: 0, deletions: 0 }, + }, +} diff --git a/packages/ui/src/components/diff-ssr.tsx b/packages/ui/src/components/diff-ssr.tsx deleted file mode 100644 index e739afc16d..0000000000 --- a/packages/ui/src/components/diff-ssr.tsx +++ /dev/null @@ -1,317 +0,0 @@ -import { DIFFS_TAG_NAME, FileDiff, type SelectedLineRange, VirtualizedFileDiff } from "@pierre/diffs" -import { PreloadMultiFileDiffResult } from "@pierre/diffs/ssr" -import { createEffect, onCleanup, onMount, Show, splitProps } from "solid-js" -import { Dynamic, isServer } from "solid-js/web" -import { createDefaultOptions, styleVariables, type DiffProps } from "../pierre" -import { acquireVirtualizer, virtualMetrics } from "../pierre/virtualizer" -import { useWorkerPool } from "../context/worker-pool" - -export type SSRDiffProps<T = {}> = DiffProps<T> & { - preloadedDiff: PreloadMultiFileDiffResult<T> -} - -export function Diff<T>(props: SSRDiffProps<T>) { - let container!: HTMLDivElement - let fileDiffRef!: HTMLElement - const [local, others] = splitProps(props, [ - "before", - "after", - "class", - "classList", - "annotations", - "selectedLines", - "commentedLines", - ]) - const workerPool = useWorkerPool(props.diffStyle) - - let fileDiffInstance: FileDiff<T> | undefined - let sharedVirtualizer: NonNullable<ReturnType<typeof acquireVirtualizer>> | undefined - const cleanupFunctions: Array<() => void> = [] - - const getRoot = () => fileDiffRef?.shadowRoot ?? undefined - - const getVirtualizer = () => { - if (sharedVirtualizer) return sharedVirtualizer.virtualizer - - const result = acquireVirtualizer(container) - if (!result) return - - sharedVirtualizer = result - return result.virtualizer - } - - const applyScheme = () => { - const scheme = document.documentElement.dataset.colorScheme - if (scheme === "dark" || scheme === "light") { - fileDiffRef.dataset.colorScheme = scheme - return - } - - fileDiffRef.removeAttribute("data-color-scheme") - } - - const lineIndex = (split: boolean, element: HTMLElement) => { - const raw = element.dataset.lineIndex - if (!raw) return - const values = raw - .split(",") - .map((value) => parseInt(value, 10)) - .filter((value) => !Number.isNaN(value)) - if (values.length === 0) return - if (!split) return values[0] - if (values.length === 2) return values[1] - return values[0] - } - - const rowIndex = (root: ShadowRoot, split: boolean, line: number, side: "additions" | "deletions" | undefined) => { - const nodes = Array.from(root.querySelectorAll(`[data-line="${line}"], [data-alt-line="${line}"]`)).filter( - (node): node is HTMLElement => node instanceof HTMLElement, - ) - if (nodes.length === 0) return - - const targetSide = side ?? "additions" - - for (const node of nodes) { - if (findSide(node) === targetSide) return lineIndex(split, node) - if (parseInt(node.dataset.altLine ?? "", 10) === line) return lineIndex(split, node) - } - } - - const fixSelection = (range: SelectedLineRange | null) => { - if (!range) return range - const root = getRoot() - if (!root) return - - const diffs = root.querySelector("[data-diff]") - if (!(diffs instanceof HTMLElement)) return - - const split = diffs.dataset.diffType === "split" - - const start = rowIndex(root, split, range.start, range.side) - const end = rowIndex(root, split, range.end, range.endSide ?? range.side) - - if (start === undefined || end === undefined) { - if (root.querySelector("[data-line], [data-alt-line]") == null) return - return null - } - if (start <= end) return range - - const side = range.endSide ?? range.side - const swapped: SelectedLineRange = { - start: range.end, - end: range.start, - } - if (side) swapped.side = side - if (range.endSide && range.side) swapped.endSide = range.side - - return swapped - } - - const setSelectedLines = (range: SelectedLineRange | null, attempt = 0) => { - const diff = fileDiffInstance - if (!diff) return - - const fixed = fixSelection(range) - if (fixed === undefined) { - if (attempt >= 120) return - requestAnimationFrame(() => setSelectedLines(range, attempt + 1)) - return - } - - diff.setSelectedLines(fixed) - } - - const findSide = (element: HTMLElement): "additions" | "deletions" => { - const line = element.closest("[data-line], [data-alt-line]") - if (line instanceof HTMLElement) { - const type = line.dataset.lineType - if (type === "change-deletion") return "deletions" - if (type === "change-addition" || type === "change-additions") return "additions" - } - - const code = element.closest("[data-code]") - if (!(code instanceof HTMLElement)) return "additions" - return code.hasAttribute("data-deletions") ? "deletions" : "additions" - } - - const applyCommentedLines = (ranges: SelectedLineRange[]) => { - const root = getRoot() - if (!root) return - - const existing = Array.from(root.querySelectorAll("[data-comment-selected]")) - for (const node of existing) { - if (!(node instanceof HTMLElement)) continue - node.removeAttribute("data-comment-selected") - } - - const diffs = root.querySelector("[data-diff]") - if (!(diffs instanceof HTMLElement)) return - - const split = diffs.dataset.diffType === "split" - - const rows = Array.from(diffs.querySelectorAll("[data-line-index]")).filter( - (node): node is HTMLElement => node instanceof HTMLElement, - ) - if (rows.length === 0) return - - const annotations = Array.from(diffs.querySelectorAll("[data-line-annotation]")).filter( - (node): node is HTMLElement => node instanceof HTMLElement, - ) - - const lineIndex = (element: HTMLElement) => { - const raw = element.dataset.lineIndex - if (!raw) return - const values = raw - .split(",") - .map((value) => parseInt(value, 10)) - .filter((value) => !Number.isNaN(value)) - if (values.length === 0) return - if (!split) return values[0] - if (values.length === 2) return values[1] - return values[0] - } - - const rowIndex = (line: number, side: "additions" | "deletions" | undefined) => { - const nodes = Array.from(root.querySelectorAll(`[data-line="${line}"], [data-alt-line="${line}"]`)).filter( - (node): node is HTMLElement => node instanceof HTMLElement, - ) - if (nodes.length === 0) return - - const targetSide = side ?? "additions" - - for (const node of nodes) { - if (findSide(node) === targetSide) return lineIndex(node) - if (parseInt(node.dataset.altLine ?? "", 10) === line) return lineIndex(node) - } - } - - for (const range of ranges) { - const start = rowIndex(range.start, range.side) - if (start === undefined) continue - - const end = (() => { - const same = range.end === range.start && (range.endSide == null || range.endSide === range.side) - if (same) return start - return rowIndex(range.end, range.endSide ?? range.side) - })() - if (end === undefined) continue - - const first = Math.min(start, end) - const last = Math.max(start, end) - - for (const row of rows) { - const idx = lineIndex(row) - if (idx === undefined) continue - if (idx < first || idx > last) continue - row.setAttribute("data-comment-selected", "") - } - - for (const annotation of annotations) { - const idx = parseInt(annotation.dataset.lineAnnotation?.split(",")[1] ?? "", 10) - if (Number.isNaN(idx)) continue - if (idx < first || idx > last) continue - annotation.setAttribute("data-comment-selected", "") - } - } - } - - onMount(() => { - if (isServer || !props.preloadedDiff) return - - applyScheme() - - if (typeof MutationObserver !== "undefined") { - const root = document.documentElement - const monitor = new MutationObserver(() => applyScheme()) - monitor.observe(root, { attributes: true, attributeFilter: ["data-color-scheme"] }) - onCleanup(() => monitor.disconnect()) - } - - const virtualizer = getVirtualizer() - - fileDiffInstance = virtualizer - ? new VirtualizedFileDiff<T>( - { - ...createDefaultOptions(props.diffStyle), - ...others, - ...props.preloadedDiff, - }, - virtualizer, - virtualMetrics, - workerPool, - ) - : new FileDiff<T>( - { - ...createDefaultOptions(props.diffStyle), - ...others, - ...props.preloadedDiff, - }, - workerPool, - ) - // @ts-expect-error - fileContainer is private but needed for SSR hydration - fileDiffInstance.fileContainer = fileDiffRef - fileDiffInstance.hydrate({ - oldFile: local.before, - newFile: local.after, - lineAnnotations: local.annotations, - fileContainer: fileDiffRef, - containerWrapper: container, - }) - - setSelectedLines(local.selectedLines ?? null) - - createEffect(() => { - fileDiffInstance?.setLineAnnotations(local.annotations ?? []) - }) - - createEffect(() => { - setSelectedLines(local.selectedLines ?? null) - }) - - createEffect(() => { - const ranges = local.commentedLines ?? [] - requestAnimationFrame(() => applyCommentedLines(ranges)) - }) - - // Hydrate annotation slots with interactive SolidJS components - // if (props.annotations.length > 0 && props.renderAnnotation != null) { - // for (const annotation of props.annotations) { - // const slotName = `annotation-${annotation.side}-${annotation.lineNumber}`; - // const slotElement = fileDiffRef.querySelector( - // `[slot="${slotName}"]` - // ) as HTMLElement; - // - // if (slotElement != null) { - // // Clear the static server-rendered content from the slot - // slotElement.innerHTML = ''; - // - // // Mount a fresh SolidJS component into this slot using render(). - // // This enables full SolidJS reactivity (signals, effects, etc.) - // const dispose = render( - // () => props.renderAnnotation!(annotation), - // slotElement - // ); - // cleanupFunctions.push(dispose); - // } - // } - // } - }) - - onCleanup(() => { - // Clean up FileDiff event handlers and dispose SolidJS components - fileDiffInstance?.cleanUp() - cleanupFunctions.forEach((dispose) => dispose()) - sharedVirtualizer?.release() - sharedVirtualizer = undefined - }) - - return ( - <div data-component="diff" style={styleVariables} ref={container}> - <Dynamic component={DIFFS_TAG_NAME} ref={fileDiffRef} id="ssr-diff"> - <Show when={isServer}> - <template shadowrootmode="open" innerHTML={props.preloadedDiff.prerenderedHTML} /> - </Show> - </Dynamic> - </div> - ) -} diff --git a/packages/ui/src/components/diff.tsx b/packages/ui/src/components/diff.tsx deleted file mode 100644 index 0002232b01..0000000000 --- a/packages/ui/src/components/diff.tsx +++ /dev/null @@ -1,652 +0,0 @@ -import { sampledChecksum } from "@opencode-ai/util/encode" -import { FileDiff, type FileDiffOptions, type SelectedLineRange, VirtualizedFileDiff } from "@pierre/diffs" -import { createMediaQuery } from "@solid-primitives/media" -import { createEffect, createMemo, createSignal, onCleanup, splitProps } from "solid-js" -import { createDefaultOptions, type DiffProps, styleVariables } from "../pierre" -import { acquireVirtualizer, virtualMetrics } from "../pierre/virtualizer" -import { getWorkerPool } from "../pierre/worker" - -type SelectionSide = "additions" | "deletions" - -function findElement(node: Node | null): HTMLElement | undefined { - if (!node) return - if (node instanceof HTMLElement) return node - return node.parentElement ?? undefined -} - -function findLineNumber(node: Node | null): number | undefined { - const element = findElement(node) - if (!element) return - - const line = element.closest("[data-line], [data-alt-line]") - if (!(line instanceof HTMLElement)) return - - const value = (() => { - const primary = parseInt(line.dataset.line ?? "", 10) - if (!Number.isNaN(primary)) return primary - - const alt = parseInt(line.dataset.altLine ?? "", 10) - if (!Number.isNaN(alt)) return alt - })() - - return value -} - -function findSide(node: Node | null): SelectionSide | undefined { - const element = findElement(node) - if (!element) return - - const line = element.closest("[data-line], [data-alt-line]") - if (line instanceof HTMLElement) { - const type = line.dataset.lineType - if (type === "change-deletion") return "deletions" - if (type === "change-addition" || type === "change-additions") return "additions" - } - - const code = element.closest("[data-code]") - if (!(code instanceof HTMLElement)) return - - if (code.hasAttribute("data-deletions")) return "deletions" - return "additions" -} - -export function Diff<T>(props: DiffProps<T>) { - let container!: HTMLDivElement - let observer: MutationObserver | undefined - let sharedVirtualizer: NonNullable<ReturnType<typeof acquireVirtualizer>> | undefined - let renderToken = 0 - let selectionFrame: number | undefined - let dragFrame: number | undefined - let dragStart: number | undefined - let dragEnd: number | undefined - let dragSide: SelectionSide | undefined - let dragEndSide: SelectionSide | undefined - let dragMoved = false - let lastSelection: SelectedLineRange | null = null - let pendingSelectionEnd = false - - const [local, others] = splitProps(props, [ - "before", - "after", - "class", - "classList", - "annotations", - "selectedLines", - "commentedLines", - "onRendered", - ]) - - const mobile = createMediaQuery("(max-width: 640px)") - - const large = createMemo(() => { - const before = typeof local.before?.contents === "string" ? local.before.contents : "" - const after = typeof local.after?.contents === "string" ? local.after.contents : "" - return Math.max(before.length, after.length) > 500_000 - }) - - const largeOptions = { - lineDiffType: "none", - maxLineDiffLength: 0, - tokenizeMaxLineLength: 1, - } satisfies Pick<FileDiffOptions<T>, "lineDiffType" | "maxLineDiffLength" | "tokenizeMaxLineLength"> - - const options = createMemo<FileDiffOptions<T>>(() => { - const base = { - ...createDefaultOptions(props.diffStyle), - ...others, - } - - const perf = large() ? { ...base, ...largeOptions } : base - if (!mobile()) return perf - - return { - ...perf, - disableLineNumbers: true, - } - }) - - let instance: FileDiff<T> | undefined - const [current, setCurrent] = createSignal<FileDiff<T> | undefined>(undefined) - const [rendered, setRendered] = createSignal(0) - - const getVirtualizer = () => { - if (sharedVirtualizer) return sharedVirtualizer.virtualizer - - const result = acquireVirtualizer(container) - if (!result) return - - sharedVirtualizer = result - return result.virtualizer - } - - const getRoot = () => { - const host = container.querySelector("diffs-container") - if (!(host instanceof HTMLElement)) return - - const root = host.shadowRoot - if (!root) return - - return root - } - - const applyScheme = () => { - const host = container.querySelector("diffs-container") - if (!(host instanceof HTMLElement)) return - - const scheme = document.documentElement.dataset.colorScheme - if (scheme === "dark" || scheme === "light") { - host.dataset.colorScheme = scheme - return - } - - host.removeAttribute("data-color-scheme") - } - - const lineIndex = (split: boolean, element: HTMLElement) => { - const raw = element.dataset.lineIndex - if (!raw) return - const values = raw - .split(",") - .map((value) => parseInt(value, 10)) - .filter((value) => !Number.isNaN(value)) - if (values.length === 0) return - if (!split) return values[0] - if (values.length === 2) return values[1] - return values[0] - } - - const rowIndex = (root: ShadowRoot, split: boolean, line: number, side: SelectionSide | undefined) => { - const nodes = Array.from(root.querySelectorAll(`[data-line="${line}"], [data-alt-line="${line}"]`)).filter( - (node): node is HTMLElement => node instanceof HTMLElement, - ) - if (nodes.length === 0) return - - const targetSide = side ?? "additions" - - for (const node of nodes) { - if (findSide(node) === targetSide) return lineIndex(split, node) - if (parseInt(node.dataset.altLine ?? "", 10) === line) return lineIndex(split, node) - } - } - - const fixSelection = (range: SelectedLineRange | null) => { - if (!range) return range - const root = getRoot() - if (!root) return - - const diffs = root.querySelector("[data-diff]") - if (!(diffs instanceof HTMLElement)) return - - const split = diffs.dataset.diffType === "split" - - const start = rowIndex(root, split, range.start, range.side) - const end = rowIndex(root, split, range.end, range.endSide ?? range.side) - if (start === undefined || end === undefined) { - if (root.querySelector("[data-line], [data-alt-line]") == null) return - return null - } - if (start <= end) return range - - const side = range.endSide ?? range.side - const swapped: SelectedLineRange = { - start: range.end, - end: range.start, - } - - if (side) swapped.side = side - if (range.endSide && range.side) swapped.endSide = range.side - - return swapped - } - - const notifyRendered = () => { - observer?.disconnect() - observer = undefined - renderToken++ - - const token = renderToken - let settle = 0 - - const isReady = (root: ShadowRoot) => root.querySelector("[data-line]") != null - - const notify = () => { - if (token !== renderToken) return - - observer?.disconnect() - observer = undefined - requestAnimationFrame(() => { - if (token !== renderToken) return - setSelectedLines(lastSelection) - local.onRendered?.() - }) - } - - const schedule = () => { - settle++ - const current = settle - - requestAnimationFrame(() => { - if (token !== renderToken) return - if (current !== settle) return - - requestAnimationFrame(() => { - if (token !== renderToken) return - if (current !== settle) return - - notify() - }) - }) - } - - const observeRoot = (root: ShadowRoot) => { - observer?.disconnect() - observer = new MutationObserver(() => { - if (token !== renderToken) return - if (!isReady(root)) return - - schedule() - }) - - observer.observe(root, { childList: true, subtree: true }) - - if (!isReady(root)) return - schedule() - } - - const root = getRoot() - if (typeof MutationObserver === "undefined") { - if (!root || !isReady(root)) return - setSelectedLines(lastSelection) - local.onRendered?.() - return - } - - if (root) { - observeRoot(root) - return - } - - observer = new MutationObserver(() => { - if (token !== renderToken) return - - const root = getRoot() - if (!root) return - - observeRoot(root) - }) - - observer.observe(container, { childList: true, subtree: true }) - } - - const applyCommentedLines = (ranges: SelectedLineRange[]) => { - const root = getRoot() - if (!root) return - - const existing = Array.from(root.querySelectorAll("[data-comment-selected]")) - for (const node of existing) { - if (!(node instanceof HTMLElement)) continue - node.removeAttribute("data-comment-selected") - } - - const diffs = root.querySelector("[data-diff]") - if (!(diffs instanceof HTMLElement)) return - - const split = diffs.dataset.diffType === "split" - - const rows = Array.from(diffs.querySelectorAll("[data-line-index]")).filter( - (node): node is HTMLElement => node instanceof HTMLElement, - ) - if (rows.length === 0) return - - const annotations = Array.from(diffs.querySelectorAll("[data-line-annotation]")).filter( - (node): node is HTMLElement => node instanceof HTMLElement, - ) - - for (const range of ranges) { - const start = rowIndex(root, split, range.start, range.side) - if (start === undefined) continue - - const end = (() => { - const same = range.end === range.start && (range.endSide == null || range.endSide === range.side) - if (same) return start - return rowIndex(root, split, range.end, range.endSide ?? range.side) - })() - if (end === undefined) continue - - const first = Math.min(start, end) - const last = Math.max(start, end) - - for (const row of rows) { - const idx = lineIndex(split, row) - if (idx === undefined) continue - if (idx < first || idx > last) continue - row.setAttribute("data-comment-selected", "") - } - - for (const annotation of annotations) { - const idx = parseInt(annotation.dataset.lineAnnotation?.split(",")[1] ?? "", 10) - if (Number.isNaN(idx)) continue - if (idx < first || idx > last) continue - annotation.setAttribute("data-comment-selected", "") - } - } - } - - const setSelectedLines = (range: SelectedLineRange | null) => { - const active = current() - if (!active) return - - const fixed = fixSelection(range) - if (fixed === undefined) { - lastSelection = range - return - } - - lastSelection = fixed - active.setSelectedLines(fixed) - } - - const updateSelection = () => { - const root = getRoot() - if (!root) return - - const selection = - (root as unknown as { getSelection?: () => Selection | null }).getSelection?.() ?? window.getSelection() - if (!selection || selection.isCollapsed) return - - const domRange = - ( - selection as unknown as { - getComposedRanges?: (options?: { shadowRoots?: ShadowRoot[] }) => Range[] - } - ).getComposedRanges?.({ shadowRoots: [root] })?.[0] ?? - (selection.rangeCount > 0 ? selection.getRangeAt(0) : undefined) - - const startNode = domRange?.startContainer ?? selection.anchorNode - const endNode = domRange?.endContainer ?? selection.focusNode - if (!startNode || !endNode) return - - if (!root.contains(startNode) || !root.contains(endNode)) return - - const start = findLineNumber(startNode) - const end = findLineNumber(endNode) - if (start === undefined || end === undefined) return - - const startSide = findSide(startNode) - const endSide = findSide(endNode) - const side = startSide ?? endSide - - const selected: SelectedLineRange = { - start, - end, - } - - if (side) selected.side = side - if (endSide && side && endSide !== side) selected.endSide = endSide - - setSelectedLines(selected) - } - - const scheduleSelectionUpdate = () => { - if (selectionFrame !== undefined) return - - selectionFrame = requestAnimationFrame(() => { - selectionFrame = undefined - updateSelection() - - if (!pendingSelectionEnd) return - pendingSelectionEnd = false - props.onLineSelectionEnd?.(lastSelection) - }) - } - - const updateDragSelection = () => { - if (dragStart === undefined || dragEnd === undefined) return - - const selected: SelectedLineRange = { - start: dragStart, - end: dragEnd, - } - - if (dragSide) selected.side = dragSide - if (dragEndSide && dragSide && dragEndSide !== dragSide) selected.endSide = dragEndSide - - setSelectedLines(selected) - } - - const scheduleDragUpdate = () => { - if (dragFrame !== undefined) return - - dragFrame = requestAnimationFrame(() => { - dragFrame = undefined - updateDragSelection() - }) - } - - const lineFromMouseEvent = (event: MouseEvent) => { - const path = event.composedPath() - - let numberColumn = false - let line: number | undefined - let side: SelectionSide | undefined - - for (const item of path) { - if (!(item instanceof HTMLElement)) continue - - numberColumn = numberColumn || item.dataset.columnNumber != null - - if (side === undefined) { - const type = item.dataset.lineType - if (type === "change-deletion") side = "deletions" - if (type === "change-addition" || type === "change-additions") side = "additions" - } - - if (side === undefined && item.dataset.code != null) { - side = item.hasAttribute("data-deletions") ? "deletions" : "additions" - } - - if (line === undefined) { - const primary = item.dataset.line ? parseInt(item.dataset.line, 10) : Number.NaN - if (!Number.isNaN(primary)) { - line = primary - } else { - const alt = item.dataset.altLine ? parseInt(item.dataset.altLine, 10) : Number.NaN - if (!Number.isNaN(alt)) line = alt - } - } - - if (numberColumn && line !== undefined && side !== undefined) break - } - - return { line, numberColumn, side } - } - - const handleMouseDown = (event: MouseEvent) => { - if (props.enableLineSelection !== true) return - if (event.button !== 0) return - - const { line, numberColumn, side } = lineFromMouseEvent(event) - if (numberColumn) return - if (line === undefined) return - - dragStart = line - dragEnd = line - dragSide = side - dragEndSide = side - dragMoved = false - } - - const handleMouseMove = (event: MouseEvent) => { - if (props.enableLineSelection !== true) return - if (dragStart === undefined) return - - if ((event.buttons & 1) === 0) { - dragStart = undefined - dragEnd = undefined - dragSide = undefined - dragEndSide = undefined - dragMoved = false - return - } - - const { line, side } = lineFromMouseEvent(event) - if (line === undefined) return - - dragEnd = line - dragEndSide = side - dragMoved = true - scheduleDragUpdate() - } - - const handleMouseUp = () => { - if (props.enableLineSelection !== true) return - if (dragStart === undefined) return - - if (!dragMoved) { - pendingSelectionEnd = false - const line = dragStart - const selected: SelectedLineRange = { - start: line, - end: line, - } - if (dragSide) selected.side = dragSide - setSelectedLines(selected) - props.onLineSelectionEnd?.(lastSelection) - dragStart = undefined - dragEnd = undefined - dragSide = undefined - dragEndSide = undefined - dragMoved = false - return - } - - pendingSelectionEnd = true - scheduleDragUpdate() - scheduleSelectionUpdate() - - dragStart = undefined - dragEnd = undefined - dragSide = undefined - dragEndSide = undefined - dragMoved = false - } - - const handleSelectionChange = () => { - if (props.enableLineSelection !== true) return - if (dragStart === undefined) return - - const selection = window.getSelection() - if (!selection || selection.isCollapsed) return - - scheduleSelectionUpdate() - } - - createEffect(() => { - const opts = options() - const workerPool = large() ? getWorkerPool("unified") : getWorkerPool(props.diffStyle) - const virtualizer = getVirtualizer() - const annotations = local.annotations - const beforeContents = typeof local.before?.contents === "string" ? local.before.contents : "" - const afterContents = typeof local.after?.contents === "string" ? local.after.contents : "" - - const cacheKey = (contents: string) => { - if (!large()) return sampledChecksum(contents, contents.length) - return sampledChecksum(contents) - } - - instance?.cleanUp() - instance = virtualizer - ? new VirtualizedFileDiff<T>(opts, virtualizer, virtualMetrics, workerPool) - : new FileDiff<T>(opts, workerPool) - setCurrent(instance) - - container.innerHTML = "" - instance.render({ - oldFile: { - ...local.before, - contents: beforeContents, - cacheKey: cacheKey(beforeContents), - }, - newFile: { - ...local.after, - contents: afterContents, - cacheKey: cacheKey(afterContents), - }, - lineAnnotations: annotations, - containerWrapper: container, - }) - - applyScheme() - - setRendered((value) => value + 1) - notifyRendered() - }) - - createEffect(() => { - if (typeof document === "undefined") return - if (typeof MutationObserver === "undefined") return - - const root = document.documentElement - const monitor = new MutationObserver(() => applyScheme()) - monitor.observe(root, { attributes: true, attributeFilter: ["data-color-scheme"] }) - applyScheme() - - onCleanup(() => monitor.disconnect()) - }) - - createEffect(() => { - rendered() - const ranges = local.commentedLines ?? [] - requestAnimationFrame(() => applyCommentedLines(ranges)) - }) - - createEffect(() => { - const selected = local.selectedLines ?? null - setSelectedLines(selected) - }) - - createEffect(() => { - if (props.enableLineSelection !== true) return - - container.addEventListener("mousedown", handleMouseDown) - container.addEventListener("mousemove", handleMouseMove) - window.addEventListener("mouseup", handleMouseUp) - document.addEventListener("selectionchange", handleSelectionChange) - - onCleanup(() => { - container.removeEventListener("mousedown", handleMouseDown) - container.removeEventListener("mousemove", handleMouseMove) - window.removeEventListener("mouseup", handleMouseUp) - document.removeEventListener("selectionchange", handleSelectionChange) - }) - }) - - onCleanup(() => { - observer?.disconnect() - - if (selectionFrame !== undefined) { - cancelAnimationFrame(selectionFrame) - selectionFrame = undefined - } - - if (dragFrame !== undefined) { - cancelAnimationFrame(dragFrame) - dragFrame = undefined - } - - dragStart = undefined - dragEnd = undefined - dragSide = undefined - dragEndSide = undefined - dragMoved = false - lastSelection = null - pendingSelectionEnd = false - - instance?.cleanUp() - setCurrent(undefined) - sharedVirtualizer?.release() - sharedVirtualizer = undefined - }) - - return <div data-component="diff" style={styleVariables} ref={container} /> -} diff --git a/packages/ui/src/components/dock-prompt.stories.tsx b/packages/ui/src/components/dock-prompt.stories.tsx new file mode 100644 index 0000000000..de017a1ba2 --- /dev/null +++ b/packages/ui/src/components/dock-prompt.stories.tsx @@ -0,0 +1,62 @@ +// @ts-nocheck +import * as mod from "./dock-prompt" +import { create } from "../storybook/scaffold" + +const docs = `### Overview +Docked prompt layout for questions and permission requests. + +Use with form controls or confirmation buttons in the footer. + +### API +- Required: \`kind\` (question | permission), \`header\`, \`children\`, \`footer\`. +- Optional: \`ref\` for measuring or focus management. + +### Variants and states +- Question and permission layouts (data attributes). + +### Behavior +- Pure layout component; behavior handled by parent. + +### Accessibility +- Ensure header and footer content provide clear context and actions. + +### Theming/tokens +- Uses \`data-component="dock-prompt"\` with kind data attribute. + +` + +const story = create({ + title: "UI/DockPrompt", + mod, + args: { + kind: "question", + header: "Header", + children: "Prompt content", + footer: "Footer", + }, +}) + +export default { + title: "UI/DockPrompt", + id: "components-dock-prompt", + component: story.meta.component, + tags: ["autodocs"], + parameters: { + docs: { + description: { + component: docs, + }, + }, + }, +} + +export const Basic = story.Basic + +export const Permission = { + args: { + kind: "permission", + header: "Allow access?", + children: "This action needs permission to proceed.", + footer: "Approve or deny", + }, +} diff --git a/packages/ui/src/components/dropdown-menu.stories.tsx b/packages/ui/src/components/dropdown-menu.stories.tsx new file mode 100644 index 0000000000..7a2d644fac --- /dev/null +++ b/packages/ui/src/components/dropdown-menu.stories.tsx @@ -0,0 +1,97 @@ +// @ts-nocheck +import * as mod from "./dropdown-menu" +import { Button } from "./button" + +const docs = `### Overview +Dropdown menu built on Kobalte with composable items, groups, and submenus. + +Use \`DropdownMenu.ItemLabel\`/\`ItemDescription\` for richer rows. + +### API +- Root accepts Kobalte DropdownMenu props (\`open\`, \`defaultOpen\`, \`onOpenChange\`). +- Compose with \`Trigger\`, \`Content\`, \`Item\`, \`Separator\`, and optional \`Sub\` sections. + +### Variants and states +- Supports item groups, separators, and nested submenus. + +### Behavior +- Menu opens from trigger and renders in a portal by default. + +### Accessibility +- TODO: confirm keyboard navigation from Kobalte. + +### Theming/tokens +- Uses \`data-component="dropdown-menu"\` and slot attributes for styling. + +` + +export default { + title: "UI/DropdownMenu", + id: "components-dropdown-menu", + component: mod.DropdownMenu, + tags: ["autodocs"], + parameters: { + docs: { + description: { + component: docs, + }, + }, + }, +} + +export const Basic = { + render: () => ( + <mod.DropdownMenu defaultOpen> + <mod.DropdownMenu.Trigger as={Button} variant="secondary" size="small"> + Open menu + </mod.DropdownMenu.Trigger> + <mod.DropdownMenu.Portal> + <mod.DropdownMenu.Content> + <mod.DropdownMenu.Group> + <mod.DropdownMenu.GroupLabel>Actions</mod.DropdownMenu.GroupLabel> + <mod.DropdownMenu.Item> + <mod.DropdownMenu.ItemLabel>New file</mod.DropdownMenu.ItemLabel> + </mod.DropdownMenu.Item> + <mod.DropdownMenu.Item> + <mod.DropdownMenu.ItemLabel>Rename</mod.DropdownMenu.ItemLabel> + <mod.DropdownMenu.ItemDescription>Shift+R</mod.DropdownMenu.ItemDescription> + </mod.DropdownMenu.Item> + </mod.DropdownMenu.Group> + <mod.DropdownMenu.Separator /> + <mod.DropdownMenu.Sub> + <mod.DropdownMenu.SubTrigger>More options</mod.DropdownMenu.SubTrigger> + <mod.DropdownMenu.SubContent> + <mod.DropdownMenu.Item> + <mod.DropdownMenu.ItemLabel>Duplicate</mod.DropdownMenu.ItemLabel> + </mod.DropdownMenu.Item> + <mod.DropdownMenu.Item> + <mod.DropdownMenu.ItemLabel>Move</mod.DropdownMenu.ItemLabel> + </mod.DropdownMenu.Item> + </mod.DropdownMenu.SubContent> + </mod.DropdownMenu.Sub> + </mod.DropdownMenu.Content> + </mod.DropdownMenu.Portal> + </mod.DropdownMenu> + ), +} + +export const CheckboxRadio = { + render: () => ( + <mod.DropdownMenu defaultOpen> + <mod.DropdownMenu.Trigger as={Button} variant="secondary" size="small"> + Open menu + </mod.DropdownMenu.Trigger> + <mod.DropdownMenu.Portal> + <mod.DropdownMenu.Content> + <mod.DropdownMenu.CheckboxItem checked>Show line numbers</mod.DropdownMenu.CheckboxItem> + <mod.DropdownMenu.CheckboxItem>Wrap lines</mod.DropdownMenu.CheckboxItem> + <mod.DropdownMenu.Separator /> + <mod.DropdownMenu.RadioGroup value="compact"> + <mod.DropdownMenu.RadioItem value="compact">Compact</mod.DropdownMenu.RadioItem> + <mod.DropdownMenu.RadioItem value="comfortable">Comfortable</mod.DropdownMenu.RadioItem> + </mod.DropdownMenu.RadioGroup> + </mod.DropdownMenu.Content> + </mod.DropdownMenu.Portal> + </mod.DropdownMenu> + ), +} diff --git a/packages/ui/src/components/favicon.stories.tsx b/packages/ui/src/components/favicon.stories.tsx new file mode 100644 index 0000000000..a693c0f460 --- /dev/null +++ b/packages/ui/src/components/favicon.stories.tsx @@ -0,0 +1,49 @@ +// @ts-nocheck +import * as mod from "./favicon" + +const docs = `### Overview +Injects favicon and app icon meta tags for the document head. + +Render once near the app root (head management). + +### API +- No props. + +### Variants and states +- Single configuration. + +### Behavior +- Registers link and meta tags via Solid Meta components. + +### Accessibility +- Not applicable. + +### Theming/tokens +- Not applicable. + +` + +export default { + title: "UI/Favicon", + id: "components-favicon", + component: mod.Favicon, + tags: ["autodocs"], + parameters: { + docs: { + description: { + component: docs, + }, + }, + }, +} + +export const Basic = { + render: () => ( + <div style={{ display: "grid", gap: "8px" }}> + <mod.Favicon /> + <div style={{ color: "var(--text-weak)", "font-size": "12px" }}> + Head tags are injected for favicon and app icons. + </div> + </div> + ), +} diff --git a/packages/ui/src/components/file-icon.css b/packages/ui/src/components/file-icon.css index a49674a90d..5776425de3 100644 --- a/packages/ui/src/components/file-icon.css +++ b/packages/ui/src/components/file-icon.css @@ -1,4 +1,5 @@ [data-component="file-icon"] { + display: block; flex-shrink: 0; width: 16px; height: 16px; diff --git a/packages/ui/src/components/file-icon.stories.tsx b/packages/ui/src/components/file-icon.stories.tsx new file mode 100644 index 0000000000..937328502f --- /dev/null +++ b/packages/ui/src/components/file-icon.stories.tsx @@ -0,0 +1,94 @@ +// @ts-nocheck +import * as mod from "./file-icon" +import { create } from "../storybook/scaffold" + +const docs = `### Overview +File and folder icon renderer based on file name and extension. + +Use in file trees and lists. + +### API +- Required: \`node\` with \`path\` and \`type\`. +- Optional: \`expanded\` (for folders), \`mono\` for monochrome rendering. + +### Variants and states +- Folder vs file icons; expanded folder variant. + +### Behavior +- Maps file names and extensions to sprite icons. + +### Accessibility +- Provide adjacent text labels for filenames; icons are decorative. + +### Theming/tokens +- Uses \`data-component="file-icon"\` and sprite-based styling. + +` + +const story = create({ + title: "UI/FileIcon", + mod, + args: { + node: { path: "package.json", type: "file" }, + mono: true, + }, +}) + +export default { + title: "UI/FileIcon", + id: "components-file-icon", + component: story.meta.component, + tags: ["autodocs"], + parameters: { + docs: { + description: { + component: docs, + }, + }, + }, +} + +export const Basic = story.Basic + +export const Folder = { + args: { + node: { path: "src", type: "directory" }, + expanded: true, + mono: false, + }, +} + +export const Samples = { + render: () => { + const items = [ + { path: "README.md", type: "file" }, + { path: "package.json", type: "file" }, + { path: "tsconfig.json", type: "file" }, + { path: "index.ts", type: "file" }, + { path: "styles.css", type: "file" }, + { path: "logo.svg", type: "file" }, + { path: "photo.png", type: "file" }, + { path: "Dockerfile", type: "file" }, + { path: ".env", type: "file" }, + { path: "src", type: "directory" }, + { path: "public", type: "directory" }, + ] as const + + return ( + <div + style={{ + display: "grid", + gap: "12px", + "grid-template-columns": "repeat(auto-fill, minmax(120px, 1fr))", + }} + > + {items.map((node) => ( + <div style={{ display: "flex", gap: "8px", "align-items": "center" }}> + <mod.FileIcon node={{ path: node.path, type: node.type }} mono={false} /> + <div style={{ "font-size": "12px", color: "var(--text-weak)" }}>{node.path}</div> + </div> + ))} + </div> + ) + }, +} diff --git a/packages/ui/src/components/file-icon.tsx b/packages/ui/src/components/file-icon.tsx index 405cbe163a..133cb169c7 100644 --- a/packages/ui/src/components/file-icon.tsx +++ b/packages/ui/src/components/file-icon.tsx @@ -1,10 +1,8 @@ import type { Component, JSX } from "solid-js" -import { createMemo, splitProps, Show } from "solid-js" +import { createMemo, createUniqueId, splitProps, Show } from "solid-js" import sprite from "./file-icons/sprite.svg" import type { IconName } from "./file-icons/types" -let filter = 0 - export type FileIconProps = JSX.GSVGAttributes<SVGSVGElement> & { node: { path: string; type: "file" | "directory" } expanded?: boolean @@ -14,7 +12,7 @@ export type FileIconProps = JSX.GSVGAttributes<SVGSVGElement> & { export const FileIcon: Component<FileIconProps> = (props) => { const [local, rest] = splitProps(props, ["node", "class", "classList", "expanded", "mono"]) const name = createMemo(() => chooseIconName(local.node.path, local.node.type, local.expanded || false)) - const id = `file-icon-mono-${filter++}` + const id = `file-icon-mono-${createUniqueId()}` return ( <svg data-component="file-icon" @@ -24,15 +22,14 @@ export const FileIcon: Component<FileIconProps> = (props) => { [local.class ?? ""]: !!local.class, }} > - <Show when={local.mono}> + <Show when={local.mono} fallback={<use href={`${sprite}#${name()}`} />}> <defs> - <filter id={id} color-interpolation-filters="sRGB"> - <feFlood flood-color="currentColor" result="flood" /> - <feComposite in="flood" in2="SourceAlpha" operator="in" /> - </filter> + <mask id={id} mask-type="alpha"> + <use href={`${sprite}#${name()}`} /> + </mask> </defs> + <rect width="100%" height="100%" fill="currentColor" mask={`url(#${id})`} /> </Show> - <use href={`${sprite}#${name()}`} filter={local.mono ? `url(#${id})` : undefined} /> </svg> ) } diff --git a/packages/ui/src/components/file-media.tsx b/packages/ui/src/components/file-media.tsx new file mode 100644 index 0000000000..2fd54588a3 --- /dev/null +++ b/packages/ui/src/components/file-media.tsx @@ -0,0 +1,265 @@ +import type { FileContent } from "@opencode-ai/sdk/v2" +import { createEffect, createMemo, createResource, Match, on, Show, Switch, type JSX } from "solid-js" +import { useI18n } from "../context/i18n" +import { + dataUrlFromMediaValue, + hasMediaValue, + isBinaryContent, + mediaKindFromPath, + normalizeMimeType, + svgTextFromValue, +} from "../pierre/media" + +export type FileMediaOptions = { + mode?: "auto" | "off" + path?: string + current?: unknown + before?: unknown + after?: unknown + readFile?: (path: string) => Promise<FileContent | undefined> + onLoad?: () => void + onError?: (ctx: { kind: "image" | "audio" | "svg" }) => void +} + +function mediaValue(cfg: FileMediaOptions, mode: "image" | "audio") { + if (cfg.current !== undefined) return cfg.current + if (mode === "image") return cfg.after ?? cfg.before + return cfg.after ?? cfg.before +} + +export function FileMedia(props: { media?: FileMediaOptions; fallback: () => JSX.Element }) { + const i18n = useI18n() + const cfg = () => props.media + const kind = createMemo(() => { + const media = cfg() + if (!media || media.mode === "off") return + return mediaKindFromPath(media.path) + }) + + const isBinary = createMemo(() => { + const media = cfg() + if (!media || media.mode === "off") return false + if (kind()) return false + return isBinaryContent(media.current as any) + }) + + const onLoad = () => props.media?.onLoad?.() + + const deleted = createMemo(() => { + const media = cfg() + const k = kind() + if (!media || !k) return false + if (k === "svg") return false + if (media.current !== undefined) return false + return !hasMediaValue(media.after as any) && hasMediaValue(media.before as any) + }) + + const direct = createMemo(() => { + const media = cfg() + const k = kind() + if (!media || (k !== "image" && k !== "audio")) return + return dataUrlFromMediaValue(mediaValue(media, k), k) + }) + + const request = createMemo(() => { + const media = cfg() + const k = kind() + if (!media || (k !== "image" && k !== "audio")) return + if (media.current !== undefined) return + if (deleted()) return + if (direct()) return + if (!media.path || !media.readFile) return + + return { + key: `${k}:${media.path}`, + kind: k, + path: media.path, + readFile: media.readFile, + onError: media.onError, + } + }) + + const [loaded] = createResource(request, async (input) => { + return input.readFile(input.path).then( + (result) => { + const src = dataUrlFromMediaValue(result as any, input.kind) + if (!src) { + input.onError?.({ kind: input.kind }) + return { key: input.key, error: true as const } + } + + return { + key: input.key, + src, + mime: input.kind === "audio" ? normalizeMimeType(result?.mimeType) : undefined, + } + }, + () => { + input.onError?.({ kind: input.kind }) + return { key: input.key, error: true as const } + }, + ) + }) + + const remote = createMemo(() => { + const input = request() + const value = loaded() + if (!input || !value || value.key !== input.key) return + return value + }) + + const src = createMemo(() => { + const value = remote() + return direct() ?? (value && "src" in value ? value.src : undefined) + }) + const status = createMemo(() => { + if (direct()) return "ready" as const + if (!request()) return "idle" as const + if (loaded.loading) return "loading" as const + if (remote()?.error) return "error" as const + if (src()) return "ready" as const + return "idle" as const + }) + const audioMime = createMemo(() => { + const value = remote() + return value && "mime" in value ? value.mime : undefined + }) + + const svgSource = createMemo(() => { + const media = cfg() + if (!media || kind() !== "svg") return + return svgTextFromValue(media.current as any) + }) + const svgSrc = createMemo(() => { + const media = cfg() + if (!media || kind() !== "svg") return + return dataUrlFromMediaValue(media.current as any, "svg") + }) + const svgInvalid = createMemo(() => { + const media = cfg() + if (!media || kind() !== "svg") return + if (svgSource() !== undefined) return + if (!hasMediaValue(media.current as any)) return + return [media.path, media.current] as const + }) + + createEffect( + on( + svgInvalid, + (value) => { + if (!value) return + cfg()?.onError?.({ kind: "svg" }) + }, + { defer: true }, + ), + ) + + const kindLabel = (value: "image" | "audio") => + i18n.t(value === "image" ? "ui.fileMedia.kind.image" : "ui.fileMedia.kind.audio") + + return ( + <Switch> + <Match when={kind() === "image" || kind() === "audio"}> + <Show + when={src()} + fallback={(() => { + const media = cfg() + const k = kind() + if (!media || (k !== "image" && k !== "audio")) return props.fallback() + const label = kindLabel(k) + + if (deleted()) { + return ( + <div class="flex min-h-40 items-center justify-center px-6 py-4 text-center text-text-weak"> + {i18n.t("ui.fileMedia.state.removed", { kind: label })} + </div> + ) + } + if (status() === "loading") { + return ( + <div class="flex min-h-40 items-center justify-center px-6 py-4 text-center text-text-weak"> + {i18n.t("ui.fileMedia.state.loading", { kind: label })} + </div> + ) + } + if (status() === "error") { + return ( + <div class="flex min-h-40 items-center justify-center px-6 py-4 text-center text-text-weak"> + {i18n.t("ui.fileMedia.state.error", { kind: label })} + </div> + ) + } + return ( + <div class="flex min-h-40 items-center justify-center px-6 py-4 text-center text-text-weak"> + {i18n.t("ui.fileMedia.state.unavailable", { kind: label })} + </div> + ) + })()} + > + {(value) => { + const k = kind() + if (k !== "image" && k !== "audio") return props.fallback() + if (k === "image") { + return ( + <div class="flex justify-center bg-background-stronger px-6 py-4"> + <img + src={value()} + alt={cfg()?.path} + class="max-h-[60vh] max-w-full rounded border border-border-weak-base bg-background-base object-contain" + onLoad={onLoad} + /> + </div> + ) + } + + return ( + <div class="flex justify-center bg-background-stronger px-6 py-4"> + <audio class="w-full max-w-xl" controls preload="metadata" onLoadedMetadata={onLoad}> + <source src={value()} type={audioMime()} /> + </audio> + </div> + ) + }} + </Show> + </Match> + <Match when={kind() === "svg"}> + {(() => { + if (svgSource() === undefined && svgSrc() == null) return props.fallback() + + return ( + <div class="flex flex-col gap-4 px-6 py-4"> + <Show when={svgSource() !== undefined}>{props.fallback()}</Show> + <Show when={svgSrc()}> + {(value) => ( + <div class="flex justify-center"> + <img + src={value()} + alt={cfg()?.path} + class="max-h-[60vh] max-w-full rounded border border-border-weak-base bg-background-base object-contain" + onLoad={onLoad} + /> + </div> + )} + </Show> + </div> + ) + })()} + </Match> + <Match when={isBinary()}> + <div class="flex min-h-56 flex-col items-center justify-center gap-2 px-6 py-10 text-center"> + <div class="text-14-semibold text-text-strong"> + {cfg()?.path?.split("/").pop() ?? i18n.t("ui.fileMedia.binary.title")} + </div> + <div class="text-14-regular text-text-weak"> + {(() => { + const path = cfg()?.path + if (!path) return i18n.t("ui.fileMedia.binary.description.default") + return i18n.t("ui.fileMedia.binary.description.path", { path }) + })()} + </div> + </div> + </Match> + <Match when={true}>{props.fallback()}</Match> + </Switch> + ) +} diff --git a/packages/ui/src/components/file-search.tsx b/packages/ui/src/components/file-search.tsx new file mode 100644 index 0000000000..d83fdb16a3 --- /dev/null +++ b/packages/ui/src/components/file-search.tsx @@ -0,0 +1,69 @@ +import { Portal } from "solid-js/web" +import { Icon } from "./icon" + +export function FileSearchBar(props: { + pos: () => { top: number; right: number } + query: () => string + index: () => number + count: () => number + setInput: (el: HTMLInputElement) => void + onInput: (value: string) => void + onKeyDown: (event: KeyboardEvent) => void + onClose: () => void + onPrev: () => void + onNext: () => void +}) { + return ( + <Portal> + <div + class="fixed z-50 flex h-8 items-center gap-2 rounded-md border border-border-base bg-background-base px-3 shadow-md" + style={{ + top: `${props.pos().top}px`, + right: `${props.pos().right}px`, + }} + onPointerDown={(e) => e.stopPropagation()} + > + <Icon name="magnifying-glass" size="small" class="text-text-weak shrink-0" /> + <input + ref={props.setInput} + placeholder="Find" + value={props.query()} + class="w-40 bg-transparent outline-none text-14-regular text-text-strong placeholder:text-text-weak" + onInput={(e) => props.onInput(e.currentTarget.value)} + onKeyDown={(e) => props.onKeyDown(e as KeyboardEvent)} + /> + <div class="shrink-0 text-12-regular text-text-weak tabular-nums text-right" style={{ width: "10ch" }}> + {props.count() ? `${props.index() + 1}/${props.count()}` : "0/0"} + </div> + <div class="flex items-center"> + <button + type="button" + class="size-6 grid place-items-center rounded text-text-weak hover:bg-surface-base-hover hover:text-text-strong disabled:opacity-40 disabled:pointer-events-none" + disabled={props.count() === 0} + aria-label="Previous match" + onClick={props.onPrev} + > + <Icon name="chevron-down" size="small" class="rotate-180" /> + </button> + <button + type="button" + class="size-6 grid place-items-center rounded text-text-weak hover:bg-surface-base-hover hover:text-text-strong disabled:opacity-40 disabled:pointer-events-none" + disabled={props.count() === 0} + aria-label="Next match" + onClick={props.onNext} + > + <Icon name="chevron-down" size="small" /> + </button> + </div> + <button + type="button" + class="size-6 grid place-items-center rounded text-text-weak hover:bg-surface-base-hover hover:text-text-strong" + aria-label="Close search" + onClick={props.onClose} + > + <Icon name="close-small" size="small" /> + </button> + </div> + </Portal> + ) +} diff --git a/packages/ui/src/components/file-ssr.tsx b/packages/ui/src/components/file-ssr.tsx new file mode 100644 index 0000000000..9526907831 --- /dev/null +++ b/packages/ui/src/components/file-ssr.tsx @@ -0,0 +1,178 @@ +import { DIFFS_TAG_NAME, FileDiff, VirtualizedFileDiff } from "@pierre/diffs" +import { type PreloadMultiFileDiffResult } from "@pierre/diffs/ssr" +import { createEffect, onCleanup, onMount, Show, splitProps } from "solid-js" +import { Dynamic, isServer } from "solid-js/web" +import { useWorkerPool } from "../context/worker-pool" +import { createDefaultOptions, styleVariables } from "../pierre" +import { markCommentedDiffLines } from "../pierre/commented-lines" +import { fixDiffSelection } from "../pierre/diff-selection" +import { + applyViewerScheme, + clearReadyWatcher, + createReadyWatcher, + notifyShadowReady, + observeViewerScheme, +} from "../pierre/file-runtime" +import { acquireVirtualizer, virtualMetrics } from "../pierre/virtualizer" +import { File, type DiffFileProps, type FileProps } from "./file" + +type SSRDiffFileProps<T> = DiffFileProps<T> & { + preloadedDiff: PreloadMultiFileDiffResult<T> +} + +function DiffSSRViewer<T>(props: SSRDiffFileProps<T>) { + let container!: HTMLDivElement + let fileDiffRef!: HTMLElement + let fileDiffInstance: FileDiff<T> | undefined + let sharedVirtualizer: NonNullable<ReturnType<typeof acquireVirtualizer>> | undefined + + const ready = createReadyWatcher() + const workerPool = useWorkerPool(props.diffStyle) + + const [local, others] = splitProps(props, [ + "mode", + "media", + "before", + "after", + "class", + "classList", + "annotations", + "selectedLines", + "commentedLines", + "onLineSelected", + "onLineSelectionEnd", + "onLineNumberSelectionEnd", + "onRendered", + "preloadedDiff", + ]) + + const getRoot = () => fileDiffRef?.shadowRoot ?? undefined + + const getVirtualizer = () => { + if (sharedVirtualizer) return sharedVirtualizer.virtualizer + const result = acquireVirtualizer(container) + if (!result) return + sharedVirtualizer = result + return result.virtualizer + } + + const setSelectedLines = (range: DiffFileProps<T>["selectedLines"], attempt = 0) => { + const diff = fileDiffInstance + if (!diff) return + + const fixed = fixDiffSelection(getRoot(), range ?? null) + if (fixed === undefined) { + if (attempt >= 120) return + requestAnimationFrame(() => setSelectedLines(range ?? null, attempt + 1)) + return + } + + diff.setSelectedLines(fixed) + } + + const notifyRendered = () => { + notifyShadowReady({ + state: ready, + container, + getRoot, + isReady: (root) => root.querySelector("[data-line]") != null, + settleFrames: 1, + onReady: () => { + setSelectedLines(local.selectedLines ?? null) + local.onRendered?.() + }, + }) + } + + onMount(() => { + if (isServer) return + + onCleanup(observeViewerScheme(() => fileDiffRef)) + + const virtualizer = getVirtualizer() + fileDiffInstance = virtualizer + ? new VirtualizedFileDiff<T>( + { + ...createDefaultOptions(props.diffStyle), + ...others, + ...local.preloadedDiff, + }, + virtualizer, + virtualMetrics, + workerPool, + ) + : new FileDiff<T>( + { + ...createDefaultOptions(props.diffStyle), + ...others, + ...local.preloadedDiff, + }, + workerPool, + ) + + applyViewerScheme(fileDiffRef) + + // @ts-expect-error private field required for hydration + fileDiffInstance.fileContainer = fileDiffRef + fileDiffInstance.hydrate({ + oldFile: local.before, + newFile: local.after, + lineAnnotations: local.annotations ?? [], + fileContainer: fileDiffRef, + containerWrapper: container, + }) + + notifyRendered() + }) + + createEffect(() => { + const diff = fileDiffInstance + if (!diff) return + diff.setLineAnnotations(local.annotations ?? []) + diff.rerender() + }) + + createEffect(() => { + setSelectedLines(local.selectedLines ?? null) + }) + + createEffect(() => { + const ranges = local.commentedLines ?? [] + requestAnimationFrame(() => { + const root = getRoot() + if (!root) return + markCommentedDiffLines(root, ranges) + }) + }) + + onCleanup(() => { + clearReadyWatcher(ready) + fileDiffInstance?.cleanUp() + sharedVirtualizer?.release() + sharedVirtualizer = undefined + }) + + return ( + <div + data-component="file" + data-mode="diff" + style={styleVariables} + class={local.class} + classList={local.classList} + ref={container} + > + <Dynamic component={DIFFS_TAG_NAME} ref={fileDiffRef} id="ssr-diff"> + <Show when={isServer}> + <template shadowrootmode="open" innerHTML={local.preloadedDiff.prerenderedHTML} /> + </Show> + </Dynamic> + </div> + ) +} + +export type FileSSRProps<T = {}> = FileProps<T> + +export function FileSSR<T>(props: FileSSRProps<T>) { + if (props.mode !== "diff" || !props.preloadedDiff) return File(props) + return DiffSSRViewer(props as SSRDiffFileProps<T>) +} diff --git a/packages/ui/src/components/diff.css b/packages/ui/src/components/file.css similarity index 86% rename from packages/ui/src/components/diff.css rename to packages/ui/src/components/file.css index 1d94e417ae..a9150e1450 100644 --- a/packages/ui/src/components/diff.css +++ b/packages/ui/src/components/file.css @@ -1,6 +1,12 @@ -[data-component="diff"] { +[data-component="file"] { content-visibility: auto; +} +[data-component="file"][data-mode="text"] { + overflow: hidden; +} + +[data-component="file"][data-mode="diff"] { [data-slot="diff-hunk-separator-line-number"] { position: sticky; left: 0; @@ -17,6 +23,7 @@ color: var(--icon-strong-base); } } + [data-slot="diff-hunk-separator-content"] { position: sticky; background-color: var(--surface-diff-hidden-base); diff --git a/packages/ui/src/components/file.tsx b/packages/ui/src/components/file.tsx new file mode 100644 index 0000000000..f42fbb24d2 --- /dev/null +++ b/packages/ui/src/components/file.tsx @@ -0,0 +1,1176 @@ +import { sampledChecksum } from "@opencode-ai/util/encode" +import { + DEFAULT_VIRTUAL_FILE_METRICS, + type ExpansionDirections, + type DiffLineAnnotation, + type FileContents, + type FileDiffMetadata, + File as PierreFile, + type FileDiffOptions, + FileDiff, + type FileOptions, + type LineAnnotation, + type SelectedLineRange, + type VirtualFileMetrics, + VirtualizedFile, + VirtualizedFileDiff, + Virtualizer, +} from "@pierre/diffs" +import { type PreloadMultiFileDiffResult } from "@pierre/diffs/ssr" +import { createMediaQuery } from "@solid-primitives/media" +import { ComponentProps, createEffect, createMemo, createSignal, onCleanup, onMount, Show, splitProps } from "solid-js" +import { createDefaultOptions, styleVariables } from "../pierre" +import { markCommentedDiffLines, markCommentedFileLines } from "../pierre/commented-lines" +import { fixDiffSelection, findDiffSide, type DiffSelectionSide } from "../pierre/diff-selection" +import { createFileFind, type FileFindReveal } from "../pierre/file-find" +import { + applyViewerScheme, + clearReadyWatcher, + createReadyWatcher, + getViewerHost, + getViewerRoot, + notifyShadowReady, + observeViewerScheme, +} from "../pierre/file-runtime" +import { + findCodeSelectionSide, + findDiffLineNumber, + findElement, + findFileLineNumber, + readShadowLineSelection, +} from "../pierre/file-selection" +import { createLineNumberSelectionBridge, restoreShadowTextSelection } from "../pierre/selection-bridge" +import { acquireVirtualizer, virtualMetrics } from "../pierre/virtualizer" +import { getWorkerPool } from "../pierre/worker" +import { FileMedia, type FileMediaOptions } from "./file-media" +import { FileSearchBar } from "./file-search" + +const VIRTUALIZE_BYTES = 500_000 + +const codeMetrics = { + ...DEFAULT_VIRTUAL_FILE_METRICS, + lineHeight: 24, + fileGap: 0, +} satisfies Partial<VirtualFileMetrics> + +type SharedProps<T> = { + annotations?: LineAnnotation<T>[] | DiffLineAnnotation<T>[] + selectedLines?: SelectedLineRange | null + commentedLines?: SelectedLineRange[] + onLineNumberSelectionEnd?: (selection: SelectedLineRange | null) => void + onRendered?: () => void + class?: string + classList?: ComponentProps<"div">["classList"] + media?: FileMediaOptions + search?: FileSearchControl +} + +export type FileSearchReveal = FileFindReveal + +export type FileSearchHandle = { + focus: () => void + setQuery: (value: string) => void + clear: () => void + reveal: (hit: FileSearchReveal) => boolean + expand: (hit: FileSearchReveal) => boolean + refresh: () => void +} + +export type FileSearchControl = { + shortcuts?: "global" | "disabled" + showBar?: boolean + disableVirtualization?: boolean + register: (handle: FileSearchHandle | null) => void +} + +export type TextFileProps<T = {}> = FileOptions<T> & + SharedProps<T> & { + mode: "text" + file: FileContents + annotations?: LineAnnotation<T>[] + preloadedDiff?: PreloadMultiFileDiffResult<T> + } + +export type DiffFileProps<T = {}> = FileDiffOptions<T> & + SharedProps<T> & { + mode: "diff" + before: FileContents + after: FileContents + annotations?: DiffLineAnnotation<T>[] + preloadedDiff?: PreloadMultiFileDiffResult<T> + } + +export type FileProps<T = {}> = TextFileProps<T> | DiffFileProps<T> + +const sharedKeys = [ + "mode", + "media", + "class", + "classList", + "annotations", + "selectedLines", + "commentedLines", + "search", + "onLineSelected", + "onLineSelectionEnd", + "onLineNumberSelectionEnd", + "onRendered", + "preloadedDiff", +] as const + +const textKeys = ["file", ...sharedKeys] as const +const diffKeys = ["before", "after", ...sharedKeys] as const + +function expansionForHit(diff: FileDiffMetadata, hit: FileSearchReveal) { + if (diff.isPartial || diff.hunks.length === 0) return + + const side = + hit.side === "deletions" + ? { + start: (hunk: FileDiffMetadata["hunks"][number]) => hunk.deletionStart, + count: (hunk: FileDiffMetadata["hunks"][number]) => hunk.deletionCount, + } + : { + start: (hunk: FileDiffMetadata["hunks"][number]) => hunk.additionStart, + count: (hunk: FileDiffMetadata["hunks"][number]) => hunk.additionCount, + } + + for (let i = 0; i < diff.hunks.length; i++) { + const hunk = diff.hunks[i] + const start = side.start(hunk) + if (hit.line < start) { + return { + index: i, + direction: i === 0 ? "down" : "both", + } satisfies { index: number; direction: ExpansionDirections } + } + + const end = start + Math.max(side.count(hunk) - 1, -1) + if (hit.line <= end) return + } + + return { + index: diff.hunks.length, + direction: "up", + } satisfies { index: number; direction: ExpansionDirections } +} + +// --------------------------------------------------------------------------- +// Shared viewer hook +// --------------------------------------------------------------------------- + +type MouseHit = { + line: number | undefined + numberColumn: boolean + side?: DiffSelectionSide +} + +type ViewerConfig = { + enableLineSelection: () => boolean + search: () => FileSearchControl | undefined + selectedLines: () => SelectedLineRange | null | undefined + commentedLines: () => SelectedLineRange[] + onLineSelectionEnd: (range: SelectedLineRange | null) => void + + // mode-specific callbacks + lineFromMouseEvent: (event: MouseEvent) => MouseHit + setSelectedLines: (range: SelectedLineRange | null, preserve?: { root: ShadowRoot; text: Range }) => void + updateSelection: (preserveTextSelection: boolean) => void + buildDragSelection: () => SelectedLineRange | undefined + buildClickSelection: () => SelectedLineRange | undefined + onDragStart: (hit: MouseHit) => void + onDragMove: (hit: MouseHit) => void + onDragReset: () => void + markCommented: (root: ShadowRoot, ranges: SelectedLineRange[]) => void +} + +function useFileViewer(config: ViewerConfig) { + let wrapper!: HTMLDivElement + let container!: HTMLDivElement + let overlay!: HTMLDivElement + let selectionFrame: number | undefined + let dragFrame: number | undefined + let dragStart: number | undefined + let dragEnd: number | undefined + let dragMoved = false + let lastSelection: SelectedLineRange | null = null + let pendingSelectionEnd = false + + const ready = createReadyWatcher() + const bridge = createLineNumberSelectionBridge() + const [rendered, setRendered] = createSignal(0) + + const getRoot = () => getViewerRoot(container) + const getHost = () => getViewerHost(container) + + const find = createFileFind({ + wrapper: () => wrapper, + overlay: () => overlay, + getRoot, + shortcuts: config.search()?.shortcuts, + }) + + // -- selection scheduling -- + + const scheduleSelectionUpdate = () => { + if (selectionFrame !== undefined) return + selectionFrame = requestAnimationFrame(() => { + selectionFrame = undefined + const finishing = pendingSelectionEnd + config.updateSelection(finishing) + if (!pendingSelectionEnd) return + pendingSelectionEnd = false + config.onLineSelectionEnd(lastSelection) + }) + } + + const scheduleDragUpdate = () => { + if (dragFrame !== undefined) return + dragFrame = requestAnimationFrame(() => { + dragFrame = undefined + const selected = config.buildDragSelection() + if (selected) config.setSelectedLines(selected) + }) + } + + // -- mouse handlers -- + + const handleMouseDown = (event: MouseEvent) => { + if (!config.enableLineSelection()) return + if (event.button !== 0) return + + const hit = config.lineFromMouseEvent(event) + if (hit.numberColumn) { + bridge.begin(true, hit.line) + return + } + if (hit.line === undefined) return + + bridge.begin(false, hit.line) + dragStart = hit.line + dragEnd = hit.line + dragMoved = false + config.onDragStart(hit) + } + + const handleMouseMove = (event: MouseEvent) => { + if (!config.enableLineSelection()) return + + const hit = config.lineFromMouseEvent(event) + if (bridge.track(event.buttons, hit.line)) return + if (dragStart === undefined) return + + if ((event.buttons & 1) === 0) { + dragStart = undefined + dragEnd = undefined + dragMoved = false + config.onDragReset() + bridge.finish() + return + } + + if (hit.line === undefined) return + dragEnd = hit.line + dragMoved = true + config.onDragMove(hit) + scheduleDragUpdate() + } + + const handleMouseUp = () => { + if (!config.enableLineSelection()) return + if (bridge.finish() === "numbers") return + if (dragStart === undefined) return + + if (!dragMoved) { + pendingSelectionEnd = false + const selected = config.buildClickSelection() + if (selected) config.setSelectedLines(selected) + config.onLineSelectionEnd(lastSelection) + dragStart = undefined + dragEnd = undefined + dragMoved = false + config.onDragReset() + return + } + + pendingSelectionEnd = true + scheduleDragUpdate() + scheduleSelectionUpdate() + + dragStart = undefined + dragEnd = undefined + dragMoved = false + config.onDragReset() + } + + const handleSelectionChange = () => { + if (!config.enableLineSelection()) return + if (dragStart === undefined) return + const selection = window.getSelection() + if (!selection || selection.isCollapsed) return + scheduleSelectionUpdate() + } + + // -- shared effects -- + + onMount(() => { + onCleanup(observeViewerScheme(getHost)) + }) + + createEffect(() => { + rendered() + const ranges = config.commentedLines() + requestAnimationFrame(() => { + const root = getRoot() + if (!root) return + config.markCommented(root, ranges) + }) + }) + + createEffect(() => { + config.setSelectedLines(config.selectedLines() ?? null) + }) + + createEffect(() => { + if (!config.enableLineSelection()) return + + container.addEventListener("mousedown", handleMouseDown) + container.addEventListener("mousemove", handleMouseMove) + window.addEventListener("mouseup", handleMouseUp) + document.addEventListener("selectionchange", handleSelectionChange) + + onCleanup(() => { + container.removeEventListener("mousedown", handleMouseDown) + container.removeEventListener("mousemove", handleMouseMove) + window.removeEventListener("mouseup", handleMouseUp) + document.removeEventListener("selectionchange", handleSelectionChange) + }) + }) + + onCleanup(() => { + clearReadyWatcher(ready) + + if (selectionFrame !== undefined) cancelAnimationFrame(selectionFrame) + if (dragFrame !== undefined) cancelAnimationFrame(dragFrame) + + selectionFrame = undefined + dragFrame = undefined + dragStart = undefined + dragEnd = undefined + dragMoved = false + bridge.reset() + lastSelection = null + pendingSelectionEnd = false + }) + + return { + get wrapper() { + return wrapper + }, + set wrapper(v: HTMLDivElement) { + wrapper = v + }, + get container() { + return container + }, + set container(v: HTMLDivElement) { + container = v + }, + get overlay() { + return overlay + }, + set overlay(v: HTMLDivElement) { + overlay = v + }, + get dragStart() { + return dragStart + }, + get dragEnd() { + return dragEnd + }, + get lastSelection() { + return lastSelection + }, + set lastSelection(v: SelectedLineRange | null) { + lastSelection = v + }, + ready, + bridge, + rendered, + setRendered, + getRoot, + getHost, + find, + scheduleSelectionUpdate, + } +} + +type Viewer = ReturnType<typeof useFileViewer> + +type ModeAdapter = Omit< + ViewerConfig, + "enableLineSelection" | "search" | "selectedLines" | "commentedLines" | "onLineSelectionEnd" +> + +type ModeConfig = { + enableLineSelection: () => boolean + search: () => FileSearchControl | undefined + selectedLines: () => SelectedLineRange | null | undefined + commentedLines: () => SelectedLineRange[] | undefined + onLineSelectionEnd: (range: SelectedLineRange | null) => void +} + +type RenderTarget = { + cleanUp: () => void +} + +type AnnotationTarget<A> = { + setLineAnnotations: (annotations: A[]) => void + rerender: () => void +} + +type VirtualStrategy = { + get: () => Virtualizer | undefined + cleanup: () => void +} + +function useModeViewer(config: ModeConfig, adapter: ModeAdapter) { + return useFileViewer({ + enableLineSelection: config.enableLineSelection, + search: config.search, + selectedLines: config.selectedLines, + commentedLines: () => config.commentedLines() ?? [], + onLineSelectionEnd: config.onLineSelectionEnd, + ...adapter, + }) +} + +function useSearchHandle(opts: { + search: () => FileSearchControl | undefined + find: ReturnType<typeof createFileFind> + expand?: (hit: FileSearchReveal) => boolean +}) { + createEffect(() => { + const search = opts.search() + if (!search) return + + const handle = { + focus: () => { + opts.find.focus() + }, + setQuery: (value: string) => { + opts.find.activate() + opts.find.setQuery(value, { scroll: false }) + }, + clear: () => { + opts.find.clear() + }, + reveal: (hit: FileSearchReveal) => { + opts.find.activate() + return opts.find.reveal(hit) + }, + expand: (hit: FileSearchReveal) => opts.expand?.(hit) ?? false, + refresh: () => { + opts.find.activate() + opts.find.refresh() + }, + } satisfies FileSearchHandle + + search.register(handle) + onCleanup(() => search.register(null)) + }) +} + +function createLineCallbacks(opts: { + viewer: Viewer + normalize?: (range: SelectedLineRange | null) => SelectedLineRange | null | undefined + onLineSelected?: (range: SelectedLineRange | null) => void + onLineSelectionEnd?: (range: SelectedLineRange | null) => void + onLineNumberSelectionEnd?: (selection: SelectedLineRange | null) => void +}) { + const select = (range: SelectedLineRange | null) => { + if (!opts.normalize) return range + const next = opts.normalize(range) + if (next !== undefined) return next + return range + } + + return { + onLineSelected: (range: SelectedLineRange | null) => { + const next = select(range) + opts.viewer.lastSelection = next + opts.onLineSelected?.(next) + }, + onLineSelectionEnd: (range: SelectedLineRange | null) => { + const next = select(range) + opts.viewer.lastSelection = next + opts.onLineSelectionEnd?.(next) + if (!opts.viewer.bridge.consume(next)) return + requestAnimationFrame(() => opts.onLineNumberSelectionEnd?.(next)) + }, + } +} + +function useAnnotationRerender<A>(opts: { + viewer: Viewer + current: () => AnnotationTarget<A> | undefined + annotations: () => A[] +}) { + createEffect(() => { + opts.viewer.rendered() + const active = opts.current() + if (!active) return + active.setLineAnnotations(opts.annotations()) + active.rerender() + requestAnimationFrame(() => opts.viewer.find.refresh({ reset: true })) + }) +} + +function notifyRendered(opts: { + viewer: Viewer + isReady: (root: ShadowRoot) => boolean + settleFrames?: number + onReady: () => void +}) { + notifyShadowReady({ + state: opts.viewer.ready, + container: opts.viewer.container, + getRoot: opts.viewer.getRoot, + isReady: opts.isReady, + settleFrames: opts.settleFrames, + onReady: opts.onReady, + }) +} + +function renderViewer<I extends RenderTarget>(opts: { + viewer: Viewer + current: I | undefined + create: () => I + assign: (value: I) => void + draw: (value: I) => void + onReady: () => void +}) { + clearReadyWatcher(opts.viewer.ready) + opts.current?.cleanUp() + const next = opts.create() + opts.assign(next) + + opts.viewer.container.innerHTML = "" + opts.draw(next) + + applyViewerScheme(opts.viewer.getHost()) + opts.viewer.setRendered((value) => value + 1) + opts.onReady() +} + +function scrollParent(el: HTMLElement): HTMLElement | undefined { + let parent = el.parentElement + while (parent) { + const style = getComputedStyle(parent) + if (style.overflowY === "auto" || style.overflowY === "scroll") return parent + parent = parent.parentElement + } +} + +function createLocalVirtualStrategy(host: () => HTMLDivElement | undefined, enabled: () => boolean): VirtualStrategy { + let virtualizer: Virtualizer | undefined + let root: Document | HTMLElement | undefined + + const release = () => { + virtualizer?.cleanUp() + virtualizer = undefined + root = undefined + } + + return { + get: () => { + if (!enabled()) { + release() + return + } + if (typeof document === "undefined") return + + const wrapper = host() + if (!wrapper) return + + const next = scrollParent(wrapper) ?? document + if (virtualizer && root === next) return virtualizer + + release() + virtualizer = new Virtualizer() + root = next + virtualizer.setup(next, next instanceof Document ? undefined : wrapper) + return virtualizer + }, + cleanup: release, + } +} + +function createSharedVirtualStrategy(host: () => HTMLDivElement | undefined, enabled: () => boolean): VirtualStrategy { + let shared: NonNullable<ReturnType<typeof acquireVirtualizer>> | undefined + + const release = () => { + shared?.release() + shared = undefined + } + + return { + get: () => { + if (!enabled()) { + release() + return + } + if (shared) return shared.virtualizer + + const container = host() + if (!container) return + + const result = acquireVirtualizer(container) + if (!result) return + shared = result + return result.virtualizer + }, + cleanup: release, + } +} + +function parseLine(node: HTMLElement) { + if (!node.dataset.line) return + const value = parseInt(node.dataset.line, 10) + if (Number.isNaN(value)) return + return value +} + +function mouseHit( + event: MouseEvent, + line: (node: HTMLElement) => number | undefined, + side?: (node: HTMLElement) => DiffSelectionSide | undefined, +): MouseHit { + const path = event.composedPath() + let numberColumn = false + let value: number | undefined + let branch: DiffSelectionSide | undefined + + for (const item of path) { + if (!(item instanceof HTMLElement)) continue + + numberColumn = numberColumn || item.dataset.columnNumber != null + if (value === undefined) value = line(item) + if (branch === undefined && side) branch = side(item) + + if (numberColumn && value !== undefined && (side == null || branch !== undefined)) break + } + + return { + line: value, + numberColumn, + side: branch, + } +} + +function diffMouseSide(node: HTMLElement) { + const type = node.dataset.lineType + if (type === "change-deletion") return "deletions" satisfies DiffSelectionSide + if (type === "change-addition" || type === "change-additions") return "additions" satisfies DiffSelectionSide + if (node.dataset.code == null) return + return node.hasAttribute("data-deletions") ? "deletions" : "additions" +} + +function diffSelectionSide(node: Node | null) { + const el = findElement(node) + if (!el) return + return findDiffSide(el) +} + +// --------------------------------------------------------------------------- +// Shared JSX shell +// --------------------------------------------------------------------------- + +function ViewerShell(props: { + mode: "text" | "diff" + viewer: ReturnType<typeof useFileViewer> + search: FileSearchControl | undefined + class: string | undefined + classList: ComponentProps<"div">["classList"] | undefined +}) { + return ( + <div + data-component="file" + data-mode={props.mode} + style={styleVariables} + class="relative outline-none" + classList={{ + ...(props.classList || {}), + [props.class ?? ""]: !!props.class, + }} + ref={(el) => (props.viewer.wrapper = el)} + tabIndex={0} + onPointerDown={props.viewer.find.onPointerDown} + onFocus={props.viewer.find.onFocus} + > + <Show when={(props.search?.showBar ?? true) && props.viewer.find.open()}> + <FileSearchBar + pos={props.viewer.find.pos} + query={props.viewer.find.query} + count={props.viewer.find.count} + index={props.viewer.find.index} + setInput={props.viewer.find.setInput} + onInput={props.viewer.find.setQuery} + onKeyDown={props.viewer.find.onInputKeyDown} + onClose={props.viewer.find.close} + onPrev={() => props.viewer.find.next(-1)} + onNext={() => props.viewer.find.next(1)} + /> + </Show> + <div ref={(el) => (props.viewer.container = el)} /> + <div ref={(el) => (props.viewer.overlay = el)} class="pointer-events-none absolute inset-0 z-0" /> + </div> + ) +} + +// --------------------------------------------------------------------------- +// TextViewer +// --------------------------------------------------------------------------- + +function TextViewer<T>(props: TextFileProps<T>) { + let instance: PierreFile<T> | VirtualizedFile<T> | undefined + let viewer!: Viewer + + const [local, others] = splitProps(props, textKeys) + + const text = () => { + const value = local.file.contents as unknown + if (typeof value === "string") return value + if (Array.isArray(value)) return value.join("\n") + if (value == null) return "" + return String(value) + } + + const lineCount = () => { + const value = text() + const total = value.split("\n").length - (value.endsWith("\n") ? 1 : 0) + return Math.max(1, total) + } + + const bytes = createMemo(() => { + const value = local.file.contents as unknown + if (typeof value === "string") return value.length + if (Array.isArray(value)) { + return value.reduce( + (sum, part) => sum + (typeof part === "string" ? part.length + 1 : String(part).length + 1), + 0, + ) + } + if (value == null) return 0 + return String(value).length + }) + + const virtual = createMemo(() => bytes() > VIRTUALIZE_BYTES) + + const virtuals = createLocalVirtualStrategy(() => viewer.wrapper, virtual) + + const lineFromMouseEvent = (event: MouseEvent): MouseHit => mouseHit(event, parseLine) + + const applySelection = (range: SelectedLineRange | null) => { + const current = instance + if (!current) return false + + if (virtual()) { + current.setSelectedLines(range) + return true + } + + const root = viewer.getRoot() + if (!root) return false + + const total = lineCount() + if (root.querySelectorAll("[data-line]").length < total) return false + + if (!range) { + current.setSelectedLines(null) + return true + } + + const start = Math.min(range.start, range.end) + const end = Math.max(range.start, range.end) + if (start < 1 || end > total) { + current.setSelectedLines(null) + return true + } + + if (!root.querySelector(`[data-line="${start}"]`) || !root.querySelector(`[data-line="${end}"]`)) { + current.setSelectedLines(null) + return true + } + + const normalized = (() => { + if (range.endSide != null) return { start: range.start, end: range.end } + if (range.side !== "deletions") return range + if (root.querySelector("[data-deletions]") != null) return range + return { start: range.start, end: range.end } + })() + + current.setSelectedLines(normalized) + return true + } + + const setSelectedLines = (range: SelectedLineRange | null) => { + viewer.lastSelection = range + applySelection(range) + } + + const adapter: ModeAdapter = { + lineFromMouseEvent, + setSelectedLines, + updateSelection: (preserveTextSelection) => { + const root = viewer.getRoot() + if (!root) return + + const selected = readShadowLineSelection({ + root, + lineForNode: findFileLineNumber, + sideForNode: findCodeSelectionSide, + preserveTextSelection, + }) + if (!selected) return + + setSelectedLines(selected.range) + if (!preserveTextSelection || !selected.text) return + restoreShadowTextSelection(root, selected.text) + }, + buildDragSelection: () => { + if (viewer.dragStart === undefined || viewer.dragEnd === undefined) return + return { start: Math.min(viewer.dragStart, viewer.dragEnd), end: Math.max(viewer.dragStart, viewer.dragEnd) } + }, + buildClickSelection: () => { + if (viewer.dragStart === undefined) return + return { start: viewer.dragStart, end: viewer.dragStart } + }, + onDragStart: () => {}, + onDragMove: () => {}, + onDragReset: () => {}, + markCommented: markCommentedFileLines, + } + + viewer = useModeViewer( + { + enableLineSelection: () => props.enableLineSelection === true, + search: () => local.search, + selectedLines: () => local.selectedLines, + commentedLines: () => local.commentedLines, + onLineSelectionEnd: (range) => local.onLineSelectionEnd?.(range), + }, + adapter, + ) + + const lineCallbacks = createLineCallbacks({ + viewer, + onLineSelected: (range) => local.onLineSelected?.(range), + onLineSelectionEnd: (range) => local.onLineSelectionEnd?.(range), + onLineNumberSelectionEnd: (range) => local.onLineNumberSelectionEnd?.(range), + }) + + const options = createMemo(() => ({ + ...createDefaultOptions<T>("unified"), + ...others, + ...lineCallbacks, + })) + + const notify = () => { + notifyRendered({ + viewer, + isReady: (root) => { + if (virtual()) return root.querySelector("[data-line]") != null + return root.querySelectorAll("[data-line]").length >= lineCount() + }, + onReady: () => { + applySelection(viewer.lastSelection) + viewer.find.refresh({ reset: true }) + local.onRendered?.() + }, + }) + } + + useSearchHandle({ + search: () => local.search, + find: viewer.find, + }) + + // -- render instance -- + + createEffect(() => { + const opts = options() + const workerPool = getWorkerPool("unified") + const isVirtual = virtual() + + const virtualizer = virtuals.get() + + renderViewer({ + viewer, + current: instance, + create: () => + isVirtual && virtualizer + ? new VirtualizedFile<T>(opts, virtualizer, codeMetrics, workerPool) + : new PierreFile<T>(opts, workerPool), + assign: (value) => { + instance = value + }, + draw: (value) => { + const contents = text() + value.render({ + file: typeof local.file.contents === "string" ? local.file : { ...local.file, contents }, + lineAnnotations: [], + containerWrapper: viewer.container, + }) + }, + onReady: notify, + }) + }) + + useAnnotationRerender<LineAnnotation<T>>({ + viewer, + current: () => instance, + annotations: () => (local.annotations as LineAnnotation<T>[] | undefined) ?? [], + }) + + // -- cleanup -- + + onCleanup(() => { + instance?.cleanUp() + instance = undefined + virtuals.cleanup() + }) + + return ( + <ViewerShell mode="text" viewer={viewer} search={local.search} class={local.class} classList={local.classList} /> + ) +} + +// --------------------------------------------------------------------------- +// DiffViewer +// --------------------------------------------------------------------------- + +function DiffViewer<T>(props: DiffFileProps<T>) { + let instance: FileDiff<T> | undefined + let dragSide: DiffSelectionSide | undefined + let dragEndSide: DiffSelectionSide | undefined + let viewer!: Viewer + + const [local, others] = splitProps(props, diffKeys) + + const mobile = createMediaQuery("(max-width: 640px)") + + const lineFromMouseEvent = (event: MouseEvent): MouseHit => mouseHit(event, findDiffLineNumber, diffMouseSide) + + const setSelectedLines = (range: SelectedLineRange | null, preserve?: { root: ShadowRoot; text: Range }) => { + const active = instance + if (!active) return + + const fixed = fixDiffSelection(viewer.getRoot(), range) + if (fixed === undefined) { + viewer.lastSelection = range + return + } + + viewer.lastSelection = fixed + active.setSelectedLines(fixed) + restoreShadowTextSelection(preserve?.root, preserve?.text) + } + + const adapter: ModeAdapter = { + lineFromMouseEvent, + setSelectedLines, + updateSelection: (preserveTextSelection) => { + const root = viewer.getRoot() + if (!root) return + + const selected = readShadowLineSelection({ + root, + lineForNode: findDiffLineNumber, + sideForNode: diffSelectionSide, + preserveTextSelection, + }) + if (!selected) return + + if (selected.text) { + setSelectedLines(selected.range, { root, text: selected.text }) + return + } + + setSelectedLines(selected.range) + }, + buildDragSelection: () => { + if (viewer.dragStart === undefined || viewer.dragEnd === undefined) return + const selected: SelectedLineRange = { start: viewer.dragStart, end: viewer.dragEnd } + if (dragSide) selected.side = dragSide + if (dragEndSide && dragSide && dragEndSide !== dragSide) selected.endSide = dragEndSide + return selected + }, + buildClickSelection: () => { + if (viewer.dragStart === undefined) return + const selected: SelectedLineRange = { start: viewer.dragStart, end: viewer.dragStart } + if (dragSide) selected.side = dragSide + return selected + }, + onDragStart: (hit) => { + dragSide = hit.side + dragEndSide = hit.side + }, + onDragMove: (hit) => { + dragEndSide = hit.side + }, + onDragReset: () => { + dragSide = undefined + dragEndSide = undefined + }, + markCommented: markCommentedDiffLines, + } + + viewer = useModeViewer( + { + enableLineSelection: () => props.enableLineSelection === true, + search: () => local.search, + selectedLines: () => local.selectedLines, + commentedLines: () => local.commentedLines, + onLineSelectionEnd: (range) => local.onLineSelectionEnd?.(range), + }, + adapter, + ) + + const virtuals = createSharedVirtualStrategy( + () => viewer.container, + () => local.search?.disableVirtualization !== true, + ) + + const large = createMemo(() => { + const before = typeof local.before?.contents === "string" ? local.before.contents : "" + const after = typeof local.after?.contents === "string" ? local.after.contents : "" + return Math.max(before.length, after.length) > 500_000 + }) + + const largeOptions = { + lineDiffType: "none", + maxLineDiffLength: 0, + tokenizeMaxLineLength: 1, + } satisfies Pick<FileDiffOptions<T>, "lineDiffType" | "maxLineDiffLength" | "tokenizeMaxLineLength"> + + const lineCallbacks = createLineCallbacks({ + viewer, + normalize: (range) => fixDiffSelection(viewer.getRoot(), range), + onLineSelected: (range) => local.onLineSelected?.(range), + onLineSelectionEnd: (range) => local.onLineSelectionEnd?.(range), + onLineNumberSelectionEnd: (range) => local.onLineNumberSelectionEnd?.(range), + }) + + const options = createMemo<FileDiffOptions<T>>(() => { + const base = { + ...createDefaultOptions(props.diffStyle), + ...others, + ...lineCallbacks, + } + + const perf = large() ? { ...base, ...largeOptions } : base + if (!mobile()) return perf + return { ...perf, disableLineNumbers: true } + }) + + const notify = () => { + notifyRendered({ + viewer, + isReady: (root) => root.querySelector("[data-line]") != null, + settleFrames: 1, + onReady: () => { + setSelectedLines(viewer.lastSelection) + viewer.find.refresh({ reset: true }) + local.onRendered?.() + }, + }) + } + + useSearchHandle({ + search: () => local.search, + find: viewer.find, + expand: (hit) => { + const active = instance as + | ((FileDiff<T> | VirtualizedFileDiff<T>) & { + fileDiff?: FileDiffMetadata + }) + | undefined + if (!active?.fileDiff) return false + + const next = expansionForHit(active.fileDiff, hit) + if (!next) return false + + active.expandHunk(next.index, next.direction) + return true + }, + }) + + // -- render instance -- + + createEffect(() => { + const opts = options() + const workerPool = large() ? getWorkerPool("unified") : getWorkerPool(props.diffStyle) + const virtualizer = virtuals.get() + const beforeContents = typeof local.before?.contents === "string" ? local.before.contents : "" + const afterContents = typeof local.after?.contents === "string" ? local.after.contents : "" + + const cacheKey = (contents: string) => { + if (!large()) return sampledChecksum(contents, contents.length) + return sampledChecksum(contents) + } + + renderViewer({ + viewer, + current: instance, + create: () => + virtualizer + ? new VirtualizedFileDiff<T>(opts, virtualizer, virtualMetrics, workerPool) + : new FileDiff<T>(opts, workerPool), + assign: (value) => { + instance = value + }, + draw: (value) => { + value.render({ + oldFile: { ...local.before, contents: beforeContents, cacheKey: cacheKey(beforeContents) }, + newFile: { ...local.after, contents: afterContents, cacheKey: cacheKey(afterContents) }, + lineAnnotations: [], + containerWrapper: viewer.container, + }) + }, + onReady: notify, + }) + }) + + useAnnotationRerender<DiffLineAnnotation<T>>({ + viewer, + current: () => instance, + annotations: () => (local.annotations as DiffLineAnnotation<T>[] | undefined) ?? [], + }) + + // -- cleanup -- + + onCleanup(() => { + instance?.cleanUp() + instance = undefined + virtuals.cleanup() + dragSide = undefined + dragEndSide = undefined + }) + + return ( + <ViewerShell mode="diff" viewer={viewer} search={local.search} class={local.class} classList={local.classList} /> + ) +} + +// --------------------------------------------------------------------------- +// Public API +// --------------------------------------------------------------------------- + +export function File<T>(props: FileProps<T>) { + if (props.mode === "text") { + return <FileMedia media={props.media} fallback={() => TextViewer(props)} /> + } + + return <FileMedia media={props.media} fallback={() => DiffViewer(props)} /> +} diff --git a/packages/ui/src/components/font.stories.tsx b/packages/ui/src/components/font.stories.tsx new file mode 100644 index 0000000000..153a2c8dc9 --- /dev/null +++ b/packages/ui/src/components/font.stories.tsx @@ -0,0 +1,48 @@ +// @ts-nocheck +import * as mod from "./font" + +const docs = `### Overview +Loads OpenCode typography assets and mono nerd fonts. + +Render once at the app root or Storybook preview. + +### API +- No props. + +### Variants and states +- Fonts include sans and multiple mono families. + +### Behavior +- Injects @font-face rules and preload links into the document head. + +### Accessibility +- Not applicable. + +### Theming/tokens +- Provides font families used by theme tokens. + +` + +export default { + title: "UI/Font", + id: "components-font", + component: mod.Font, + tags: ["autodocs"], + parameters: { + docs: { + description: { + component: docs, + }, + }, + }, +} + +export const Basic = { + render: () => ( + <div style={{ display: "grid", gap: "8px" }}> + <mod.Font /> + <div style={{ "font-family": "var(--font-family-sans)" }}>OpenCode Sans Sample</div> + <div style={{ "font-family": "var(--font-family-mono)" }}>OpenCode Mono Sample</div> + </div> + ), +} diff --git a/packages/ui/src/components/hover-card.stories.tsx b/packages/ui/src/components/hover-card.stories.tsx new file mode 100644 index 0000000000..3f5cf10281 --- /dev/null +++ b/packages/ui/src/components/hover-card.stories.tsx @@ -0,0 +1,70 @@ +// @ts-nocheck +import { createSignal } from "solid-js" +import * as mod from "./hover-card" + +const docs = `### Overview +Hover-triggered card for lightweight previews and metadata. + +Use for short summaries; avoid dense interactive controls. + +### API +- Required: \`trigger\` element. +- Children render inside the hover card body. + +### Variants and states +- None; content and trigger are fully composable. + +### Behavior +- Opens on hover/focus over the trigger. + +### Accessibility +- TODO: confirm focus and hover intent behavior from Kobalte. + +### Theming/tokens +- Uses \`data-component="hover-card-content"\` and slots for styling. + +` + +export default { + title: "UI/HoverCard", + id: "components-hover-card", + component: mod.HoverCard, + tags: ["autodocs"], + parameters: { + docs: { + description: { + component: docs, + }, + }, + }, +} + +export const Basic = { + render: () => ( + <mod.HoverCard trigger={<span style={{ "text-decoration": "underline", cursor: "default" }}>Hover me</span>}> + <div style={{ display: "grid", gap: "6px" }}> + <div style={{ "font-weight": 600 }}>Preview</div> + <div style={{ color: "var(--text-weak)", "font-size": "12px" }}>Short supporting text.</div> + </div> + </mod.HoverCard> + ), +} + +export const InlineMount = { + render: () => { + const [mount, setMount] = createSignal<HTMLDivElement | undefined>(undefined) + return ( + <div ref={setMount} style={{ padding: "16px", border: "1px dashed var(--border-weak)" }}> + <mod.HoverCard + mount={mount()} + trigger={<span style={{ "text-decoration": "underline", cursor: "default" }}>Hover me</span>} + > + <div style={{ display: "grid", gap: "6px" }}> + <div style={{ "font-weight": 600 }}>Mounted inside</div> + <div style={{ color: "var(--text-weak)", "font-size": "12px" }}>Uses custom mount node.</div> + </div> + </mod.HoverCard> + </div> + ) + }, +} diff --git a/packages/ui/src/components/icon-button.stories.tsx b/packages/ui/src/components/icon-button.stories.tsx new file mode 100644 index 0000000000..9782759f82 --- /dev/null +++ b/packages/ui/src/components/icon-button.stories.tsx @@ -0,0 +1,74 @@ +// @ts-nocheck +import * as mod from "./icon-button" +import { create } from "../storybook/scaffold" + +const docs = `### Overview +Compact icon-only button with size and variant control. + +Use \`Button\` for text labels and primary actions. + +### API +- Required: \`icon\` icon name. +- Optional: \`size\`, \`iconSize\`, \`variant\`. +- Inherits Kobalte Button props and native button attributes. + +### Variants and states +- Variants: primary, secondary, ghost. +- Sizes: small, normal, large. + +### Behavior +- Icon size adapts to button size unless overridden. + +### Accessibility +- Provide \`aria-label\` when there is no visible text. + +### Theming/tokens +- Uses \`data-component="icon-button"\` and size/variant data attributes. + +` + +const story = create({ title: "UI/IconButton", mod, args: { icon: "check", "aria-label": "Icon" } }) +export default { + title: "UI/IconButton", + id: "components-icon-button", + component: story.meta.component, + tags: ["autodocs"], + parameters: { + docs: { + description: { + component: docs, + }, + }, + }, +} + +export const Basic = story.Basic + +export const Sizes = { + render: () => ( + <div style={{ display: "flex", gap: "12px", "align-items": "center" }}> + <mod.IconButton icon="check" size="small" aria-label="Small" /> + <mod.IconButton icon="check" size="normal" aria-label="Normal" /> + <mod.IconButton icon="check" size="large" aria-label="Large" /> + </div> + ), +} + +export const Variants = { + render: () => ( + <div style={{ display: "flex", gap: "12px", "align-items": "center" }}> + <mod.IconButton icon="check" variant="primary" aria-label="Primary" /> + <mod.IconButton icon="check" variant="secondary" aria-label="Secondary" /> + <mod.IconButton icon="check" variant="ghost" aria-label="Ghost" /> + </div> + ), +} + +export const IconSizeOverride = { + render: () => ( + <div style={{ display: "flex", gap: "12px", "align-items": "center" }}> + <mod.IconButton icon="check" size="small" iconSize="large" aria-label="Small with large icon" /> + <mod.IconButton icon="check" size="large" iconSize="small" aria-label="Large with small icon" /> + </div> + ), +} diff --git a/packages/ui/src/components/icon.stories.tsx b/packages/ui/src/components/icon.stories.tsx new file mode 100644 index 0000000000..1986d74772 --- /dev/null +++ b/packages/ui/src/components/icon.stories.tsx @@ -0,0 +1,170 @@ +// @ts-nocheck +import * as mod from "./icon" +import { create } from "../storybook/scaffold" + +const docs = `### Overview +Inline icon renderer using the built-in OpenCode icon set. + +Use with \`Button\`, \`IconButton\`, and menu items. + +### API +- Required: \`name\` (icon key). +- Optional: \`size\` (small | normal | medium | large). +- Accepts standard SVG props. + +### Variants and states +- Size variants only. + +### Behavior +- Uses an internal SVG path map. + +### Accessibility +- Icons are aria-hidden by default; wrap with accessible text when needed. + +### Theming/tokens +- Uses \`data-component="icon"\` with size data attributes. + +` + +const names = [ + "align-right", + "arrow-up", + "arrow-left", + "arrow-right", + "archive", + "bubble-5", + "prompt", + "brain", + "bullet-list", + "check-small", + "chevron-down", + "chevron-left", + "chevron-right", + "chevron-grabber-vertical", + "chevron-double-right", + "circle-x", + "close", + "close-small", + "checklist", + "console", + "expand", + "collapse", + "code", + "code-lines", + "circle-ban-sign", + "edit-small-2", + "eye", + "enter", + "folder", + "file-tree", + "file-tree-active", + "magnifying-glass", + "plus-small", + "plus", + "new-session", + "pencil-line", + "mcp", + "glasses", + "magnifying-glass-menu", + "window-cursor", + "task", + "stop", + "layout-left", + "layout-left-partial", + "layout-left-full", + "layout-right", + "layout-right-partial", + "layout-right-full", + "square-arrow-top-right", + "open-file", + "speech-bubble", + "comment", + "folder-add-left", + "github", + "discord", + "layout-bottom", + "layout-bottom-partial", + "layout-bottom-full", + "dot-grid", + "circle-check", + "copy", + "check", + "photo", + "share", + "download", + "menu", + "server", + "branch", + "edit", + "help", + "settings-gear", + "dash", + "cloud-upload", + "trash", + "sliders", + "keyboard", + "selector", + "arrow-down-to-line", + "warning", + "link", + "providers", + "models", +] + +const story = create({ title: "UI/Icon", mod, args: { name: "check" } }) + +export default { + title: "UI/Icon", + id: "components-icon", + component: story.meta.component, + tags: ["autodocs"], + parameters: { + docs: { + description: { + component: docs, + }, + }, + }, + argTypes: { + name: { + control: "select", + options: names, + }, + size: { + control: "select", + options: ["small", "normal", "medium", "large"], + }, + }, +} + +export const Basic = story.Basic + +export const Sizes = { + render: () => ( + <div style={{ display: "flex", gap: "12px", "align-items": "center" }}> + <mod.Icon name="check" size="small" /> + <mod.Icon name="check" size="normal" /> + <mod.Icon name="check" size="medium" /> + <mod.Icon name="check" size="large" /> + </div> + ), +} + +export const Gallery = { + render: () => ( + <div + style={{ + display: "grid", + gap: "12px", + "grid-template-columns": "repeat(auto-fill, minmax(88px, 1fr))", + }} + > + {names.map((name) => ( + <div style={{ display: "grid", gap: "6px", "justify-items": "center" }}> + <mod.Icon name={name} /> + <div style={{ "font-size": "10px", color: "var(--text-weak)", "text-align": "center" }}>{name}</div> + </div> + ))} + </div> + ), +} diff --git a/packages/ui/src/components/image-preview.stories.tsx b/packages/ui/src/components/image-preview.stories.tsx new file mode 100644 index 0000000000..f0a00c7825 --- /dev/null +++ b/packages/ui/src/components/image-preview.stories.tsx @@ -0,0 +1,59 @@ +// @ts-nocheck +import { onMount } from "solid-js" +import * as mod from "./image-preview" +import { Button } from "./button" +import { useDialog } from "../context/dialog" + +const docs = `### Overview +Image preview content intended to render inside the dialog stack. + +Use for full-size image inspection; keep images optimized. + +### API +- Required: \`src\`. +- Optional: \`alt\` text. + +### Variants and states +- Single layout with close action. + +### Behavior +- Intended to be used via \`useDialog().show\`. + +### Accessibility +- Uses localized aria-label for close button. + +### Theming/tokens +- Uses \`data-component="image-preview"\` and slot attributes. + +` + +export default { + title: "UI/ImagePreview", + id: "components-image-preview", + component: mod.ImagePreview, + tags: ["autodocs"], + parameters: { + docs: { + description: { + component: docs, + }, + }, + }, +} + +export const Basic = { + render: () => { + const dialog = useDialog() + const src = "https://placehold.co/640x360/png" + + const open = () => dialog.show(() => <mod.ImagePreview src={src} alt="Preview" />) + + onMount(open) + + return ( + <Button variant="secondary" onClick={open}> + Open image preview + </Button> + ) + }, +} diff --git a/packages/ui/src/components/inline-input.stories.tsx b/packages/ui/src/components/inline-input.stories.tsx new file mode 100644 index 0000000000..e364c89631 --- /dev/null +++ b/packages/ui/src/components/inline-input.stories.tsx @@ -0,0 +1,50 @@ +// @ts-nocheck +import * as mod from "./inline-input" +import { create } from "../storybook/scaffold" + +const docs = `### Overview +Compact inline input for short values. + +Use inside text or table rows for quick edits. + +### API +- Optional: \`width\` to set a fixed width. +- Accepts standard input props. + +### Variants and states +- No built-in variants; style via class or width. + +### Behavior +- Uses inline width when provided. + +### Accessibility +- Provide a label or aria-label when used standalone. + +### Theming/tokens +- Uses \`data-component="inline-input"\`. + +` + +const story = create({ title: "UI/InlineInput", mod, args: { placeholder: "Type...", value: "Inline" } }) +export default { + title: "UI/InlineInput", + id: "components-inline-input", + component: story.meta.component, + tags: ["autodocs"], + parameters: { + docs: { + description: { + component: docs, + }, + }, + }, +} + +export const Basic = story.Basic + +export const FixedWidth = { + args: { + value: "80px", + width: "80px", + }, +} diff --git a/packages/ui/src/components/keybind.stories.tsx b/packages/ui/src/components/keybind.stories.tsx new file mode 100644 index 0000000000..a458a53a74 --- /dev/null +++ b/packages/ui/src/components/keybind.stories.tsx @@ -0,0 +1,43 @@ +// @ts-nocheck +import * as mod from "./keybind" +import { create } from "../storybook/scaffold" + +const docs = `### Overview +Keyboard shortcut pill for displaying keybindings. + +Pair with menu items or command palettes. + +### API +- Children render the key sequence text. +- Accepts standard span props. + +### Variants and states +- Single visual style. + +### Behavior +- Presentational only. + +### Accessibility +- Ensure text conveys the shortcut (e.g., "Cmd+K"). + +### Theming/tokens +- Uses \`data-component="keybind"\`. + +` + +const story = create({ title: "UI/Keybind", mod, args: { children: "Cmd+K" } }) +export default { + title: "UI/Keybind", + id: "components-keybind", + component: story.meta.component, + tags: ["autodocs"], + parameters: { + docs: { + description: { + component: docs, + }, + }, + }, +} + +export const Basic = story.Basic diff --git a/packages/ui/src/components/line-comment-annotations.tsx b/packages/ui/src/components/line-comment-annotations.tsx new file mode 100644 index 0000000000..6b072d9c5c --- /dev/null +++ b/packages/ui/src/components/line-comment-annotations.tsx @@ -0,0 +1,586 @@ +import { type DiffLineAnnotation, type SelectedLineRange } from "@pierre/diffs" +import { createEffect, createMemo, createSignal, onCleanup, Show, type Accessor, type JSX } from "solid-js" +import { render as renderSolid } from "solid-js/web" +import { createHoverCommentUtility } from "../pierre/comment-hover" +import { cloneSelectedLineRange, formatSelectedLineLabel, lineInSelectedRange } from "../pierre/selection-bridge" +import { LineComment, LineCommentEditor } from "./line-comment" + +export type LineCommentAnnotationMeta<T> = + | { kind: "comment"; key: string; comment: T } + | { kind: "draft"; key: string; range: SelectedLineRange } + +export type LineCommentAnnotation<T> = { + lineNumber: number + side?: "additions" | "deletions" + metadata: LineCommentAnnotationMeta<T> +} + +type LineCommentAnnotationsProps<T> = { + comments: Accessor<T[]> + getCommentId: (comment: T) => string + getCommentSelection: (comment: T) => SelectedLineRange + draftRange: Accessor<SelectedLineRange | null> + draftKey: Accessor<string> +} + +type LineCommentAnnotationsWithSideProps<T> = LineCommentAnnotationsProps<T> & { + getSide: (range: SelectedLineRange) => "additions" | "deletions" +} + +type HoverCommentLine = { + lineNumber: number + side?: "additions" | "deletions" +} + +type LineCommentStateProps<T> = { + opened: Accessor<T | null> + setOpened: (id: T | null) => void + selected: Accessor<SelectedLineRange | null> + setSelected: (range: SelectedLineRange | null) => void + commenting: Accessor<SelectedLineRange | null> + setCommenting: (range: SelectedLineRange | null) => void + syncSelected?: (range: SelectedLineRange | null) => void + hoverSelected?: (range: SelectedLineRange) => void +} + +type LineCommentShape = { + id: string + selection: SelectedLineRange + comment: string +} + +type LineCommentControllerProps<T extends LineCommentShape> = { + comments: Accessor<T[]> + draftKey: Accessor<string> + label: string + state: LineCommentStateProps<string> + onSubmit: (input: { comment: string; selection: SelectedLineRange }) => void + onUpdate?: (input: { id: string; comment: string; selection: SelectedLineRange }) => void + onDelete?: (comment: T) => void + renderCommentActions?: (comment: T, controls: { edit: VoidFunction; remove: VoidFunction }) => JSX.Element + editSubmitLabel?: string + onDraftPopoverFocusOut?: JSX.EventHandlerUnion<HTMLDivElement, FocusEvent> + getHoverSelectedRange?: Accessor<SelectedLineRange | null> + cancelDraftOnCommentToggle?: boolean + clearSelectionOnSelectionEndNull?: boolean +} + +type LineCommentControllerWithSideProps<T extends LineCommentShape> = LineCommentControllerProps<T> & { + getSide: (range: SelectedLineRange) => "additions" | "deletions" +} + +type CommentProps = { + id?: string + open: boolean + comment: JSX.Element + selection: JSX.Element + actions?: JSX.Element + editor?: DraftProps + onClick?: JSX.EventHandlerUnion<HTMLButtonElement, MouseEvent> + onMouseEnter?: JSX.EventHandlerUnion<HTMLButtonElement, MouseEvent> +} + +type DraftProps = { + value: string + selection: JSX.Element + onInput: (value: string) => void + onCancel: VoidFunction + onSubmit: (value: string) => void + onPopoverFocusOut?: JSX.EventHandlerUnion<HTMLDivElement, FocusEvent> + cancelLabel?: string + submitLabel?: string +} + +export function createLineCommentAnnotationRenderer<T>(props: { + renderComment: (comment: T) => CommentProps + renderDraft: (range: SelectedLineRange) => DraftProps +}) { + const nodes = new Map< + string, + { + host: HTMLDivElement + dispose: VoidFunction + setMeta: (meta: LineCommentAnnotationMeta<T>) => void + } + >() + + const mount = (meta: LineCommentAnnotationMeta<T>) => { + if (typeof document === "undefined") return + + const host = document.createElement("div") + host.setAttribute("data-prevent-autofocus", "") + const [current, setCurrent] = createSignal(meta) + + const dispose = renderSolid(() => { + const active = current() + if (active.kind === "comment") { + const view = createMemo(() => { + const next = current() + if (next.kind !== "comment") return props.renderComment(active.comment) + return props.renderComment(next.comment) + }) + return ( + <Show + when={view().editor} + fallback={ + <LineComment + inline + id={view().id} + open={view().open} + comment={view().comment} + selection={view().selection} + actions={view().actions} + onClick={view().onClick} + onMouseEnter={view().onMouseEnter} + /> + } + > + <LineCommentEditor + inline + id={view().id} + value={view().editor!.value} + selection={view().editor!.selection} + onInput={view().editor!.onInput} + onCancel={view().editor!.onCancel} + onSubmit={view().editor!.onSubmit} + onPopoverFocusOut={view().editor!.onPopoverFocusOut} + cancelLabel={view().editor!.cancelLabel} + submitLabel={view().editor!.submitLabel} + /> + </Show> + ) + } + + const view = createMemo(() => { + const next = current() + if (next.kind !== "draft") return props.renderDraft(active.range) + return props.renderDraft(next.range) + }) + return ( + <LineCommentEditor + inline + value={view().value} + selection={view().selection} + onInput={view().onInput} + onCancel={view().onCancel} + onSubmit={view().onSubmit} + onPopoverFocusOut={view().onPopoverFocusOut} + /> + ) + }, host) + + const node = { host, dispose, setMeta: setCurrent } + nodes.set(meta.key, node) + return node + } + + const render = <A extends { metadata: LineCommentAnnotationMeta<T> }>(annotation: A) => { + const meta = annotation.metadata + const node = nodes.get(meta.key) ?? mount(meta) + if (!node) return + node.setMeta(meta) + return node.host + } + + const reconcile = <A extends { metadata: LineCommentAnnotationMeta<T> }>(annotations: A[]) => { + const next = new Set(annotations.map((annotation) => annotation.metadata.key)) + for (const [key, node] of nodes) { + if (next.has(key)) continue + node.dispose() + nodes.delete(key) + } + } + + const cleanup = () => { + for (const [, node] of nodes) node.dispose() + nodes.clear() + } + + return { render, reconcile, cleanup } +} + +export function createLineCommentState<T>(props: LineCommentStateProps<T>) { + const [draft, setDraft] = createSignal("") + const [editing, setEditing] = createSignal<T | null>(null) + + const toRange = (range: SelectedLineRange | null) => (range ? cloneSelectedLineRange(range) : null) + const setSelected = (range: SelectedLineRange | null) => { + const next = toRange(range) + props.setSelected(next) + props.syncSelected?.(toRange(next)) + return next + } + + const setCommenting = (range: SelectedLineRange | null) => { + const next = toRange(range) + props.setCommenting(next) + return next + } + + const closeComment = () => { + props.setOpened(null) + } + + const cancelDraft = () => { + setDraft("") + setEditing(null) + setCommenting(null) + } + + const reset = () => { + setDraft("") + setEditing(null) + props.setOpened(null) + props.setSelected(null) + props.setCommenting(null) + } + + const openComment = (id: T, range: SelectedLineRange, options?: { cancelDraft?: boolean }) => { + if (options?.cancelDraft) cancelDraft() + props.setOpened(id) + setSelected(range) + } + + const toggleComment = (id: T, range: SelectedLineRange, options?: { cancelDraft?: boolean }) => { + if (options?.cancelDraft) cancelDraft() + const next = props.opened() === id ? null : id + props.setOpened(next) + setSelected(range) + } + + const openDraft = (range: SelectedLineRange) => { + const next = toRange(range) + setDraft("") + setEditing(null) + closeComment() + setSelected(next) + setCommenting(next) + } + + const openEditor = (id: T, range: SelectedLineRange, value: string) => { + closeComment() + setSelected(range) + props.setCommenting(null) + setEditing(() => id) + setDraft(value) + } + + const hoverComment = (range: SelectedLineRange) => { + const next = toRange(range) + if (!next) return + if (props.hoverSelected) { + props.hoverSelected(next) + return + } + + setSelected(next) + } + + const finishSelection = (range: SelectedLineRange) => { + closeComment() + setSelected(range) + cancelDraft() + } + + createEffect(() => { + props.commenting() + setDraft("") + }) + + return { + draft, + setDraft, + editing, + opened: props.opened, + selected: props.selected, + commenting: props.commenting, + isOpen: (id: T) => props.opened() === id, + isEditing: (id: T) => editing() === id, + closeComment, + openComment, + toggleComment, + openDraft, + openEditor, + hoverComment, + cancelDraft, + finishSelection, + select: setSelected, + reset, + } +} + +export function createLineCommentController<T extends LineCommentShape>( + props: LineCommentControllerWithSideProps<T>, +): { + note: ReturnType<typeof createLineCommentState<string>> + annotations: Accessor<DiffLineAnnotation<LineCommentAnnotationMeta<T>>[]> + renderAnnotation: ReturnType<typeof createManagedLineCommentAnnotationRenderer<T>>["renderAnnotation"] + renderHoverUtility: ReturnType<typeof createLineCommentHoverRenderer> + onLineSelected: (range: SelectedLineRange | null) => void + onLineSelectionEnd: (range: SelectedLineRange | null) => void + onLineNumberSelectionEnd: (range: SelectedLineRange | null) => void +} +export function createLineCommentController<T extends LineCommentShape>( + props: LineCommentControllerProps<T>, +): { + note: ReturnType<typeof createLineCommentState<string>> + annotations: Accessor<LineCommentAnnotation<T>[]> + renderAnnotation: ReturnType<typeof createManagedLineCommentAnnotationRenderer<T>>["renderAnnotation"] + renderHoverUtility: ReturnType<typeof createLineCommentHoverRenderer> + onLineSelected: (range: SelectedLineRange | null) => void + onLineSelectionEnd: (range: SelectedLineRange | null) => void + onLineNumberSelectionEnd: (range: SelectedLineRange | null) => void +} +export function createLineCommentController<T extends LineCommentShape>( + props: LineCommentControllerProps<T> | LineCommentControllerWithSideProps<T>, +) { + const note = createLineCommentState<string>(props.state) + + const annotations = + "getSide" in props + ? createLineCommentAnnotations({ + comments: props.comments, + getCommentId: (comment) => comment.id, + getCommentSelection: (comment) => comment.selection, + draftRange: note.commenting, + draftKey: props.draftKey, + getSide: props.getSide, + }) + : createLineCommentAnnotations({ + comments: props.comments, + getCommentId: (comment) => comment.id, + getCommentSelection: (comment) => comment.selection, + draftRange: note.commenting, + draftKey: props.draftKey, + }) + + const { renderAnnotation } = createManagedLineCommentAnnotationRenderer<T>({ + annotations, + renderComment: (comment) => { + const edit = () => note.openEditor(comment.id, comment.selection, comment.comment) + const remove = () => { + note.reset() + props.onDelete?.(comment) + } + + return { + id: comment.id, + get open() { + return note.isOpen(comment.id) || note.isEditing(comment.id) + }, + comment: comment.comment, + selection: formatSelectedLineLabel(comment.selection), + get actions() { + return props.renderCommentActions?.(comment, { edit, remove }) + }, + get editor() { + return note.isEditing(comment.id) + ? { + get value() { + return note.draft() + }, + selection: formatSelectedLineLabel(comment.selection), + onInput: note.setDraft, + onCancel: note.cancelDraft, + onSubmit: (value: string) => { + props.onUpdate?.({ + id: comment.id, + comment: value, + selection: cloneSelectedLineRange(comment.selection), + }) + note.cancelDraft() + }, + submitLabel: props.editSubmitLabel, + } + : undefined + }, + onMouseEnter: () => note.hoverComment(comment.selection), + onClick: () => { + if (note.isEditing(comment.id)) return + note.toggleComment(comment.id, comment.selection, { cancelDraft: props.cancelDraftOnCommentToggle }) + }, + } + }, + renderDraft: (range) => ({ + get value() { + return note.draft() + }, + selection: formatSelectedLineLabel(range), + onInput: note.setDraft, + onCancel: note.cancelDraft, + onSubmit: (comment) => { + props.onSubmit({ comment, selection: cloneSelectedLineRange(range) }) + note.cancelDraft() + }, + onPopoverFocusOut: props.onDraftPopoverFocusOut, + }), + }) + + const renderHoverUtility = createLineCommentHoverRenderer({ + label: props.label, + getSelectedRange: () => { + if (note.opened()) return null + return props.getHoverSelectedRange?.() ?? note.selected() + }, + onOpenDraft: note.openDraft, + }) + + const onLineSelected = (range: SelectedLineRange | null) => { + if (!range) { + note.select(null) + note.cancelDraft() + return + } + + note.select(range) + } + + const onLineSelectionEnd = (range: SelectedLineRange | null) => { + if (!range) { + if (props.clearSelectionOnSelectionEndNull) note.select(null) + note.cancelDraft() + return + } + + note.finishSelection(range) + } + + const onLineNumberSelectionEnd = (range: SelectedLineRange | null) => { + if (!range) return + note.openDraft(range) + } + + return { + note, + annotations, + renderAnnotation, + renderHoverUtility, + onLineSelected, + onLineSelectionEnd, + onLineNumberSelectionEnd, + } +} + +export function createLineCommentAnnotations<T>( + props: LineCommentAnnotationsWithSideProps<T>, +): Accessor<DiffLineAnnotation<LineCommentAnnotationMeta<T>>[]> +export function createLineCommentAnnotations<T>( + props: LineCommentAnnotationsProps<T>, +): Accessor<LineCommentAnnotation<T>[]> +export function createLineCommentAnnotations<T>( + props: LineCommentAnnotationsProps<T> | LineCommentAnnotationsWithSideProps<T>, +) { + const line = (range: SelectedLineRange) => Math.max(range.start, range.end) + + if ("getSide" in props) { + return createMemo<DiffLineAnnotation<LineCommentAnnotationMeta<T>>[]>(() => { + const list = props.comments().map((comment) => { + const range = props.getCommentSelection(comment) + return { + side: props.getSide(range), + lineNumber: line(range), + metadata: { + kind: "comment", + key: `comment:${props.getCommentId(comment)}`, + comment, + } satisfies LineCommentAnnotationMeta<T>, + } + }) + + const range = props.draftRange() + if (!range) return list + + return [ + ...list, + { + side: props.getSide(range), + lineNumber: line(range), + metadata: { + kind: "draft", + key: `draft:${props.draftKey()}`, + range, + } satisfies LineCommentAnnotationMeta<T>, + }, + ] + }) + } + + return createMemo<LineCommentAnnotation<T>[]>(() => { + const list = props.comments().map((comment) => { + const range = props.getCommentSelection(comment) + const entry: LineCommentAnnotation<T> = { + lineNumber: line(range), + metadata: { + kind: "comment", + key: `comment:${props.getCommentId(comment)}`, + comment, + }, + } + + return entry + }) + + const range = props.draftRange() + if (!range) return list + + const draft: LineCommentAnnotation<T> = { + lineNumber: line(range), + metadata: { + kind: "draft", + key: `draft:${props.draftKey()}`, + range, + }, + } + + return [...list, draft] + }) +} + +export function createManagedLineCommentAnnotationRenderer<T>(props: { + annotations: Accessor<LineCommentAnnotation<T>[]> + renderComment: (comment: T) => CommentProps + renderDraft: (range: SelectedLineRange) => DraftProps +}) { + const renderer = createLineCommentAnnotationRenderer<T>({ + renderComment: props.renderComment, + renderDraft: props.renderDraft, + }) + + createEffect(() => { + renderer.reconcile(props.annotations()) + }) + + onCleanup(() => { + renderer.cleanup() + }) + + return { + renderAnnotation: renderer.render, + } +} + +export function createLineCommentHoverRenderer(props: { + label: string + getSelectedRange: Accessor<SelectedLineRange | null> + onOpenDraft: (range: SelectedLineRange) => void +}) { + return (getHoveredLine: () => HoverCommentLine | undefined) => + createHoverCommentUtility({ + label: props.label, + getHoveredLine, + onSelect: (hovered) => { + const current = props.getSelectedRange() + if (current && lineInSelectedRange(current, hovered.lineNumber, hovered.side)) { + props.onOpenDraft(cloneSelectedLineRange(current)) + return + } + + const range: SelectedLineRange = { + start: hovered.lineNumber, + end: hovered.lineNumber, + } + if (hovered.side) range.side = hovered.side + props.onOpenDraft(range) + }, + }) +} diff --git a/packages/ui/src/components/line-comment.css b/packages/ui/src/components/line-comment-styles.ts similarity index 52% rename from packages/ui/src/components/line-comment.css rename to packages/ui/src/components/line-comment-styles.ts index 9dc8eb74f3..d5be675541 100644 --- a/packages/ui/src/components/line-comment.css +++ b/packages/ui/src/components/line-comment-styles.ts @@ -1,9 +1,23 @@ +export const lineCommentStyles = ` +[data-annotation-slot] { + padding: 12px; + box-sizing: border-box; +} + [data-component="line-comment"] { position: absolute; right: 24px; z-index: var(--line-comment-z, 30); } +[data-component="line-comment"][data-inline] { + position: relative; + right: auto; + display: flex; + width: 100%; + align-items: flex-start; +} + [data-component="line-comment"][data-open] { z-index: var(--line-comment-open-z, 100); } @@ -21,10 +35,20 @@ border: none; } +[data-component="line-comment"][data-variant="add"] [data-slot="line-comment-button"] { + background: var(--syntax-diff-add); +} + [data-component="line-comment"] [data-component="icon"] { color: var(--white); } +[data-component="line-comment"] [data-slot="line-comment-icon"] { + width: 12px; + height: 12px; + color: var(--white); +} + [data-component="line-comment"] [data-slot="line-comment-button"]:focus { outline: none; } @@ -39,27 +63,56 @@ right: -8px; z-index: var(--line-comment-popover-z, 40); min-width: 200px; - max-width: min(320px, calc(100vw - 48px)); + max-width: none; border-radius: 8px; background: var(--surface-raised-stronger-non-alpha); - box-shadow: var(--shadow-lg-border-base); + box-shadow: var(--shadow-xxs-border); padding: 12px; } +[data-component="line-comment"][data-inline] [data-slot="line-comment-popover"] { + position: relative; + top: auto; + right: auto; + margin-left: 8px; + flex: 0 1 600px; + width: min(100%, 600px); + max-width: min(100%, 600px); +} + +[data-component="line-comment"][data-inline] [data-slot="line-comment-popover"][data-inline-body] { + margin-left: 0; +} + +[data-component="line-comment"][data-inline][data-variant="default"] [data-slot="line-comment-popover"][data-inline-body] { + cursor: pointer; +} + [data-component="line-comment"][data-variant="editor"] [data-slot="line-comment-popover"] { width: 380px; - max-width: min(380px, calc(100vw - 48px)); + max-width: none; padding: 8px; border-radius: 14px; } +[data-component="line-comment"][data-inline][data-variant="editor"] [data-slot="line-comment-popover"] { + flex-basis: 600px; +} + [data-component="line-comment"] [data-slot="line-comment-content"] { display: flex; flex-direction: column; gap: 6px; } +[data-component="line-comment"] [data-slot="line-comment-head"] { + display: flex; + align-items: flex-start; + gap: 8px; +} + [data-component="line-comment"] [data-slot="line-comment-text"] { + flex: 1; font-family: var(--font-family-sans); font-size: var(--font-size-base); font-weight: var(--font-weight-regular); @@ -69,6 +122,13 @@ white-space: pre-wrap; } +[data-component="line-comment"] [data-slot="line-comment-tools"] { + flex: 0 0 auto; + display: flex; + align-items: center; + justify-content: flex-end; +} + [data-component="line-comment"] [data-slot="line-comment-label"], [data-component="line-comment"] [data-slot="line-comment-editor-label"] { font-family: var(--font-family-sans); @@ -108,8 +168,56 @@ display: flex; align-items: center; gap: 8px; + padding-left: 8px; } [data-component="line-comment"] [data-slot="line-comment-editor-label"] { margin-right: auto; } + +[data-component="line-comment"] [data-slot="line-comment-action"] { + border: 1px solid var(--border-base); + background: var(--surface-base); + color: var(--text-strong); + border-radius: var(--radius-md); + height: 28px; + padding: 0 10px; + font-family: var(--font-family-sans); + font-size: var(--font-size-small); + font-weight: var(--font-weight-medium); +} + +[data-component="line-comment"] [data-slot="line-comment-action"][data-variant="ghost"] { + background: transparent; +} + +[data-component="line-comment"] [data-slot="line-comment-action"][data-variant="primary"] { + background: var(--text-strong); + border-color: var(--text-strong); + color: var(--background-base); +} + +[data-component="line-comment"] [data-slot="line-comment-action"]:disabled { + opacity: 0.5; + pointer-events: none; +} +` + +let installed = false + +export function installLineCommentStyles() { + if (installed) return + if (typeof document === "undefined") return + + const id = "opencode-line-comment-styles" + if (document.getElementById(id)) { + installed = true + return + } + + const style = document.createElement("style") + style.id = id + style.textContent = lineCommentStyles + document.head.appendChild(style) + installed = true +} diff --git a/packages/ui/src/components/line-comment.stories.tsx b/packages/ui/src/components/line-comment.stories.tsx new file mode 100644 index 0000000000..c48674e3c7 --- /dev/null +++ b/packages/ui/src/components/line-comment.stories.tsx @@ -0,0 +1,115 @@ +// @ts-nocheck +import { createSignal } from "solid-js" +import * as mod from "./line-comment" + +const docs = `### Overview +Inline comment anchor and editor for code review or annotation flows. + +Pair with \`Diff\` or \`Code\` to align comments to lines. + +### API +- \`LineCommentAnchor\`: position with \`top\`, control \`open\`, render custom children. +- \`LineComment\`: convenience wrapper for displaying comment + selection label. +- \`LineCommentEditor\`: controlled textarea with submit/cancel handlers. + +### Variants and states +- Default display and editor display variants. + +### Behavior +- Anchor positions relative to a containing element. +- Editor submits on Enter (Shift+Enter for newline). + +### Accessibility +- TODO: confirm ARIA labeling for comment button and editor textarea. + +### Theming/tokens +- Uses \`data-component="line-comment"\` and related slots. + +` + +export default { + title: "UI/LineComment", + id: "components-line-comment", + component: mod.LineComment, + tags: ["autodocs"], + parameters: { + docs: { + description: { + component: docs, + }, + }, + }, +} + +export const Default = { + render: () => ( + <div + style={{ + position: "relative", + height: "160px", + padding: "16px 16px 16px 40px", + border: "1px solid var(--border-weak)", + "border-radius": "8px", + "font-family": "var(--font-family-mono)", + "font-size": "12px", + color: "var(--text-weak)", + }} + > + <div>12 | const total = sum(values)</div> + <div>13 | return total / values.length</div> + <mod.LineComment open top={18} comment="Consider guarding against empty arrays." selection="L12-L13" /> + </div> + ), +} + +export const Editor = { + render: () => { + const [value, setValue] = createSignal("Add context for this change.") + return ( + <div + style={{ + position: "relative", + height: "220px", + padding: "16px 16px 16px 40px", + border: "1px solid var(--border-weak)", + "border-radius": "8px", + "font-family": "var(--font-family-mono)", + "font-size": "12px", + color: "var(--text-weak)", + }} + > + <div>40 | if (values.length === 0) return 0</div> + <mod.LineCommentEditor + top={24} + value={value()} + selection="L40" + onInput={setValue} + onCancel={() => setValue("")} + onSubmit={(next) => setValue(next)} + /> + </div> + ) + }, +} + +export const AnchorOnly = { + render: () => ( + <div + style={{ + position: "relative", + height: "120px", + padding: "16px 16px 16px 40px", + border: "1px solid var(--border-weak)", + "border-radius": "8px", + "font-family": "var(--font-family-mono)", + "font-size": "12px", + color: "var(--text-weak)", + }} + > + <div>20 | const ready = true</div> + <mod.LineCommentAnchor top={18} open={false}> + <div data-slot="line-comment-content">Anchor content</div> + </mod.LineCommentAnchor> + </div> + ), +} diff --git a/packages/ui/src/components/line-comment.tsx b/packages/ui/src/components/line-comment.tsx index 81e4759b01..ff5d1df007 100644 --- a/packages/ui/src/components/line-comment.tsx +++ b/packages/ui/src/components/line-comment.tsx @@ -1,52 +1,121 @@ -import { onMount, Show, splitProps, type JSX } from "solid-js" +import { createEffect, createSignal, onMount, Show, splitProps, type JSX } from "solid-js" import { Button } from "./button" import { Icon } from "./icon" +import { installLineCommentStyles } from "./line-comment-styles" import { useI18n } from "../context/i18n" -export type LineCommentVariant = "default" | "editor" +installLineCommentStyles() + +export type LineCommentVariant = "default" | "editor" | "add" + +function InlineGlyph(props: { icon: "comment" | "plus" }) { + return ( + <svg data-slot="line-comment-icon" viewBox="0 0 20 20" fill="none" aria-hidden="true"> + <Show + when={props.icon === "comment"} + fallback={ + <path + d="M10 5.41699V10.0003M10 10.0003V14.5837M10 10.0003H5.4165M10 10.0003H14.5832" + stroke="currentColor" + stroke-linecap="square" + /> + } + > + <path d="M16.25 3.75H3.75V16.25L6.875 14.4643H16.25V3.75Z" stroke="currentColor" stroke-linecap="square" /> + </Show> + </svg> + ) +} export type LineCommentAnchorProps = { id?: string top?: number + inline?: boolean + hideButton?: boolean open: boolean variant?: LineCommentVariant + icon?: "comment" | "plus" + buttonLabel?: string onClick?: JSX.EventHandlerUnion<HTMLButtonElement, MouseEvent> onMouseEnter?: JSX.EventHandlerUnion<HTMLButtonElement, MouseEvent> onPopoverFocusOut?: JSX.EventHandlerUnion<HTMLDivElement, FocusEvent> class?: string popoverClass?: string - children: JSX.Element + children?: JSX.Element } export const LineCommentAnchor = (props: LineCommentAnchorProps) => { - const hidden = () => props.top === undefined + const hidden = () => !props.inline && props.top === undefined const variant = () => props.variant ?? "default" + const icon = () => props.icon ?? "comment" + const inlineBody = () => props.inline && props.hideButton return ( <div data-component="line-comment" + data-prevent-autofocus="" data-variant={variant()} data-comment-id={props.id} data-open={props.open ? "" : undefined} + data-inline={props.inline ? "" : undefined} classList={{ [props.class ?? ""]: !!props.class, }} - style={{ - top: `${props.top ?? 0}px`, - opacity: hidden() ? 0 : 1, - "pointer-events": hidden() ? "none" : "auto", - }} + style={ + props.inline + ? undefined + : { + top: `${props.top ?? 0}px`, + opacity: hidden() ? 0 : 1, + "pointer-events": hidden() ? "none" : "auto", + } + } > - <button type="button" data-slot="line-comment-button" onClick={props.onClick} onMouseEnter={props.onMouseEnter}> - <Icon name="comment" size="small" /> - </button> - <Show when={props.open}> + <Show + when={inlineBody()} + fallback={ + <> + <button + type="button" + aria-label={props.buttonLabel} + data-slot="line-comment-button" + on:mousedown={(e) => e.stopPropagation()} + on:mouseup={(e) => e.stopPropagation()} + on:click={props.onClick as any} + on:mouseenter={props.onMouseEnter as any} + > + <Show + when={props.inline} + fallback={<Icon name={icon() === "plus" ? "plus-small" : "comment"} size="small" />} + > + <InlineGlyph icon={icon()} /> + </Show> + </button> + <Show when={props.open}> + <div + data-slot="line-comment-popover" + classList={{ + [props.popoverClass ?? ""]: !!props.popoverClass, + }} + on:mousedown={(e) => e.stopPropagation()} + on:focusout={props.onPopoverFocusOut as any} + > + {props.children} + </div> + </Show> + </> + } + > <div data-slot="line-comment-popover" + data-inline-body="" classList={{ [props.popoverClass ?? ""]: !!props.popoverClass, }} - onFocusOut={props.onPopoverFocusOut} + on:mousedown={(e) => e.stopPropagation()} + on:click={props.onClick as any} + on:mouseenter={props.onMouseEnter as any} + on:focusout={props.onPopoverFocusOut as any} > {props.children} </div> @@ -58,16 +127,22 @@ export const LineCommentAnchor = (props: LineCommentAnchorProps) => { export type LineCommentProps = Omit<LineCommentAnchorProps, "children" | "variant"> & { comment: JSX.Element selection: JSX.Element + actions?: JSX.Element } export const LineComment = (props: LineCommentProps) => { const i18n = useI18n() - const [split, rest] = splitProps(props, ["comment", "selection"]) + const [split, rest] = splitProps(props, ["comment", "selection", "actions"]) return ( - <LineCommentAnchor {...rest} variant="default"> + <LineCommentAnchor {...rest} variant="default" hideButton={props.inline}> <div data-slot="line-comment-content"> - <div data-slot="line-comment-text">{split.comment}</div> + <div data-slot="line-comment-head"> + <div data-slot="line-comment-text">{split.comment}</div> + <Show when={split.actions}> + <div data-slot="line-comment-tools">{split.actions}</div> + </Show> + </div> <div data-slot="line-comment-label"> {i18n.t("ui.lineComment.label.prefix")} {split.selection} @@ -78,6 +153,25 @@ export const LineComment = (props: LineCommentProps) => { ) } +export type LineCommentAddProps = Omit<LineCommentAnchorProps, "children" | "variant" | "open" | "icon"> & { + label?: string +} + +export const LineCommentAdd = (props: LineCommentAddProps) => { + const [split, rest] = splitProps(props, ["label"]) + const i18n = useI18n() + + return ( + <LineCommentAnchor + {...rest} + open={false} + variant="add" + icon="plus" + buttonLabel={split.label ?? i18n.t("ui.lineComment.submit")} + /> + ) +} + export type LineCommentEditorProps = Omit<LineCommentAnchorProps, "children" | "open" | "variant" | "onClick"> & { value: string selection: JSX.Element @@ -109,11 +203,16 @@ export const LineCommentEditor = (props: LineCommentEditorProps) => { const refs = { textarea: undefined as HTMLTextAreaElement | undefined, } + const [text, setText] = createSignal(split.value) const focus = () => refs.textarea?.focus() + createEffect(() => { + setText(split.value) + }) + const submit = () => { - const value = split.value.trim() + const value = text().trim() if (!value) return split.onSubmit(value) } @@ -124,7 +223,7 @@ export const LineCommentEditor = (props: LineCommentEditorProps) => { }) return ( - <LineCommentAnchor {...rest} open={true} variant="editor" onClick={() => focus()}> + <LineCommentAnchor {...rest} open={true} variant="editor" hideButton={props.inline} onClick={() => focus()}> <div data-slot="line-comment-editor"> <textarea ref={(el) => { @@ -133,19 +232,25 @@ export const LineCommentEditor = (props: LineCommentEditorProps) => { data-slot="line-comment-textarea" rows={split.rows ?? 3} placeholder={split.placeholder ?? i18n.t("ui.lineComment.placeholder")} - value={split.value} - onInput={(e) => split.onInput(e.currentTarget.value)} - onKeyDown={(e) => { + value={text()} + on:input={(e) => { + const value = (e.currentTarget as HTMLTextAreaElement).value + setText(value) + split.onInput(value) + }} + on:keydown={(e) => { + const event = e as KeyboardEvent + if (event.isComposing || event.keyCode === 229) return + event.stopPropagation() if (e.key === "Escape") { - e.preventDefault() - e.stopPropagation() + event.preventDefault() + e.currentTarget.blur() split.onCancel() return } if (e.key !== "Enter") return if (e.shiftKey) return - e.preventDefault() - e.stopPropagation() + event.preventDefault() submit() }} /> @@ -155,12 +260,37 @@ export const LineCommentEditor = (props: LineCommentEditorProps) => { {split.selection} {i18n.t("ui.lineComment.editorLabel.suffix")} </div> - <Button size="small" variant="ghost" onClick={split.onCancel}> - {split.cancelLabel ?? i18n.t("ui.common.cancel")} - </Button> - <Button size="small" variant="primary" disabled={split.value.trim().length === 0} onClick={submit}> - {split.submitLabel ?? i18n.t("ui.lineComment.submit")} - </Button> + <Show + when={!props.inline} + fallback={ + <> + <button + type="button" + data-slot="line-comment-action" + data-variant="ghost" + on:click={split.onCancel as any} + > + {split.cancelLabel ?? i18n.t("ui.common.cancel")} + </button> + <button + type="button" + data-slot="line-comment-action" + data-variant="primary" + disabled={text().trim().length === 0} + on:click={submit as any} + > + {split.submitLabel ?? i18n.t("ui.lineComment.submit")} + </button> + </> + } + > + <Button size="small" variant="ghost" onClick={split.onCancel}> + {split.cancelLabel ?? i18n.t("ui.common.cancel")} + </Button> + <Button size="small" variant="primary" disabled={text().trim().length === 0} onClick={submit}> + {split.submitLabel ?? i18n.t("ui.lineComment.submit")} + </Button> + </Show> </div> </div> </LineCommentAnchor> diff --git a/packages/ui/src/components/list.stories.tsx b/packages/ui/src/components/list.stories.tsx new file mode 100644 index 0000000000..280f323c0b --- /dev/null +++ b/packages/ui/src/components/list.stories.tsx @@ -0,0 +1,170 @@ +// @ts-nocheck +import * as mod from "./list" +import { create } from "../storybook/scaffold" + +const docs = `### Overview +Filterable list with keyboard navigation and optional search input. + +Use within panels or popovers where keyboard navigation is expected. + +### API +- Required: \`items\` and \`key\`. +- Required: \`children\` render function for items. +- Optional: \`search\`, \`filterKeys\`, \`groupBy\`, \`onSelect\`, \`onKeyEvent\`. + +### Variants and states +- Optional search bar and group headers. + +### Behavior +- Uses fuzzy search when \`search\` is enabled. +- Keyboard navigation via arrow keys; Enter selects. + +### Accessibility +- TODO: confirm ARIA roles for list items and search input. + +### Theming/tokens +- Uses \`data-component="list"\` and data slots for structure. + +` + +const story = create({ + title: "UI/List", + mod, + args: { + items: ["One", "Two", "Three", "Four"], + key: (x: string) => x, + children: (x: string) => x, + search: true, + }, +}) + +export default { + title: "UI/List", + id: "components-list", + component: story.meta.component, + tags: ["autodocs"], + parameters: { + docs: { + description: { + component: docs, + }, + }, + }, +} + +export const Basic = story.Basic + +export const Grouped = { + render: () => { + const items = [ + { id: "a1", title: "Alpha", group: "Group A" }, + { id: "a2", title: "Bravo", group: "Group A" }, + { id: "b1", title: "Delta", group: "Group B" }, + ] + return ( + <mod.List items={items} key={(item) => item.id} groupBy={(item) => item.group} search={true}> + {(item) => item.title} + </mod.List> + ) + }, +} + +export const Empty = { + render: () => ( + <mod.List items={[]} key={(item) => item} search={true}> + {(item) => item} + </mod.List> + ), +} + +export const WithAdd = { + render: () => ( + <mod.List + items={["One", "Two"]} + key={(item) => item} + search={true} + add={{ + render: () => ( + <button type="button" data-slot="list-item"> + Add item + </button> + ), + }} + > + {(item) => item} + </mod.List> + ), +} + +export const Divider = { + render: () => ( + <mod.List items={["One", "Two", "Three"]} key={(item) => item} divider={true}> + {(item) => item} + </mod.List> + ), +} + +export const ActiveIcon = { + render: () => ( + <mod.List items={["Alpha", "Beta", "Gamma"]} key={(item) => item} activeIcon="chevron-right"> + {(item) => item} + </mod.List> + ), +} + +export const NoSearch = { + render: () => ( + <mod.List items={["One", "Two", "Three"]} key={(item) => item} search={false}> + {(item) => item} + </mod.List> + ), +} + +export const SearchOptions = { + render: () => ( + <mod.List + items={["Apple", "Banana", "Cherry"]} + key={(item) => item} + search={{ + placeholder: "Filter...", + hideIcon: true, + action: <button type="button">Action</button>, + }} + > + {(item) => item} + </mod.List> + ), +} + +export const ItemWrapper = { + render: () => ( + <mod.List + items={["One", "Two", "Three"]} + key={(item) => item} + itemWrapper={(item, node) => ( + <div style={{ border: "1px solid var(--border-weak)", "border-radius": "6px", margin: "4px 0" }}>{node}</div> + )} + > + {(item) => item} + </mod.List> + ), +} + +export const GroupHeader = { + render: () => { + const items = [ + { id: "a1", title: "Alpha", group: "Group A" }, + { id: "b1", title: "Beta", group: "Group B" }, + ] + return ( + <mod.List + items={items} + key={(item) => item.id} + groupBy={(item) => item.group} + groupHeader={(group) => <strong>{group.category}</strong>} + > + {(item) => item.title} + </mod.List> + ) + }, +} diff --git a/packages/ui/src/components/logo.stories.tsx b/packages/ui/src/components/logo.stories.tsx new file mode 100644 index 0000000000..3f5dd9cef7 --- /dev/null +++ b/packages/ui/src/components/logo.stories.tsx @@ -0,0 +1,57 @@ +// @ts-nocheck +import * as mod from "./logo" + +const docs = `### Overview +OpenCode logo assets: mark, splash, and wordmark. + +Use Mark for compact spaces, Logo for headers, Splash for hero sections. + +### API +- \`Mark\`, \`Splash\`, and \`Logo\` components accept standard SVG props. + +### Variants and states +- Multiple logo variants for different contexts. + +### Behavior +- Pure SVG rendering. + +### Accessibility +- Provide title/aria-label when logos convey meaning. + +### Theming/tokens +- Uses theme color tokens via CSS variables. + +` + +export default { + title: "UI/Logo", + id: "components-logo", + component: mod.Logo, + tags: ["autodocs"], + parameters: { + docs: { + description: { + component: docs, + }, + }, + }, +} + +export const Basic = { + render: () => ( + <div style={{ display: "grid", gap: "16px", "align-items": "start" }}> + <div> + <div style={{ color: "var(--text-weak)", "font-size": "12px" }}>Mark</div> + <mod.Mark /> + </div> + <div> + <div style={{ color: "var(--text-weak)", "font-size": "12px" }}>Splash</div> + <mod.Splash style={{ width: "80px", height: "100px" }} /> + </div> + <div> + <div style={{ color: "var(--text-weak)", "font-size": "12px" }}>Logo</div> + <mod.Logo style={{ width: "200px" }} /> + </div> + </div> + ), +} diff --git a/packages/ui/src/components/markdown.stories.tsx b/packages/ui/src/components/markdown.stories.tsx new file mode 100644 index 0000000000..cae4294869 --- /dev/null +++ b/packages/ui/src/components/markdown.stories.tsx @@ -0,0 +1,53 @@ +// @ts-nocheck +import * as mod from "./markdown" +import { create } from "../storybook/scaffold" +import { markdown } from "../storybook/fixtures" + +const docs = `### Overview +Render sanitized Markdown with code blocks, inline code, and safe links. + +Pair with \`Code\` for standalone code views. + +### API +- Required: \`text\` Markdown string. +- Uses the Marked context provider for parsing and sanitization. + +### Variants and states +- Code blocks include copy buttons when rendered. + +### Behavior +- Sanitizes HTML and auto-converts inline URL code to links. +- Adds copy buttons to code blocks. + +### Accessibility +- Copy buttons include aria-labels from i18n. +- TODO: confirm link target behavior in sanitized output. + +### Theming/tokens +- Uses \`data-component="markdown"\` and related slots for styling. + +` + +const story = create({ + title: "UI/Markdown", + mod, + args: { + text: markdown, + }, +}) + +export default { + title: "UI/Markdown", + id: "components-markdown", + component: story.meta.component, + tags: ["autodocs"], + parameters: { + docs: { + description: { + component: docs, + }, + }, + }, +} + +export const Basic = story.Basic diff --git a/packages/ui/src/components/markdown.tsx b/packages/ui/src/components/markdown.tsx index be43eca81a..01254f1189 100644 --- a/packages/ui/src/components/markdown.tsx +++ b/packages/ui/src/components/markdown.tsx @@ -44,6 +44,19 @@ function sanitize(html: string) { return DOMPurify.sanitize(html, config) } +function escape(text: string) { + return text + .replace(/&/g, "&") + .replace(/</g, "<") + .replace(/>/g, ">") + .replace(/\"/g, """) + .replace(/'/g, "'") +} + +function fallback(markdown: string) { + return escape(markdown).replace(/\r\n?/g, "\n").replace(/\n/g, "<br>") +} + type CopyLabels = { copy: string copied: string @@ -103,6 +116,70 @@ function setCopyState(button: HTMLButtonElement, labels: CopyLabels, copied: boo button.setAttribute("data-tooltip", labels.copy) } +function ensureCodeWrapper(block: HTMLPreElement, labels: CopyLabels) { + const parent = block.parentElement + if (!parent) return + const wrapped = parent.getAttribute("data-component") === "markdown-code" + if (!wrapped) { + const wrapper = document.createElement("div") + wrapper.setAttribute("data-component", "markdown-code") + parent.replaceChild(wrapper, block) + wrapper.appendChild(block) + wrapper.appendChild(createCopyButton(labels)) + return + } + + const buttons = Array.from(parent.querySelectorAll('[data-slot="markdown-copy-button"]')).filter( + (el): el is HTMLButtonElement => el instanceof HTMLButtonElement, + ) + + if (buttons.length === 0) { + parent.appendChild(createCopyButton(labels)) + return + } + + for (const button of buttons.slice(1)) { + button.remove() + } +} + +function markCodeLinks(root: HTMLDivElement) { + const codeNodes = Array.from(root.querySelectorAll(":not(pre) > code")) + for (const code of codeNodes) { + const href = codeUrl(code.textContent ?? "") + const parentLink = + code.parentElement instanceof HTMLAnchorElement && code.parentElement.classList.contains("external-link") + ? code.parentElement + : null + + if (!href) { + if (parentLink) parentLink.replaceWith(code) + continue + } + + if (parentLink) { + parentLink.href = href + continue + } + + const link = document.createElement("a") + link.href = href + link.className = "external-link" + link.target = "_blank" + link.rel = "noopener noreferrer" + code.parentNode?.replaceChild(link, code) + link.appendChild(code) + } +} + +function decorate(root: HTMLDivElement, labels: CopyLabels) { + const blocks = Array.from(root.querySelectorAll("pre")) + for (const block of blocks) { + ensureCodeWrapper(block, labels) + } + markCodeLinks(root) +} + function setupCodeCopy(root: HTMLDivElement, labels: CopyLabels) { const timeouts = new Map<HTMLButtonElement, ReturnType<typeof setTimeout>>() @@ -111,47 +188,6 @@ function setupCodeCopy(root: HTMLDivElement, labels: CopyLabels) { setCopyState(button, labels, copied) } - const ensureWrapper = (block: HTMLPreElement) => { - const parent = block.parentElement - if (!parent) return - const wrapped = parent.getAttribute("data-component") === "markdown-code" - if (wrapped) return - const wrapper = document.createElement("div") - wrapper.setAttribute("data-component", "markdown-code") - parent.replaceChild(wrapper, block) - wrapper.appendChild(block) - wrapper.appendChild(createCopyButton(labels)) - } - - const markCodeLinks = () => { - const codeNodes = Array.from(root.querySelectorAll(":not(pre) > code")) - for (const code of codeNodes) { - const href = codeUrl(code.textContent ?? "") - const parentLink = - code.parentElement instanceof HTMLAnchorElement && code.parentElement.classList.contains("external-link") - ? code.parentElement - : null - - if (!href) { - if (parentLink) parentLink.replaceWith(code) - continue - } - - if (parentLink) { - parentLink.href = href - continue - } - - const link = document.createElement("a") - link.href = href - link.className = "external-link" - link.target = "_blank" - link.rel = "noopener noreferrer" - code.parentNode?.replaceChild(link, code) - link.appendChild(code) - } - } - const handleClick = async (event: MouseEvent) => { const target = event.target if (!(target instanceof Element)) return @@ -171,11 +207,7 @@ function setupCodeCopy(root: HTMLDivElement, labels: CopyLabels) { timeouts.set(button, timeout) } - const blocks = Array.from(root.querySelectorAll("pre")) - for (const block of blocks) { - ensureWrapper(block) - } - markCodeLinks() + decorate(root, labels) const buttons = Array.from(root.querySelectorAll('[data-slot="markdown-copy-button"]')) for (const button of buttons) { @@ -218,7 +250,7 @@ export function Markdown( const [html] = createResource( () => local.text, async (markdown) => { - if (isServer) return "" + if (isServer) return fallback(markdown) const hash = checksum(markdown) const key = local.cacheKey ?? hash @@ -236,7 +268,7 @@ export function Markdown( if (key && hash) touch(key, { hash, html: safe }) return safe }, - { initialValue: "" }, + { initialValue: isServer ? fallback(local.text) : "" }, ) let copySetupTimer: ReturnType<typeof setTimeout> | undefined @@ -255,26 +287,15 @@ export function Markdown( const temp = document.createElement("div") temp.innerHTML = content + decorate(temp, { + copy: i18n.t("ui.message.copy"), + copied: i18n.t("ui.message.copied"), + }) morphdom(container, temp, { childrenOnly: true, onBeforeElUpdated: (fromEl, toEl) => { if (fromEl.isEqualNode(toEl)) return false - if (fromEl.getAttribute("data-component") === "markdown-code") { - const fromPre = fromEl.querySelector("pre") - const toPre = toEl.querySelector("pre") - if (fromPre && toPre && !fromPre.isEqualNode(toPre)) { - morphdom(fromPre, toPre) - } - return false - } - return true - }, - onBeforeNodeDiscarded: (node) => { - if (node instanceof Element) { - if (node.getAttribute("data-slot") === "markdown-copy-button") return false - if (node.getAttribute("data-component") === "markdown-code") return false - } return true }, }) diff --git a/packages/ui/src/components/message-nav.css b/packages/ui/src/components/message-nav.css index cab16dfdc8..130b1f0f7c 100644 --- a/packages/ui/src/components/message-nav.css +++ b/packages/ui/src/components/message-nav.css @@ -95,7 +95,7 @@ color: var(--text-base); } -[data-slot="message-nav-tooltip"] { +.message-nav-tooltip { z-index: 1000; } diff --git a/packages/ui/src/components/message-nav.stories.tsx b/packages/ui/src/components/message-nav.stories.tsx new file mode 100644 index 0000000000..7ce31a7bed --- /dev/null +++ b/packages/ui/src/components/message-nav.stories.tsx @@ -0,0 +1,7 @@ +// @ts-nocheck +import * as mod from "./message-nav" +import { create } from "../storybook/scaffold" + +const story = create({ title: "UI/MessageNav", mod }) +export default { title: "UI/MessageNav", id: "components-message-nav", component: story.meta.component } +export const Basic = story.Basic diff --git a/packages/ui/src/components/message-nav.tsx b/packages/ui/src/components/message-nav.tsx index d151633faa..5e29746310 100644 --- a/packages/ui/src/components/message-nav.tsx +++ b/packages/ui/src/components/message-nav.tsx @@ -1,7 +1,7 @@ import { UserMessage } from "@opencode-ai/sdk/v2" import { ComponentProps, For, Match, Show, splitProps, Switch } from "solid-js" import { DiffChanges } from "./diff-changes" -import { Tooltip } from "@kobalte/core/tooltip" +import { Tooltip } from "./tooltip" import { useI18n } from "../context/i18n" export function MessageNav( @@ -70,15 +70,20 @@ export function MessageNav( return ( <Switch> <Match when={local.size === "compact"}> - <Tooltip openDelay={0} closeDelay={300} placement="right-start" gutter={-40} shift={-10} overlap> - <Tooltip.Trigger as="div">{content()}</Tooltip.Trigger> - <Tooltip.Portal> - <Tooltip.Content data-slot="message-nav-tooltip"> - <div data-slot="message-nav-tooltip-content"> - <MessageNav {...props} size="normal" class="" /> - </div> - </Tooltip.Content> - </Tooltip.Portal> + <Tooltip + openDelay={0} + placement="right-start" + gutter={-40} + shift={-10} + overlap + contentClass="message-nav-tooltip" + value={ + <div data-slot="message-nav-tooltip-content"> + <MessageNav {...props} size="normal" class="" /> + </div> + } + > + {content()} </Tooltip> </Match> <Match when={local.size === "normal"}>{content()}</Match> diff --git a/packages/ui/src/components/message-part.css b/packages/ui/src/components/message-part.css index 3415c034cf..704a57e5b0 100644 --- a/packages/ui/src/components/message-part.css +++ b/packages/ui/src/components/message-part.css @@ -21,7 +21,7 @@ align-self: stretch; width: 100%; max-width: 100%; - gap: 8px; + gap: 0; &[data-interrupted] { color: var(--text-weak); @@ -46,12 +46,18 @@ overflow: hidden; background: var(--surface-weak); border: 1px solid var(--border-weak-base); - transition: border-color 0.15s ease; + transition: + border-color 0.15s ease, + opacity 0.3s ease; &:hover { border-color: var(--border-strong-base); } + &[data-queued] { + opacity: 0.6; + } + &[data-type="image"] { width: 48px; height: 48px; @@ -92,6 +98,10 @@ align-items: flex-end; } + [data-slot="user-message-attachments"] + [data-slot="user-message-body"] { + margin-top: 8px; + } + [data-slot="user-message-text"] { display: inline-block; white-space: pre-wrap; @@ -101,6 +111,11 @@ border: 1px solid var(--border-weak-base); padding: 8px 12px; border-radius: 6px; + transition: opacity 0.3s ease; + + &[data-queued] { + opacity: 0.6; + } [data-highlight="file"] { color: var(--syntax-property); @@ -113,6 +128,14 @@ max-width: 100%; } + [data-slot="user-message-queued-indicator"] { + margin-top: 6px; + margin-right: 2px; + font-size: var(--font-size-small); + color: var(--text-weak); + user-select: none; + } + [data-slot="user-message-copy-wrapper"] { min-height: 24px; margin-top: 4px; @@ -149,6 +172,7 @@ align-items: center; justify-content: flex-end; overflow: hidden; + gap: 0; } [data-slot="user-message-meta-tail"] { @@ -225,6 +249,33 @@ } } +[data-component="compaction-part"] { + width: 100%; + display: flex; + flex-direction: column; + align-items: stretch; + + [data-slot="compaction-part-divider"] { + display: flex; + align-items: center; + gap: 12px; + padding: 10px 0; + width: 100%; + } + + [data-slot="compaction-part-line"] { + flex: 1 1 auto; + height: 1px; + background: var(--border-weak-base); + } + + [data-slot="compaction-part-label"] { + flex: 0 0 auto; + white-space: nowrap; + text-align: center; + } +} + [data-component="reasoning-part"] { width: 100%; color: var(--text-base); @@ -252,6 +303,12 @@ } } +@media (prefers-color-scheme: dark) { + [data-component="reasoning-part"] [data-component="markdown"] :not(pre) > code { + opacity: 0.6; + } +} + [data-component="tool-error"] { display: flex; align-items: start; @@ -332,14 +389,6 @@ } } -[data-slot="collapsible-content"]:has([data-component="edit-content"]), -[data-slot="collapsible-content"]:has([data-component="write-content"]) { - border: 1px solid var(--border-weak-base); - border-radius: 6px; - background: transparent; - overflow: hidden; -} - [data-component="bash-output"] { width: 100%; border: 1px solid var(--border-weak-base); @@ -399,11 +448,6 @@ } } -[data-slot="collapsible-content"]:has([data-component="edit-content"]) [data-component="edit-content"], -[data-slot="collapsible-content"]:has([data-component="write-content"]) [data-component="write-content"] { - border-top: none; -} - [data-component="edit-trigger"], [data-component="write-trigger"] { display: flex; @@ -490,9 +534,10 @@ } [data-component="edit-content"] { + border-radius: inherit; border-top: 1px solid var(--border-weaker-base); - max-height: 420px; - overflow-y: auto; + overflow-x: hidden; + overflow-y: visible; scrollbar-width: none; -ms-overflow-style: none; @@ -500,15 +545,23 @@ &::-webkit-scrollbar { display: none; } + + [data-component="diff"] { + border-radius: inherit; + overflow: hidden; + } } [data-component="write-content"] { + border-radius: inherit; border-top: 1px solid var(--border-weaker-base); - max-height: 240px; - overflow-y: auto; + overflow-x: hidden; + overflow-y: visible; [data-component="code"] { - padding-bottom: 0px !important; + padding-bottom: 0 !important; + border-radius: inherit; + overflow: hidden; } /* Hide scrollbar */ @@ -528,6 +581,46 @@ justify-content: center; } +[data-component="exa-tool-output"] { + width: 100%; + padding-top: 8px; + display: flex; + flex-direction: column; +} + +[data-slot="basic-tool-tool-subtitle"].exa-tool-query { + display: block; + max-width: 100%; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +[data-slot="exa-tool-links"] { + display: flex; + flex-direction: column; + gap: 4px; +} + +[data-slot="exa-tool-link"] { + display: block; + max-width: 100%; + color: var(--text-interactive-base); + text-decoration: underline; + text-underline-offset: 2px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + + &:hover { + color: var(--text-interactive-base); + } + + &:visited { + color: var(--text-interactive-base); + } +} + [data-component="todos"] { padding: 10px 0 24px 0; display: flex; @@ -559,29 +652,8 @@ cursor: pointer; [data-slot="context-tool-group-title"] { - min-width: 0; - display: flex; - align-items: center; - gap: 8px; - font-family: var(--font-family-sans); - font-size: 14px; - font-weight: var(--font-weight-medium); - line-height: var(--line-height-large); - color: var(--text-strong); - } - - [data-slot="context-tool-group-label"] { - flex-shrink: 0; - } - - [data-slot="context-tool-group-summary"] { flex-shrink: 1; min-width: 0; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - font-weight: var(--font-weight-regular); - color: var(--text-base); } [data-slot="collapsible-arrow"] { @@ -647,6 +719,7 @@ [data-component="reasoning-part"], [data-component="tool-error"], [data-component="tool-output"], +[data-component="bash-output"], [data-component="edit-content"], [data-component="write-content"], [data-component="todos"], @@ -658,105 +731,6 @@ [data-component="tool-part-wrapper"] { width: 100%; - - &[data-permission="true"], - &[data-question="true"] { - position: sticky; - top: calc(2px + var(--sticky-header-height, 40px)); - bottom: 0px; - z-index: 20; - border-radius: 6px; - border: none; - box-shadow: var(--shadow-xs-border-base); - background-color: var(--surface-raised-base); - overflow: visible; - overflow-anchor: none; - - & > *:first-child { - border-top-left-radius: 6px; - border-top-right-radius: 6px; - overflow: hidden; - } - - & > *:last-child { - border-bottom-left-radius: 6px; - border-bottom-right-radius: 6px; - overflow: hidden; - } - - [data-component="collapsible"] { - border: none; - } - - [data-component="card"] { - border: none; - } - } - - &[data-permission="true"] { - &::before { - content: ""; - position: absolute; - inset: -1.5px; - top: -5px; - border-radius: 7.5px; - border: 1.5px solid transparent; - background: - linear-gradient(var(--background-base) 0 0) padding-box, - conic-gradient( - from var(--border-angle), - transparent 0deg, - transparent 0deg, - var(--border-warning-strong, var(--border-warning-selected)) 300deg, - var(--border-warning-base) 360deg - ) - border-box; - animation: chase-border 2.5s linear infinite; - pointer-events: none; - z-index: -1; - } - } - - &[data-question="true"] { - background: var(--background-base); - border: 1px solid var(--border-weak-base); - } -} - -@property --border-angle { - syntax: "<angle>"; - initial-value: 0deg; - inherits: false; -} - -@keyframes chase-border { - from { - --border-angle: 0deg; - } - - to { - --border-angle: 360deg; - } -} - -[data-component="permission-prompt"] { - display: flex; - flex-direction: column; - padding: 8px 12px; - background-color: var(--surface-raised-strong); - border-radius: 0 0 6px 6px; - - [data-slot="permission-actions"] { - display: flex; - align-items: center; - gap: 8px; - justify-content: flex-end; - - [data-component="button"] { - padding-left: 12px; - padding-right: 12px; - } - } } [data-component="dock-prompt"][data-kind="permission"] { @@ -871,7 +845,7 @@ } } -:is([data-component="question-prompt"], [data-component="dock-prompt"][data-kind="question"]) { +[data-component="dock-prompt"][data-kind="question"] { position: relative; display: flex; flex-direction: column; @@ -1201,11 +1175,18 @@ } } +[data-component="edit-tool"], +[data-component="write-tool"], [data-component="apply-patch-tool"] { > [data-component="collapsible"].tool-collapsible { gap: 0px; } + > [data-component="collapsible"] > [data-slot="collapsible-content"] { + border: none; + background: transparent; + } + > [data-component="collapsible"] > [data-slot="collapsible-trigger"][aria-expanded="true"] { position: sticky; top: var(--sticky-accordion-top, 0px); @@ -1285,13 +1266,20 @@ } [data-component="apply-patch-file-diff"] { - overflow-y: auto; + border-radius: inherit; + overflow-x: hidden; + overflow-y: visible; scrollbar-width: none; -ms-overflow-style: none; &::-webkit-scrollbar { display: none; } + + [data-component="diff"] { + border-radius: inherit; + overflow: hidden; + } } [data-component="tool-loaded-file"] { diff --git a/packages/ui/src/components/message-part.stories.tsx b/packages/ui/src/components/message-part.stories.tsx new file mode 100644 index 0000000000..28489dc7b1 --- /dev/null +++ b/packages/ui/src/components/message-part.stories.tsx @@ -0,0 +1,7 @@ +// @ts-nocheck +import * as mod from "./message-part" +import { create } from "../storybook/scaffold" + +const story = create({ title: "UI/MessagePart", mod }) +export default { title: "UI/MessagePart", id: "components-message-part", component: story.meta.component } +export const Basic = story.Basic diff --git a/packages/ui/src/components/message-part.tsx b/packages/ui/src/components/message-part.tsx index 828ddbe87d..45b174e2b8 100644 --- a/packages/ui/src/components/message-part.tsx +++ b/packages/ui/src/components/message-part.tsx @@ -5,9 +5,11 @@ import { createSignal, For, Match, + onMount, Show, Switch, onCleanup, + Index, type JSX, } from "solid-js" import stripAnsi from "strip-ansi" @@ -23,21 +25,16 @@ import { ToolPart, UserMessage, Todo, - QuestionRequest, QuestionAnswer, QuestionInfo, } from "@opencode-ai/sdk/v2" -import { createStore } from "solid-js/store" import { useData } from "../context" -import { useDiffComponent } from "../context/diff" -import { useCodeComponent } from "../context/code" +import { useFileComponent } from "../context/file" import { useDialog } from "../context/dialog" -import { useI18n } from "../context/i18n" -import { BasicTool } from "./basic-tool" -import { GenericTool } from "./basic-tool" +import { type UiI18n, useI18n } from "../context/i18n" +import { BasicTool, GenericTool } from "./basic-tool" import { Accordion } from "./accordion" import { StickyAccordionHeader } from "./sticky-accordion-header" -import { Button } from "./button" import { Card } from "./card" import { Collapsible } from "./collapsible" import { FileIcon } from "./file-icon" @@ -51,6 +48,43 @@ import { checksum } from "@opencode-ai/util/encode" import { Tooltip } from "./tooltip" import { IconButton } from "./icon-button" import { TextShimmer } from "./text-shimmer" +import { AnimatedCountList } from "./tool-count-summary" +import { ToolStatusTitle } from "./tool-status-title" +import { animate } from "motion" +import { useLocation } from "@solidjs/router" + +function ShellSubmessage(props: { text: string; animate?: boolean }) { + let widthRef: HTMLSpanElement | undefined + let valueRef: HTMLSpanElement | undefined + + onMount(() => { + if (!props.animate) return + requestAnimationFrame(() => { + if (widthRef) { + animate(widthRef, { width: "auto" }, { type: "spring", visualDuration: 0.25, bounce: 0 }) + } + if (valueRef) { + animate(valueRef, { opacity: 1, filter: "blur(0px)" }, { duration: 0.32, ease: [0.16, 1, 0.3, 1] }) + } + }) + }) + + return ( + <span data-component="shell-submessage"> + <span ref={widthRef} data-slot="shell-submessage-width" style={{ width: props.animate ? "0px" : undefined }}> + <span data-slot="basic-tool-tool-subtitle"> + <span + ref={valueRef} + data-slot="shell-submessage-value" + style={props.animate ? { opacity: 0, filter: "blur(2px)" } : undefined} + > + {props.text} + </span> + </span> + </span> + </span> + ) +} interface Diagnostic { range: { @@ -96,6 +130,7 @@ export interface MessageProps { parts: PartType[] showAssistantCopyPartID?: string | null interrupted?: boolean + queued?: boolean showReasoningSummaries?: boolean } @@ -148,17 +183,22 @@ function createThrottledValue(getValue: () => string) { return value } -function relativizeProjectPaths(text: string, directory?: string) { - if (!text) return "" - if (!directory) return text - if (directory === "/") return text - if (directory === "\\") return text - return text.split(directory).join("") +function relativizeProjectPath(path: string, directory?: string) { + if (!path) return "" + if (!directory) return path + if (directory === "/") return path + if (directory === "\\") return path + if (path === directory) return "" + + const separator = directory.includes("\\") ? "\\" : "/" + const prefix = directory.endsWith(separator) ? directory : directory + separator + if (!path.startsWith(prefix)) return path + return path.slice(directory.length) } function getDirectory(path: string | undefined) { const data = useData() - return relativizeProjectPaths(_getDirectory(path), data.directory) + return relativizeProjectPath(_getDirectory(path), data.directory) } import type { IconProps } from "./icon" @@ -169,6 +209,11 @@ export type ToolInfo = { subtitle?: string } +function agentTitle(i18n: UiI18n, type?: string) { + if (!type) return i18n.t("ui.tool.agent.default") + return i18n.t("ui.tool.agent", { type }) +} + export function getToolInfo(tool: string, input: any = {}): ToolInfo { const i18n = useI18n() switch (tool) { @@ -202,12 +247,29 @@ export function getToolInfo(tool: string, input: any = {}): ToolInfo { title: i18n.t("ui.tool.webfetch"), subtitle: input.url, } - case "task": + case "websearch": + return { + icon: "window-cursor", + title: i18n.t("ui.tool.websearch"), + subtitle: input.query, + } + case "codesearch": + return { + icon: "code", + title: i18n.t("ui.tool.codesearch"), + subtitle: input.query, + } + case "task": { + const type = + typeof input.subagent_type === "string" && input.subagent_type + ? input.subagent_type[0]!.toUpperCase() + input.subagent_type.slice(1) + : undefined return { icon: "task", - title: i18n.t("ui.tool.agent", { type: input.subagent_type || "task" }), + title: agentTitle(i18n, type), subtitle: input.description, } + } case "bash": return { icon: "console", @@ -249,6 +311,11 @@ export function getToolInfo(tool: string, input: any = {}): ToolInfo { icon: "bubble-5", title: i18n.t("ui.tool.questions"), } + case "skill": + return { + icon: "brain", + title: input.name || "skill", + } default: return { icon: "mcp", @@ -257,6 +324,18 @@ export function getToolInfo(tool: string, input: any = {}): ToolInfo { } } +function urls(text: string | undefined) { + if (!text) return [] + const seen = new Set<string>() + return [...text.matchAll(/https?:\/\/[^\s<>"'`)\]]+/g)] + .map((item) => item[0].replace(/[),.;:!?]+$/g, "")) + .filter((item) => { + if (seen.has(item)) return false + seen.add(item) + return true + }) +} + const CONTEXT_GROUP_TOOLS = new Set(["read", "glob", "grep", "list"]) const HIDDEN_TOOLS = new Set(["todowrite", "todoread"]) @@ -265,6 +344,102 @@ function list<T>(value: T[] | undefined | null, fallback: T[]) { return fallback } +function same<T>(a: readonly T[] | undefined, b: readonly T[] | undefined) { + if (a === b) return true + if (!a || !b) return false + if (a.length !== b.length) return false + return a.every((x, i) => x === b[i]) +} + +type PartRef = { + messageID: string + partID: string +} + +type PartGroup = + | { + key: string + type: "part" + ref: PartRef + } + | { + key: string + type: "context" + refs: PartRef[] + } + +function sameRef(a: PartRef, b: PartRef) { + return a.messageID === b.messageID && a.partID === b.partID +} + +function sameGroup(a: PartGroup, b: PartGroup) { + if (a === b) return true + if (a.key !== b.key) return false + if (a.type !== b.type) return false + if (a.type === "part") { + if (b.type !== "part") return false + return sameRef(a.ref, b.ref) + } + if (b.type !== "context") return false + if (a.refs.length !== b.refs.length) return false + return a.refs.every((ref, i) => sameRef(ref, b.refs[i]!)) +} + +function sameGroups(a: readonly PartGroup[] | undefined, b: readonly PartGroup[] | undefined) { + if (a === b) return true + if (!a || !b) return false + if (a.length !== b.length) return false + return a.every((item, i) => sameGroup(item, b[i]!)) +} + +function groupParts(parts: { messageID: string; part: PartType }[]) { + const result: PartGroup[] = [] + let start = -1 + + const flush = (end: number) => { + if (start < 0) return + const first = parts[start] + const last = parts[end] + if (!first || !last) { + start = -1 + return + } + result.push({ + key: `context:${first.part.id}`, + type: "context", + refs: parts.slice(start, end + 1).map((item) => ({ + messageID: item.messageID, + partID: item.part.id, + })), + }) + start = -1 + } + + parts.forEach((item, index) => { + if (isContextGroupTool(item.part)) { + if (start < 0) start = index + return + } + + flush(index - 1) + result.push({ + key: `part:${item.messageID}:${item.part.id}`, + type: "part", + ref: { + messageID: item.messageID, + partID: item.part.id, + }, + }) + }) + + flush(parts.length - 1) + return result +} + +function partByID(parts: readonly PartType[], partID: string) { + return parts.find((part) => part.id === partID) +} + function renderable(part: PartType, showReasoningSummaries = true) { if (part.type === "tool") { if (HIDDEN_TOOLS.has(part.tool)) return false @@ -276,109 +451,108 @@ function renderable(part: PartType, showReasoningSummaries = true) { return !!PART_MAPPING[part.type] } +function toolDefaultOpen(tool: string, shell = false, edit = false) { + if (tool === "bash") return shell + if (tool === "edit" || tool === "write" || tool === "apply_patch") return edit +} + +function partDefaultOpen(part: PartType, shell = false, edit = false) { + if (part.type !== "tool") return + return toolDefaultOpen(part.tool, shell, edit) +} + export function AssistantParts(props: { messages: AssistantMessage[] showAssistantCopyPartID?: string | null turnDurationMs?: number working?: boolean showReasoningSummaries?: boolean + shellToolDefaultOpen?: boolean + editToolDefaultOpen?: boolean }) { const data = useData() const emptyParts: PartType[] = [] + const emptyTools: ToolPart[] = [] - const grouped = createMemo(() => { - const keys: string[] = [] - const items: Record< - string, - { type: "part"; part: PartType; message: AssistantMessage } | { type: "context"; parts: ToolPart[] } - > = {} - const push = ( - key: string, - item: { type: "part"; part: PartType; message: AssistantMessage } | { type: "context"; parts: ToolPart[] }, - ) => { - keys.push(key) - items[key] = item - } + const grouped = createMemo( + () => + groupParts( + props.messages.flatMap((message) => + list(data.store.part?.[message.id], emptyParts) + .filter((part) => renderable(part, props.showReasoningSummaries ?? true)) + .map((part) => ({ + messageID: message.id, + part, + })), + ), + ), + [] as PartGroup[], + { equals: sameGroups }, + ) - const parts = props.messages.flatMap((message) => - list(data.store.part?.[message.id], emptyParts) - .filter((part) => renderable(part, props.showReasoningSummaries ?? true)) - .map((part) => ({ message, part })), - ) - - let start = -1 - - const flush = (end: number) => { - if (start < 0) return - const first = parts[start] - const last = parts[end] - if (!first || !last) { - start = -1 - return - } - push(`context:${first.part.id}`, { - type: "context", - parts: parts - .slice(start, end + 1) - .map((x) => x.part) - .filter((part): part is ToolPart => isContextGroupTool(part)), - }) - start = -1 - } - - parts.forEach((item, index) => { - if (isContextGroupTool(item.part)) { - if (start < 0) start = index - return - } - - flush(index - 1) - push(`part:${item.message.id}:${item.part.id}`, { type: "part", part: item.part, message: item.message }) - }) - - flush(parts.length - 1) - - return { keys, items } - }) - - const last = createMemo(() => grouped().keys.at(-1)) + const last = createMemo(() => grouped().at(-1)?.key) return ( - <For each={grouped().keys}> - {(key) => { - const item = createMemo(() => grouped().items[key]) - const ctx = createMemo(() => { - const value = item() - if (!value) return - if (value.type !== "context") return - return value - }) - const part = createMemo(() => { - const value = item() - if (!value) return - if (value.type !== "part") return - return value - }) - const tail = createMemo(() => last() === key) + <Index each={grouped()}> + {(entryAccessor) => { + const entryType = createMemo(() => entryAccessor().type) + return ( - <> - <Show when={ctx()}> - {(entry) => <ContextToolGroup parts={entry().parts} busy={props.working && tail()} />} - </Show> - <Show when={part()}> - {(entry) => ( - <Part - part={entry().part} - message={entry().message} - showAssistantCopyPartID={props.showAssistantCopyPartID} - turnDurationMs={props.turnDurationMs} - /> - )} - </Show> - </> + <Switch> + <Match when={entryType() === "context"}> + {(() => { + const parts = createMemo( + () => { + const entry = entryAccessor() + if (entry.type !== "context") return emptyTools + return entry.refs + .map((ref) => partByID(list(data.store.part?.[ref.messageID], emptyParts), ref.partID)) + .filter((part): part is ToolPart => !!part && isContextGroupTool(part)) + }, + emptyTools, + { equals: same }, + ) + const busy = createMemo(() => props.working && last() === entryAccessor().key) + + return ( + <Show when={parts().length > 0}> + <ContextToolGroup parts={parts()} busy={busy()} /> + </Show> + ) + })()} + </Match> + <Match when={entryType() === "part"}> + {(() => { + const message = createMemo(() => { + const entry = entryAccessor() + if (entry.type !== "part") return + return props.messages.find((item) => item.id === entry.ref.messageID) + }) + const part = createMemo(() => { + const entry = entryAccessor() + if (entry.type !== "part") return + return partByID(list(data.store.part?.[entry.ref.messageID], emptyParts), entry.ref.partID) + }) + + return ( + <Show when={message()}> + <Show when={part()}> + <Part + part={part()!} + message={message()!} + showAssistantCopyPartID={props.showAssistantCopyPartID} + turnDurationMs={props.turnDurationMs} + defaultOpen={partDefaultOpen(part()!, props.shellToolDefaultOpen, props.editToolDefaultOpen)} + /> + </Show> + </Show> + ) + })()} + </Match> + </Switch> ) }} - </For> + </Index> ) } @@ -453,11 +627,33 @@ function contextToolSummary(parts: ToolPart[]) { const read = parts.filter((part) => part.tool === "read").length const search = parts.filter((part) => part.tool === "glob" || part.tool === "grep").length const list = parts.filter((part) => part.tool === "list").length - return [ - read ? `${read} ${read === 1 ? "read" : "reads"}` : undefined, - search ? `${search} ${search === 1 ? "search" : "searches"}` : undefined, - list ? `${list} ${list === 1 ? "list" : "lists"}` : undefined, - ].filter((value): value is string => !!value) + return { read, search, list } +} + +function ExaOutput(props: { output?: string }) { + const links = createMemo(() => urls(props.output)) + + return ( + <Show when={links().length > 0}> + <div data-component="exa-tool-output"> + <div data-slot="exa-tool-links"> + <For each={links()}> + {(url) => ( + <a + data-slot="exa-tool-link" + href={url} + target="_blank" + rel="noopener noreferrer" + onClick={(event) => event.stopPropagation()} + > + {url} + </a> + )} + </For> + </div> + </div> + </Show> + ) } export function registerPartComponent(type: string, component: PartComponent) { @@ -473,6 +669,7 @@ export function Message(props: MessageProps) { message={userMessage() as UserMessage} parts={props.parts} interrupted={props.interrupted} + queued={props.queued} /> )} </Match> @@ -496,81 +693,72 @@ export function AssistantMessageDisplay(props: { showAssistantCopyPartID?: string | null showReasoningSummaries?: boolean }) { - const grouped = createMemo(() => { - const keys: string[] = [] - const items: Record<string, { type: "part"; part: PartType } | { type: "context"; parts: ToolPart[] }> = {} - const push = (key: string, item: { type: "part"; part: PartType } | { type: "context"; parts: ToolPart[] }) => { - keys.push(key) - items[key] = item - } - - const parts = props.parts - let start = -1 - - const flush = (end: number) => { - if (start < 0) return - const first = parts[start] - const last = parts[end] - if (!first || !last) { - start = -1 - return - } - push(`context:${first.id}`, { - type: "context", - parts: parts.slice(start, end + 1).filter((part): part is ToolPart => isContextGroupTool(part)), - }) - start = -1 - } - - parts.forEach((part, index) => { - if (!renderable(part, props.showReasoningSummaries ?? true)) return - - if (isContextGroupTool(part)) { - if (start < 0) start = index - return - } - - flush(index - 1) - push(`part:${part.id}`, { type: "part", part }) - }) - - flush(parts.length - 1) - - return { keys, items } - }) + const emptyTools: ToolPart[] = [] + const grouped = createMemo( + () => + groupParts( + props.parts + .filter((part) => renderable(part, props.showReasoningSummaries ?? true)) + .map((part) => ({ + messageID: props.message.id, + part, + })), + ), + [] as PartGroup[], + { equals: sameGroups }, + ) return ( - <For each={grouped().keys}> - {(key) => { - const item = createMemo(() => grouped().items[key]) - const ctx = createMemo(() => { - const value = item() - if (!value) return - if (value.type !== "context") return - return value - }) - const part = createMemo(() => { - const value = item() - if (!value) return - if (value.type !== "part") return - return value - }) + <Index each={grouped()}> + {(entryAccessor) => { + const entryType = createMemo(() => entryAccessor().type) + return ( - <> - <Show when={ctx()}>{(entry) => <ContextToolGroup parts={entry().parts} />}</Show> - <Show when={part()}> - {(entry) => ( - <Part - part={entry().part} - message={props.message} - showAssistantCopyPartID={props.showAssistantCopyPartID} - /> - )} - </Show> - </> + <Switch> + <Match when={entryType() === "context"}> + {(() => { + const parts = createMemo( + () => { + const entry = entryAccessor() + if (entry.type !== "context") return emptyTools + return entry.refs + .map((ref) => partByID(props.parts, ref.partID)) + .filter((part): part is ToolPart => !!part && isContextGroupTool(part)) + }, + emptyTools, + { equals: same }, + ) + + return ( + <Show when={parts().length > 0}> + <ContextToolGroup parts={parts()} /> + </Show> + ) + })()} + </Match> + <Match when={entryType() === "part"}> + {(() => { + const part = createMemo(() => { + const entry = entryAccessor() + if (entry.type !== "part") return + return partByID(props.parts, entry.ref.partID) + }) + + return ( + <Show when={part()}> + <Part + part={part()!} + message={props.message} + showAssistantCopyPartID={props.showAssistantCopyPartID} + /> + </Show> + ) + })()} + </Match> + </Switch> ) }} - </For> + </Index> ) } @@ -582,41 +770,63 @@ function ContextToolGroup(props: { parts: ToolPart[]; busy?: boolean }) { !!props.busy || props.parts.some((part) => part.state.status === "pending" || part.state.status === "running"), ) const summary = createMemo(() => contextToolSummary(props.parts)) - const details = createMemo(() => summary().join(", ")) return ( <Collapsible open={open()} onOpenChange={setOpen} variant="ghost"> <Collapsible.Trigger> <div data-component="context-tool-group-trigger"> - <Show - when={pending()} - fallback={ - <span data-slot="context-tool-group-title"> - <span data-slot="context-tool-group-label">{i18n.t("ui.sessionTurn.status.gatheredContext")}</span> - <Show when={details().length}> - <span data-slot="context-tool-group-summary">{details()}</span> - </Show> - </span> - } + <span + data-slot="context-tool-group-title" + class="min-w-0 flex items-center gap-2 text-14-medium text-text-strong" > - <span data-slot="context-tool-group-title"> - <span data-slot="context-tool-group-label"> - <TextShimmer text={i18n.t("ui.sessionTurn.status.gatheringContext")} /> - </span> - <Show when={details().length}> - <span data-slot="context-tool-group-summary">{details()}</span> - </Show> + <span data-slot="context-tool-group-label" class="shrink-0"> + <ToolStatusTitle + active={pending()} + activeText={i18n.t("ui.sessionTurn.status.gatheringContext")} + doneText={i18n.t("ui.sessionTurn.status.gatheredContext")} + split={false} + /> </span> - </Show> + <span + data-slot="context-tool-group-summary" + class="min-w-0 overflow-hidden text-ellipsis whitespace-nowrap font-normal text-text-base" + > + <AnimatedCountList + items={[ + { + key: "read", + count: summary().read, + one: i18n.t("ui.messagePart.context.read.one"), + other: i18n.t("ui.messagePart.context.read.other"), + }, + { + key: "search", + count: summary().search, + one: i18n.t("ui.messagePart.context.search.one"), + other: i18n.t("ui.messagePart.context.search.other"), + }, + { + key: "list", + count: summary().list, + one: i18n.t("ui.messagePart.context.list.one"), + other: i18n.t("ui.messagePart.context.list.other"), + }, + ]} + fallback="" + /> + </span> + </span> <Collapsible.Arrow /> </div> </Collapsible.Trigger> <Collapsible.Content> <div data-component="context-tool-group-list"> - <For each={props.parts}> - {(part) => { - const trigger = contextToolTrigger(part, i18n) - const running = part.state.status === "pending" || part.state.status === "running" + <Index each={props.parts}> + {(partAccessor) => { + const trigger = createMemo(() => contextToolTrigger(partAccessor(), i18n)) + const running = createMemo( + () => partAccessor().state.status === "pending" || partAccessor().state.status === "running", + ) return ( <div data-slot="context-tool-group-item"> <div data-component="tool-trigger"> @@ -625,15 +835,13 @@ function ContextToolGroup(props: { parts: ToolPart[]; busy?: boolean }) { <div data-slot="basic-tool-tool-info-structured"> <div data-slot="basic-tool-tool-info-main"> <span data-slot="basic-tool-tool-title"> - <Show when={running} fallback={trigger.title}> - <TextShimmer text={trigger.title} /> - </Show> + <TextShimmer text={trigger().title} active={running()} /> </span> - <Show when={!running && trigger.subtitle}> - <span data-slot="basic-tool-tool-subtitle">{trigger.subtitle}</span> + <Show when={!running() && trigger().subtitle}> + <span data-slot="basic-tool-tool-subtitle">{trigger().subtitle}</span> </Show> - <Show when={!running && trigger.args?.length}> - <For each={trigger.args}> + <Show when={!running() && trigger().args?.length}> + <For each={trigger().args}> {(arg) => <span data-slot="basic-tool-tool-arg">{arg}</span>} </For> </Show> @@ -645,14 +853,19 @@ function ContextToolGroup(props: { parts: ToolPart[]; busy?: boolean }) { </div> ) }} - </For> + </Index> </div> </Collapsible.Content> </Collapsible> ) } -export function UserMessageDisplay(props: { message: UserMessage; parts: PartType[]; interrupted?: boolean }) { +export function UserMessageDisplay(props: { + message: UserMessage + parts: PartType[] + interrupted?: boolean + queued?: boolean +}) { const data = useData() const dialog = useDialog() const i18n = useI18n() @@ -732,6 +945,7 @@ export function UserMessageDisplay(props: { message: UserMessage; parts: PartTyp <div data-slot="user-message-attachment" data-type={file.mime.startsWith("image/") ? "image" : "file"} + data-queued={props.queued ? "" : undefined} onClick={() => { if (file.mime.startsWith("image/") && file.url) { openImagePreview(file.url, file.filename) @@ -760,9 +974,14 @@ export function UserMessageDisplay(props: { message: UserMessage; parts: PartTyp <Show when={text()}> <> <div data-slot="user-message-body"> - <div data-slot="user-message-text"> + <div data-slot="user-message-text" data-queued={props.queued ? "" : undefined}> <HighlightedText text={text()} references={inlineFiles()} agents={agents()} /> </div> + <Show when={props.queued}> + <div data-slot="user-message-queued-indicator"> + <TextShimmer text={i18n.t("ui.message.queued")} /> + </div> + </Show> </div> <div data-slot="user-message-copy-wrapper" data-interrupted={props.interrupted ? "" : undefined}> <Show when={metaHead() || metaTail()}> @@ -900,94 +1119,72 @@ export const ToolRegistry = { render: getTool, } +function ToolFileAccordion(props: { path: string; actions?: JSX.Element; children: JSX.Element }) { + const value = createMemo(() => props.path || "tool-file") + + return ( + <Accordion + multiple + data-scope="apply-patch" + style={{ "--sticky-accordion-offset": "40px" }} + defaultValue={[value()]} + > + <Accordion.Item value={value()}> + <StickyAccordionHeader> + <Accordion.Trigger> + <div data-slot="apply-patch-trigger-content"> + <div data-slot="apply-patch-file-info"> + <FileIcon node={{ path: props.path, type: "file" }} /> + <div data-slot="apply-patch-file-name-container"> + <Show when={props.path.includes("/")}> + <span data-slot="apply-patch-directory">{`\u202A${getDirectory(props.path)}\u202C`}</span> + </Show> + <span data-slot="apply-patch-filename">{getFilename(props.path)}</span> + </div> + </div> + <div data-slot="apply-patch-trigger-actions"> + {props.actions} + <Icon name="chevron-grabber-vertical" size="small" /> + </div> + </div> + </Accordion.Trigger> + </StickyAccordionHeader> + <Accordion.Content>{props.children}</Accordion.Content> + </Accordion.Item> + </Accordion> + ) +} + PART_MAPPING["tool"] = function ToolPartDisplay(props) { - const data = useData() const i18n = useI18n() - const part = props.part as ToolPart - if (part.tool === "todowrite" || part.tool === "todoread") return null + const part = () => props.part as ToolPart + if (part().tool === "todowrite" || part().tool === "todoread") return null const hideQuestion = createMemo( - () => part.tool === "question" && (part.state.status === "pending" || part.state.status === "running"), + () => part().tool === "question" && (part().state.status === "pending" || part().state.status === "running"), ) - const permission = createMemo(() => { - const next = data.store.permission?.[props.message.sessionID]?.[0] - if (!next || !next.tool) return undefined - if (next.tool!.callID !== part.callID) return undefined - return next - }) - - const questionRequest = createMemo(() => { - const next = data.store.question?.[props.message.sessionID]?.[0] - if (!next || !next.tool) return undefined - if (next.tool!.callID !== part.callID) return undefined - return next - }) - - const [showPermission, setShowPermission] = createSignal(false) - const [showQuestion, setShowQuestion] = createSignal(false) - - createEffect(() => { - const perm = permission() - if (perm) { - const timeout = setTimeout(() => setShowPermission(true), 50) - onCleanup(() => clearTimeout(timeout)) - } else { - setShowPermission(false) - } - }) - - createEffect(() => { - const question = questionRequest() - if (question) { - const timeout = setTimeout(() => setShowQuestion(true), 50) - onCleanup(() => clearTimeout(timeout)) - } else { - setShowQuestion(false) - } - }) - - const [forceOpen, setForceOpen] = createSignal(false) - createEffect(() => { - if (permission() || questionRequest()) setForceOpen(true) - }) - - const respond = (response: "once" | "always" | "reject") => { - const perm = permission() - if (!perm || !data.respondToPermission) return - data.respondToPermission({ - sessionID: perm.sessionID, - permissionID: perm.id, - response, - }) - } - const emptyInput: Record<string, any> = {} const emptyMetadata: Record<string, any> = {} - const input = () => part.state?.input ?? emptyInput + const input = () => part().state?.input ?? emptyInput // @ts-expect-error - const partMetadata = () => part.state?.metadata ?? emptyMetadata - const metadata = () => { - const perm = permission() - if (perm?.metadata) return { ...perm.metadata, ...partMetadata() } - return partMetadata() - } + const partMetadata = () => part().state?.metadata ?? emptyMetadata - const render = ToolRegistry.render(part.tool) ?? GenericTool + const render = createMemo(() => ToolRegistry.render(part().tool) ?? GenericTool) return ( <Show when={!hideQuestion()}> - <div data-component="tool-part-wrapper" data-permission={showPermission()} data-question={showQuestion()}> + <div data-component="tool-part-wrapper"> <Switch> - <Match when={part.state.status === "error" && part.state.error}> + <Match when={part().state.status === "error" && (part().state as any).error}> {(error) => { const cleaned = error().replace("Error: ", "") - if (part.tool === "question" && cleaned.includes("dismissed this question")) { + if (part().tool === "question" && cleaned.includes("dismissed this question")) { return ( <div style="width: 100%; display: flex; justify-content: flex-end;"> <span class="text-13-regular text-text-weak cursor-default"> - {i18n.t("ui.tool.questions")} dismissed + {i18n.t("ui.messagePart.questions.dismissed")} </span> </div> ) @@ -1015,45 +1212,42 @@ PART_MAPPING["tool"] = function ToolPartDisplay(props) { </Match> <Match when={true}> <Dynamic - component={render} + component={render()} input={input()} - tool={part.tool} - metadata={metadata()} + tool={part().tool} + metadata={partMetadata()} // @ts-expect-error - output={part.state.output} - status={part.state.status} + output={part().state.output} + status={part().state.status} hideDetails={props.hideDetails} - forceOpen={forceOpen()} - locked={showPermission() || showQuestion()} defaultOpen={props.defaultOpen} /> </Match> </Switch> - <Show when={showPermission() && permission()}> - <div data-component="permission-prompt"> - <div data-slot="permission-actions"> - <Button variant="ghost" size="normal" onClick={() => respond("reject")}> - {i18n.t("ui.permission.deny")} - </Button> - <Button variant="secondary" size="normal" onClick={() => respond("always")}> - {i18n.t("ui.permission.allowAlways")} - </Button> - <Button variant="primary" size="normal" onClick={() => respond("once")}> - {i18n.t("ui.permission.allowOnce")} - </Button> - </div> - </div> - </Show> - <Show when={showQuestion() && questionRequest()}>{(request) => <QuestionPrompt request={request()} />}</Show> </div> </Show> ) } +PART_MAPPING["compaction"] = function CompactionPartDisplay() { + const i18n = useI18n() + return ( + <div data-component="compaction-part"> + <div data-slot="compaction-part-divider"> + <span data-slot="compaction-part-line" /> + <span data-slot="compaction-part-label" class="text-12-regular text-text-weak"> + {i18n.t("ui.messagePart.compaction")} + </span> + <span data-slot="compaction-part-line" /> + </div> + </div> + ) +} + PART_MAPPING["text"] = function TextPartDisplay(props) { const data = useData() const i18n = useI18n() - const part = props.part as TextPart + const part = () => props.part as TextPart const interrupted = createMemo( () => props.message.role === "assistant" && (props.message as AssistantMessage).error?.name === "MessageAbortedError", @@ -1096,18 +1290,18 @@ PART_MAPPING["text"] = function TextPartDisplay(props) { return items.filter((x) => !!x).join(" \u00B7 ") }) - const displayText = () => relativizeProjectPaths((part.text ?? "").trim(), data.directory) + const displayText = () => (part().text ?? "").trim() const throttledText = createThrottledValue(displayText) const isLastTextPart = createMemo(() => { const last = (data.store.part?.[props.message.id] ?? []) .filter((item): item is TextPart => item?.type === "text" && !!item.text?.trim()) .at(-1) - return last?.id === part.id + return last?.id === part().id }) const showCopy = createMemo(() => { if (props.message.role !== "assistant") return isLastTextPart() if (props.showAssistantCopyPartID === null) return false - if (typeof props.showAssistantCopyPartID === "string") return props.showAssistantCopyPartID === part.id + if (typeof props.showAssistantCopyPartID === "string") return props.showAssistantCopyPartID === part().id return isLastTextPart() }) const [copied, setCopied] = createSignal(false) @@ -1124,7 +1318,7 @@ PART_MAPPING["text"] = function TextPartDisplay(props) { <Show when={throttledText()}> <div data-component="text-part"> <div data-slot="text-part-body"> - <Markdown text={throttledText()} cacheKey={part.id} /> + <Markdown text={throttledText()} cacheKey={part().id} /> </div> <Show when={showCopy()}> <div data-slot="text-part-copy-wrapper" data-interrupted={interrupted() ? "" : undefined}> @@ -1155,14 +1349,14 @@ PART_MAPPING["text"] = function TextPartDisplay(props) { } PART_MAPPING["reasoning"] = function ReasoningPartDisplay(props) { - const part = props.part as ReasoningPart - const text = () => part.text.trim() + const part = () => props.part as ReasoningPart + const text = () => part().text.trim() const throttledText = createThrottledValue(text) return ( <Show when={throttledText()}> <div data-component="reasoning-part"> - <Markdown text={throttledText()} cacheKey={part.id} /> + <Markdown text={throttledText()} cacheKey={part().id} /> </div> </Show> ) @@ -1198,7 +1392,7 @@ ToolRegistry.register({ <div data-component="tool-loaded-file"> <Icon name="enter" size="small" /> <span> - {i18n.t("ui.tool.loaded")} {relativizeProjectPaths(filepath, data.directory)} + {i18n.t("ui.tool.loaded")} {relativizeProjectPath(filepath, data.directory)} </span> </div> )} @@ -1219,11 +1413,9 @@ ToolRegistry.register({ trigger={{ title: i18n.t("ui.tool.list"), subtitle: getDirectory(props.input.path || "/") }} > <Show when={props.output}> - {(output) => ( - <div data-component="tool-output" data-scrollable> - <Markdown text={output()} /> - </div> - )} + <div data-component="tool-output" data-scrollable> + <Markdown text={props.output!} /> + </div> </Show> </BasicTool> ) @@ -1245,11 +1437,9 @@ ToolRegistry.register({ }} > <Show when={props.output}> - {(output) => ( - <div data-component="tool-output" data-scrollable> - <Markdown text={output()} /> - </div> - )} + <div data-component="tool-output" data-scrollable> + <Markdown text={props.output!} /> + </div> </Show> </BasicTool> ) @@ -1274,11 +1464,9 @@ ToolRegistry.register({ }} > <Show when={props.output}> - {(output) => ( - <div data-component="tool-output" data-scrollable> - <Markdown text={output()} /> - </div> - )} + <div data-component="tool-output" data-scrollable> + <Markdown text={props.output!} /> + </div> </Show> </BasicTool> ) @@ -1304,9 +1492,7 @@ ToolRegistry.register({ <div data-slot="basic-tool-tool-info-structured"> <div data-slot="basic-tool-tool-info-main"> <span data-slot="basic-tool-tool-title"> - <Show when={pending()} fallback={i18n.t("ui.tool.webfetch")}> - <TextShimmer text={i18n.t("ui.tool.webfetch")} /> - </Show> + <TextShimmer text={i18n.t("ui.tool.webfetch")} active={pending()} /> </span> <Show when={!pending() && url()}> <a @@ -1333,13 +1519,71 @@ ToolRegistry.register({ }, }) +ToolRegistry.register({ + name: "websearch", + render(props) { + const i18n = useI18n() + const query = createMemo(() => { + const value = props.input.query + if (typeof value !== "string") return "" + return value + }) + + return ( + <BasicTool + {...props} + icon="window-cursor" + trigger={{ + title: i18n.t("ui.tool.websearch"), + subtitle: query(), + subtitleClass: "exa-tool-query", + }} + > + <ExaOutput output={props.output} /> + </BasicTool> + ) + }, +}) + +ToolRegistry.register({ + name: "codesearch", + render(props) { + const i18n = useI18n() + const query = createMemo(() => { + const value = props.input.query + if (typeof value !== "string") return "" + return value + }) + + return ( + <BasicTool + {...props} + icon="code" + trigger={{ + title: i18n.t("ui.tool.codesearch"), + subtitle: query(), + subtitleClass: "exa-tool-query", + }} + > + <ExaOutput output={props.output} /> + </BasicTool> + ) + }, +}) + ToolRegistry.register({ name: "task", render(props) { const data = useData() const i18n = useI18n() + const location = useLocation() const childSessionId = () => props.metadata.sessionId as string | undefined - const title = createMemo(() => i18n.t("ui.tool.agent", { type: props.input.subagent_type || props.tool })) + const type = createMemo(() => { + const raw = props.input.subagent_type + if (typeof raw !== "string" || !raw) return undefined + return raw[0]!.toUpperCase() + raw.slice(1) + }) + const title = createMemo(() => agentTitle(i18n, type())) const description = createMemo(() => { const value = props.input.description if (typeof value === "string") return value @@ -1354,34 +1598,12 @@ ToolRegistry.register({ const direct = data.sessionHref?.(sessionId) if (direct) return direct - if (typeof window === "undefined") return - const path = window.location.pathname + const path = location.pathname const idx = path.indexOf("/session") if (idx === -1) return return `${path.slice(0, idx)}/session/${sessionId}` }) - const handleLinkClick = (e: MouseEvent) => { - const sessionId = childSessionId() - const url = href() - if (!sessionId || !url) return - - e.stopPropagation() - - if (e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return - - const nav = data.navigateToSession - if (!nav || typeof window === "undefined") return - - e.preventDefault() - const before = window.location.pathname + window.location.search + window.location.hash - nav(sessionId) - setTimeout(() => { - const after = window.location.pathname + window.location.search + window.location.hash - if (after === before) window.location.assign(url) - }, 50) - } - const titleContent = () => <TextShimmer text={title()} active={running()} /> const trigger = () => ( @@ -1393,16 +1615,14 @@ ToolRegistry.register({ <Show when={description()}> <Switch> <Match when={href()}> - {(url) => ( - <a - data-slot="basic-tool-tool-subtitle" - class="clickable subagent-link" - href={url()} - onClick={handleLinkClick} - > - {description()} - </a> - )} + <a + data-slot="basic-tool-tool-subtitle" + class="clickable subagent-link" + href={href()!} + onClick={(e) => e.stopPropagation()} + > + {description()} + </a> </Match> <Match when={true}> <span data-slot="basic-tool-tool-subtitle">{description()}</span> @@ -1421,6 +1641,8 @@ ToolRegistry.register({ name: "bash", render(props) { const i18n = useI18n() + const pending = () => props.status === "pending" || props.status === "running" + const sawPending = pending() const text = createMemo(() => { const cmd = props.input.command ?? props.metadata.command ?? "" const out = stripAnsi(props.output || props.metadata.output || "") @@ -1440,10 +1662,18 @@ ToolRegistry.register({ <BasicTool {...props} icon="console" - trigger={{ - title: i18n.t("ui.tool.shell"), - subtitle: props.input.description, - }} + trigger={ + <div data-slot="basic-tool-tool-info-structured"> + <div data-slot="basic-tool-tool-info-main"> + <span data-slot="basic-tool-tool-title"> + <TextShimmer text={i18n.t("ui.tool.shell")} active={pending()} /> + </span> + <Show when={!pending() && props.input.description}> + <ShellSubmessage text={props.input.description} animate={sawPending} /> + </Show> + </div> + </div> + } > <div data-component="bash-output"> <div data-slot="bash-copy"> @@ -1477,59 +1707,70 @@ ToolRegistry.register({ name: "edit", render(props) { const i18n = useI18n() - const diffComponent = useDiffComponent() + const fileComponent = useFileComponent() const diagnostics = createMemo(() => getDiagnostics(props.metadata.diagnostics, props.input.filePath)) + const path = createMemo(() => props.metadata?.filediff?.file || props.input.filePath || "") const filename = () => getFilename(props.input.filePath ?? "") const pending = () => props.status === "pending" || props.status === "running" return ( - <BasicTool - {...props} - icon="code-lines" - defer - trigger={ - <div data-component="edit-trigger"> - <div data-slot="message-part-title-area"> - <div data-slot="message-part-title"> - <span data-slot="message-part-title-text"> - <Show when={pending()} fallback={i18n.t("ui.messagePart.title.edit")}> - <TextShimmer text={i18n.t("ui.messagePart.title.edit")} /> + <div data-component="edit-tool"> + <BasicTool + {...props} + icon="code-lines" + defer + trigger={ + <div data-component="edit-trigger"> + <div data-slot="message-part-title-area"> + <div data-slot="message-part-title"> + <span data-slot="message-part-title-text"> + <TextShimmer text={i18n.t("ui.messagePart.title.edit")} active={pending()} /> + </span> + <Show when={!pending()}> + <span data-slot="message-part-title-filename">{filename()}</span> </Show> - </span> - <Show when={!pending()}> - <span data-slot="message-part-title-filename">{filename()}</span> + </div> + <Show when={!pending() && props.input.filePath?.includes("/")}> + <div data-slot="message-part-path"> + <span data-slot="message-part-directory">{getDirectory(props.input.filePath!)}</span> + </div> + </Show> + </div> + <div data-slot="message-part-actions"> + <Show when={!pending() && props.metadata.filediff}> + <DiffChanges changes={props.metadata.filediff} /> </Show> </div> - <Show when={!pending() && props.input.filePath?.includes("/")}> - <div data-slot="message-part-path"> - <span data-slot="message-part-directory">{getDirectory(props.input.filePath!)}</span> - </div> - </Show> </div> - <div data-slot="message-part-actions"> - <Show when={!pending() && props.metadata.filediff}> - <DiffChanges changes={props.metadata.filediff} /> - </Show> - </div> - </div> - } - > - <Show when={props.metadata.filediff?.path || props.input.filePath}> - <div data-component="edit-content"> - <Dynamic - component={diffComponent} - before={{ - name: props.metadata?.filediff?.file || props.input.filePath, - contents: props.metadata?.filediff?.before || props.input.oldString, - }} - after={{ - name: props.metadata?.filediff?.file || props.input.filePath, - contents: props.metadata?.filediff?.after || props.input.newString, - }} - /> - </div> - </Show> - <DiagnosticsDisplay diagnostics={diagnostics()} /> - </BasicTool> + } + > + <Show when={path()}> + <ToolFileAccordion + path={path()} + actions={ + <Show when={!pending() && props.metadata.filediff}> + <DiffChanges changes={props.metadata.filediff!} /> + </Show> + } + > + <div data-component="edit-content"> + <Dynamic + component={fileComponent} + mode="diff" + before={{ + name: props.metadata?.filediff?.file || props.input.filePath, + contents: props.metadata?.filediff?.before || props.input.oldString, + }} + after={{ + name: props.metadata?.filediff?.file || props.input.filePath, + contents: props.metadata?.filediff?.after || props.input.newString, + }} + /> + </div> + </ToolFileAccordion> + </Show> + <DiagnosticsDisplay diagnostics={diagnostics()} /> + </BasicTool> + </div> ) }, }) @@ -1538,53 +1779,57 @@ ToolRegistry.register({ name: "write", render(props) { const i18n = useI18n() - const codeComponent = useCodeComponent() + const fileComponent = useFileComponent() const diagnostics = createMemo(() => getDiagnostics(props.metadata.diagnostics, props.input.filePath)) + const path = createMemo(() => props.input.filePath || "") const filename = () => getFilename(props.input.filePath ?? "") const pending = () => props.status === "pending" || props.status === "running" return ( - <BasicTool - {...props} - icon="code-lines" - defer - trigger={ - <div data-component="write-trigger"> - <div data-slot="message-part-title-area"> - <div data-slot="message-part-title"> - <span data-slot="message-part-title-text"> - <Show when={pending()} fallback={i18n.t("ui.messagePart.title.write")}> - <TextShimmer text={i18n.t("ui.messagePart.title.write")} /> + <div data-component="write-tool"> + <BasicTool + {...props} + icon="code-lines" + defer + trigger={ + <div data-component="write-trigger"> + <div data-slot="message-part-title-area"> + <div data-slot="message-part-title"> + <span data-slot="message-part-title-text"> + <TextShimmer text={i18n.t("ui.messagePart.title.write")} active={pending()} /> + </span> + <Show when={!pending()}> + <span data-slot="message-part-title-filename">{filename()}</span> </Show> - </span> - <Show when={!pending()}> - <span data-slot="message-part-title-filename">{filename()}</span> + </div> + <Show when={!pending() && props.input.filePath?.includes("/")}> + <div data-slot="message-part-path"> + <span data-slot="message-part-directory">{getDirectory(props.input.filePath!)}</span> + </div> </Show> </div> - <Show when={!pending() && props.input.filePath?.includes("/")}> - <div data-slot="message-part-path"> - <span data-slot="message-part-directory">{getDirectory(props.input.filePath!)}</span> - </div> - </Show> + <div data-slot="message-part-actions">{/* <DiffChanges diff={diff} /> */}</div> </div> - <div data-slot="message-part-actions">{/* <DiffChanges diff={diff} /> */}</div> - </div> - } - > - <Show when={props.input.content}> - <div data-component="write-content"> - <Dynamic - component={codeComponent} - file={{ - name: props.input.filePath, - contents: props.input.content, - cacheKey: checksum(props.input.content), - }} - overflow="scroll" - /> - </div> - </Show> - <DiagnosticsDisplay diagnostics={diagnostics()} /> - </BasicTool> + } + > + <Show when={props.input.content && path()}> + <ToolFileAccordion path={path()}> + <div data-component="write-content"> + <Dynamic + component={fileComponent} + mode="text" + file={{ + name: props.input.filePath, + contents: props.input.content, + cacheKey: checksum(props.input.content), + }} + overflow="scroll" + /> + </div> + </ToolFileAccordion> + </Show> + <DiagnosticsDisplay diagnostics={diagnostics()} /> + </BasicTool> + </div> ) }, }) @@ -1605,7 +1850,7 @@ ToolRegistry.register({ name: "apply_patch", render(props) { const i18n = useI18n() - const diffComponent = useDiffComponent() + const fileComponent = useFileComponent() const files = createMemo(() => (props.metadata.files ?? []) as ApplyPatchFile[]) const pending = createMemo(() => props.status === "pending" || props.status === "running") const single = createMemo(() => { @@ -1713,7 +1958,8 @@ ToolRegistry.register({ <Show when={visible()}> <div data-component="apply-patch-file-diff"> <Dynamic - component={diffComponent} + component={fileComponent} + mode="diff" before={{ name: file.filePath, contents: file.before }} after={{ name: file.movePath ?? file.filePath, contents: file.after }} /> @@ -1730,7 +1976,7 @@ ToolRegistry.register({ </div> } > - {(file) => ( + <div data-component="apply-patch-tool"> <BasicTool {...props} icon="code-lines" @@ -1740,37 +1986,62 @@ ToolRegistry.register({ <div data-slot="message-part-title-area"> <div data-slot="message-part-title"> <span data-slot="message-part-title-text"> - <Show when={pending()} fallback={i18n.t("ui.tool.patch")}> - <TextShimmer text={i18n.t("ui.tool.patch")} /> - </Show> + <TextShimmer text={i18n.t("ui.tool.patch")} active={pending()} /> </span> <Show when={!pending()}> - <span data-slot="message-part-title-filename">{getFilename(file().relativePath)}</span> + <span data-slot="message-part-title-filename">{getFilename(single()!.relativePath)}</span> </Show> </div> - <Show when={!pending() && file().relativePath.includes("/")}> + <Show when={!pending() && single()!.relativePath.includes("/")}> <div data-slot="message-part-path"> - <span data-slot="message-part-directory">{getDirectory(file().relativePath)}</span> + <span data-slot="message-part-directory">{getDirectory(single()!.relativePath)}</span> </div> </Show> </div> <div data-slot="message-part-actions"> <Show when={!pending()}> - <DiffChanges changes={{ additions: file().additions, deletions: file().deletions }} /> + <DiffChanges changes={{ additions: single()!.additions, deletions: single()!.deletions }} /> </Show> </div> </div> } > - <div data-component="edit-content"> - <Dynamic - component={diffComponent} - before={{ name: file().filePath, contents: file().before }} - after={{ name: file().movePath ?? file().filePath, contents: file().after }} - /> - </div> + <ToolFileAccordion + path={single()!.relativePath} + actions={ + <Switch> + <Match when={single()!.type === "add"}> + <span data-slot="apply-patch-change" data-type="added"> + {i18n.t("ui.patch.action.created")} + </span> + </Match> + <Match when={single()!.type === "delete"}> + <span data-slot="apply-patch-change" data-type="removed"> + {i18n.t("ui.patch.action.deleted")} + </span> + </Match> + <Match when={single()!.type === "move"}> + <span data-slot="apply-patch-change" data-type="modified"> + {i18n.t("ui.patch.action.moved")} + </span> + </Match> + <Match when={true}> + <DiffChanges changes={{ additions: single()!.additions, deletions: single()!.deletions }} /> + </Match> + </Switch> + } + > + <div data-component="apply-patch-file-diff"> + <Dynamic + component={fileComponent} + mode="diff" + before={{ name: single()!.filePath, contents: single()!.before }} + after={{ name: single()!.movePath ?? single()!.filePath, contents: single()!.after }} + /> + </div> + </ToolFileAccordion> </BasicTool> - )} + </div> </Show> ) }, @@ -1872,244 +2143,24 @@ ToolRegistry.register({ }, }) -function QuestionPrompt(props: { request: QuestionRequest }) { - const data = useData() - const i18n = useI18n() - const questions = createMemo(() => props.request.questions) - const single = createMemo(() => questions().length === 1 && questions()[0]?.multiple !== true) +ToolRegistry.register({ + name: "skill", + render(props) { + const title = createMemo(() => props.input.name || "skill") + const running = createMemo(() => props.status === "pending" || props.status === "running") - const [store, setStore] = createStore({ - tab: 0, - answers: [] as QuestionAnswer[], - custom: [] as string[], - editing: false, - }) + const titleContent = () => <TextShimmer text={title()} active={running()} /> - const question = createMemo(() => questions()[store.tab]) - const confirm = createMemo(() => !single() && store.tab === questions().length) - const options = createMemo(() => question()?.options ?? []) - const input = createMemo(() => store.custom[store.tab] ?? "") - const multi = createMemo(() => question()?.multiple === true) - const customPicked = createMemo(() => { - const value = input() - if (!value) return false - return store.answers[store.tab]?.includes(value) ?? false - }) - - function submit() { - const answers = questions().map((_, i) => store.answers[i] ?? []) - data.replyToQuestion?.({ - requestID: props.request.id, - answers, - }) - } - - function reject() { - data.rejectQuestion?.({ - requestID: props.request.id, - }) - } - - function pick(answer: string, custom: boolean = false) { - const answers = [...store.answers] - answers[store.tab] = [answer] - setStore("answers", answers) - if (custom) { - const inputs = [...store.custom] - inputs[store.tab] = answer - setStore("custom", inputs) - } - if (single()) { - data.replyToQuestion?.({ - requestID: props.request.id, - answers: [[answer]], - }) - return - } - setStore("tab", store.tab + 1) - } - - function toggle(answer: string) { - const existing = store.answers[store.tab] ?? [] - const next = [...existing] - const index = next.indexOf(answer) - if (index === -1) next.push(answer) - if (index !== -1) next.splice(index, 1) - const answers = [...store.answers] - answers[store.tab] = next - setStore("answers", answers) - } - - function selectTab(index: number) { - setStore("tab", index) - setStore("editing", false) - } - - function selectOption(optIndex: number) { - if (optIndex === options().length) { - setStore("editing", true) - return - } - const opt = options()[optIndex] - if (!opt) return - if (multi()) { - toggle(opt.label) - return - } - pick(opt.label) - } - - function handleCustomSubmit(e: Event) { - e.preventDefault() - const value = input().trim() - if (!value) { - setStore("editing", false) - return - } - if (multi()) { - const existing = store.answers[store.tab] ?? [] - const next = [...existing] - if (!next.includes(value)) next.push(value) - const answers = [...store.answers] - answers[store.tab] = next - setStore("answers", answers) - setStore("editing", false) - return - } - pick(value, true) - setStore("editing", false) - } - - return ( - <div data-component="question-prompt"> - <Show when={!single()}> - <div data-slot="question-tabs"> - <For each={questions()}> - {(q, index) => { - const active = () => index() === store.tab - const answered = () => (store.answers[index()]?.length ?? 0) > 0 - return ( - <button - data-slot="question-tab" - data-active={active()} - data-answered={answered()} - onClick={() => selectTab(index())} - > - {q.header} - </button> - ) - }} - </For> - <button data-slot="question-tab" data-active={confirm()} onClick={() => selectTab(questions().length)}> - {i18n.t("ui.common.confirm")} - </button> + const trigger = () => ( + <div data-slot="basic-tool-tool-info-structured"> + <div data-slot="basic-tool-tool-info-main"> + <span data-slot="basic-tool-tool-title" class="capitalize agent-title"> + {titleContent()} + </span> </div> - </Show> - - <Show when={!confirm()}> - <div data-slot="question-content"> - <div data-slot="question-text"> - {question()?.question} - {multi() ? " " + i18n.t("ui.question.multiHint") : ""} - </div> - <div data-slot="question-options"> - <For each={options()}> - {(opt, i) => { - const picked = () => store.answers[store.tab]?.includes(opt.label) ?? false - return ( - <button data-slot="question-option" data-picked={picked()} onClick={() => selectOption(i())}> - <span data-slot="option-label">{opt.label}</span> - <Show when={opt.description}> - <span data-slot="option-description">{opt.description}</span> - </Show> - <Show when={picked()}> - <Icon name="check-small" size="normal" /> - </Show> - </button> - ) - }} - </For> - <button - data-slot="question-option" - data-picked={customPicked()} - onClick={() => selectOption(options().length)} - > - <span data-slot="option-label">{i18n.t("ui.messagePart.option.typeOwnAnswer")}</span> - <Show when={!store.editing && input()}> - <span data-slot="option-description">{input()}</span> - </Show> - <Show when={customPicked()}> - <Icon name="check-small" size="normal" /> - </Show> - </button> - <Show when={store.editing}> - <form data-slot="custom-input-form" onSubmit={handleCustomSubmit}> - <input - ref={(el) => setTimeout(() => el.focus(), 0)} - type="text" - data-slot="custom-input" - placeholder={i18n.t("ui.question.custom.placeholder")} - value={input()} - onInput={(e) => { - const inputs = [...store.custom] - inputs[store.tab] = e.currentTarget.value - setStore("custom", inputs) - }} - /> - <Button type="submit" variant="primary" size="small"> - {multi() ? i18n.t("ui.common.add") : i18n.t("ui.common.submit")} - </Button> - <Button type="button" variant="ghost" size="small" onClick={() => setStore("editing", false)}> - {i18n.t("ui.common.cancel")} - </Button> - </form> - </Show> - </div> - </div> - </Show> - - <Show when={confirm()}> - <div data-slot="question-review"> - <div data-slot="review-title">{i18n.t("ui.messagePart.review.title")}</div> - <For each={questions()}> - {(q, index) => { - const value = () => store.answers[index()]?.join(", ") ?? "" - const answered = () => Boolean(value()) - return ( - <div data-slot="review-item"> - <span data-slot="review-label">{q.question}</span> - <span data-slot="review-value" data-answered={answered()}> - {answered() ? value() : i18n.t("ui.question.review.notAnswered")} - </span> - </div> - ) - }} - </For> - </div> - </Show> - - <div data-slot="question-actions"> - <Button variant="ghost" size="small" onClick={reject}> - {i18n.t("ui.common.dismiss")} - </Button> - <Show when={!single()}> - <Show when={confirm()}> - <Button variant="primary" size="small" onClick={submit}> - {i18n.t("ui.common.submit")} - </Button> - </Show> - <Show when={!confirm() && multi()}> - <Button - variant="secondary" - size="small" - onClick={() => selectTab(store.tab + 1)} - disabled={(store.answers[store.tab]?.length ?? 0) === 0} - > - {i18n.t("ui.common.next")} - </Button> - </Show> - </Show> </div> - </div> - ) -} + ) + + return <BasicTool icon="brain" status={props.status} trigger={trigger()} hideDetails /> + }, +}) diff --git a/packages/ui/src/components/motion-spring.tsx b/packages/ui/src/components/motion-spring.tsx new file mode 100644 index 0000000000..a5104a1a3e --- /dev/null +++ b/packages/ui/src/components/motion-spring.tsx @@ -0,0 +1,45 @@ +import { attachSpring, motionValue } from "motion" +import type { SpringOptions } from "motion" +import { createEffect, createSignal, onCleanup } from "solid-js" + +type Opt = Partial<Pick<SpringOptions, "visualDuration" | "bounce" | "stiffness" | "damping" | "mass" | "velocity">> +const eq = (a: Opt | undefined, b: Opt | undefined) => + a?.visualDuration === b?.visualDuration && + a?.bounce === b?.bounce && + a?.stiffness === b?.stiffness && + a?.damping === b?.damping && + a?.mass === b?.mass && + a?.velocity === b?.velocity + +export function useSpring(target: () => number, options?: Opt | (() => Opt)) { + const read = () => (typeof options === "function" ? options() : options) + const [value, setValue] = createSignal(target()) + const source = motionValue(value()) + const spring = motionValue(value()) + let config = read() + let stop = attachSpring(spring, source, config) + let off = spring.on("change", (next: number) => setValue(next)) + + createEffect(() => { + source.set(target()) + }) + + createEffect(() => { + if (!options) return + const next = read() + if (eq(config, next)) return + config = next + stop() + stop = attachSpring(spring, source, next) + setValue(spring.get()) + }) + + onCleanup(() => { + off() + stop() + spring.destroy() + source.destroy() + }) + + return value +} diff --git a/packages/ui/src/components/popover.stories.tsx b/packages/ui/src/components/popover.stories.tsx new file mode 100644 index 0000000000..e5117b451b --- /dev/null +++ b/packages/ui/src/components/popover.stories.tsx @@ -0,0 +1,87 @@ +// @ts-nocheck +import { createSignal } from "solid-js" +import * as mod from "./popover" +import { create } from "../storybook/scaffold" + +const docs = `### Overview +Composable popover with optional title, description, and close button. + +Use for small contextual details; avoid long forms. + +### API +- \`trigger\` and \`children\` define the anchor and content. +- Optional: \`title\`, \`description\`, \`portal\`, \`open\`, \`defaultOpen\`. + +### Variants and states +- Supports controlled and uncontrolled open state. + +### Behavior +- Closes on outside click or Escape by default. + +### Accessibility +- TODO: confirm focus management from Kobalte. + +### Theming/tokens +- Uses \`data-component="popover-content"\` and related slots. + +` + +const story = create({ + title: "UI/Popover", + mod, + args: { + trigger: "Open popover", + title: "Popover", + description: "Optional description", + defaultOpen: true, + children: "Popover content", + }, +}) + +export default { + title: "UI/Popover", + id: "components-popover", + component: story.meta.component, + tags: ["autodocs"], + parameters: { + docs: { + description: { + component: docs, + }, + }, + }, +} + +export const Basic = story.Basic + +export const NoHeader = { + args: { + title: undefined, + description: undefined, + children: "Popover body only", + }, +} + +export const Inline = { + args: { + portal: false, + defaultOpen: true, + }, +} + +export const Controlled = { + render: () => { + const [open, setOpen] = createSignal(true) + return ( + <mod.Popover + open={open()} + onOpenChange={setOpen} + trigger="Toggle popover" + title="Controlled" + description="Open state is controlled" + > + Controlled content + </mod.Popover> + ) + }, +} diff --git a/packages/ui/src/components/progress-circle.stories.tsx b/packages/ui/src/components/progress-circle.stories.tsx new file mode 100644 index 0000000000..5bc23c3108 --- /dev/null +++ b/packages/ui/src/components/progress-circle.stories.tsx @@ -0,0 +1,59 @@ +// @ts-nocheck +import * as mod from "./progress-circle" +import { create } from "../storybook/scaffold" + +const docs = `### Overview +Circular progress indicator for compact loading states. + +Pair with labels for clarity in dashboards. + +### API +- Required: \`percentage\` (0-100). +- Optional: \`size\`, \`strokeWidth\`. + +### Variants and states +- Single visual style; size and stroke width adjust appearance. + +### Behavior +- Percentage is clamped between 0 and 100. + +### Accessibility +- Use alongside text or aria-live messaging for progress context. + +### Theming/tokens +- Uses \`data-component="progress-circle"\` with background/progress slots. + +` + +const story = create({ title: "UI/ProgressCircle", mod, args: { percentage: 65, size: 48 } }) + +export default { + title: "UI/ProgressCircle", + id: "components-progress-circle", + component: story.meta.component, + tags: ["autodocs"], + parameters: { + docs: { + description: { + component: docs, + }, + }, + }, + argTypes: { + percentage: { + control: { type: "range", min: 0, max: 100, step: 1 }, + }, + }, +} + +export const Basic = story.Basic + +export const States = { + render: () => ( + <div style={{ display: "flex", gap: "16px", "align-items": "center" }}> + <mod.ProgressCircle percentage={0} size={32} /> + <mod.ProgressCircle percentage={50} size={32} /> + <mod.ProgressCircle percentage={100} size={32} /> + </div> + ), +} diff --git a/packages/ui/src/components/progress.stories.tsx b/packages/ui/src/components/progress.stories.tsx new file mode 100644 index 0000000000..2ee3223434 --- /dev/null +++ b/packages/ui/src/components/progress.stories.tsx @@ -0,0 +1,67 @@ +// @ts-nocheck +import * as mod from "./progress" +import { create } from "../storybook/scaffold" + +const docs = `### Overview +Linear progress indicator with optional label and value display. + +Use in forms, uploads, or background tasks. + +### API +- \`value\` and \`maxValue\` control progress. +- Optional: \`showValueLabel\`, \`hideLabel\`. +- Children provide the label text. + +### Variants and states +- Supports indeterminate state via Kobalte props (if provided). + +### Behavior +- Uses Kobalte Progress for value calculation. + +### Accessibility +- TODO: confirm ARIA attributes from Kobalte. + +### Theming/tokens +- Uses \`data-component="progress"\` with track/fill slots. + +` + +const story = create({ + title: "UI/Progress", + mod, + args: { + value: 60, + maxValue: 100, + children: "Progress", + showValueLabel: true, + }, +}) + +export default { + title: "UI/Progress", + id: "components-progress", + component: story.meta.component, + tags: ["autodocs"], + parameters: { + docs: { + description: { + component: docs, + }, + }, + }, +} + +export const Basic = story.Basic + +export const NoLabel = { + args: { + children: "", + hideLabel: true, + showValueLabel: false, + value: 30, + }, +} + +export const Indeterminate = { + render: () => <mod.Progress>Loading</mod.Progress>, +} diff --git a/packages/ui/src/components/provider-icon.stories.tsx b/packages/ui/src/components/provider-icon.stories.tsx new file mode 100644 index 0000000000..e7fc39967b --- /dev/null +++ b/packages/ui/src/components/provider-icon.stories.tsx @@ -0,0 +1,69 @@ +// @ts-nocheck +import { iconNames } from "./provider-icons/types" +import * as mod from "./provider-icon" +import { create } from "../storybook/scaffold" + +const docs = `### Overview +Provider icon sprite renderer for model/provider badges. + +Use in model pickers or provider lists. + +### API +- Required: \`id\` (provider icon name). +- Accepts standard SVG props. + +### Variants and states +- Single visual style; size via CSS. + +### Behavior +- Renders from the provider SVG sprite sheet. + +### Accessibility +- Provide accessible text nearby when the icon conveys meaning. + +### Theming/tokens +- Uses \`data-component="provider-icon"\`. + +` + +const story = create({ title: "UI/ProviderIcon", mod, args: { id: "openai" } }) +export default { + title: "UI/ProviderIcon", + id: "components-provider-icon", + component: story.meta.component, + tags: ["autodocs"], + parameters: { + docs: { + description: { + component: docs, + }, + }, + }, + argTypes: { + id: { + control: "select", + options: iconNames, + }, + }, +} + +export const Basic = story.Basic + +export const AllIcons = { + render: () => ( + <div + style={{ + display: "grid", + gap: "12px", + "grid-template-columns": "repeat(auto-fill, minmax(80px, 1fr))", + }} + > + {iconNames.map((id) => ( + <div style={{ display: "grid", gap: "6px", "justify-items": "center" }}> + <mod.ProviderIcon id={id} width="28" height="28" aria-label={id} /> + <div style={{ "font-size": "10px", color: "var(--text-weak)", "text-align": "center" }}>{id}</div> + </div> + ))} + </div> + ), +} diff --git a/packages/ui/src/components/provider-icon.tsx b/packages/ui/src/components/provider-icon.tsx index d653765a55..edfdd03571 100644 --- a/packages/ui/src/components/provider-icon.tsx +++ b/packages/ui/src/components/provider-icon.tsx @@ -1,14 +1,15 @@ import type { Component, JSX } from "solid-js" -import { splitProps } from "solid-js" +import { createMemo, splitProps } from "solid-js" import sprite from "./provider-icons/sprite.svg" -import type { IconName } from "./provider-icons/types" +import { iconNames, type IconName } from "./provider-icons/types" export type ProviderIconProps = JSX.SVGElementTags["svg"] & { - id: IconName + id: string } export const ProviderIcon: Component<ProviderIconProps> = (props) => { const [local, rest] = splitProps(props, ["id", "class", "classList"]) + const resolved = createMemo(() => (iconNames.includes(local.id as IconName) ? local.id : "synthetic")) return ( <svg data-component="provider-icon" @@ -18,7 +19,7 @@ export const ProviderIcon: Component<ProviderIconProps> = (props) => { [local.class ?? ""]: !!local.class, }} > - <use href={`${sprite}#${local.id}`} /> + <use href={`${sprite}#${resolved()}`} /> </svg> ) } diff --git a/packages/ui/src/components/provider-icons/sprite.svg b/packages/ui/src/components/provider-icons/sprite.svg index 88406fa8c3..a0214b40d0 100644 --- a/packages/ui/src/components/provider-icons/sprite.svg +++ b/packages/ui/src/components/provider-icons/sprite.svg @@ -87,6 +87,18 @@ fill="currentColor" ></path> </symbol> + <symbol viewBox="0 0 24 24" fill="none" id="vivgrid"> + <path + d="M 10.921 1.266 C 11.477 0.952 12.161 0.952 12.717 1.266 L 14.079 2.037 C 12.108 3.127 9.934 4.437 8.274 5.788 C 7.425 6.479 6.706 7.185 6.216 7.879 C 5.727 8.574 5.458 9.268 5.53 9.935 C 5.625 10.839 6.133 11.432 6.825 11.858 C 7.512 12.283 8.388 12.55 9.232 12.809 C 9.968 13.033 10.681 13.253 11.245 13.56 C 11.808 13.868 12.214 14.257 12.353 14.819 C 12.492 15.384 12.369 16.145 11.825 17.206 C 11.286 18.255 10.342 19.586 8.861 21.293 L 2.91 17.924 C 2.356 17.608 2.013 17.028 2.013 16.398 L 2.013 7.327 C 2.013 6.697 2.356 6.116 2.91 5.802 L 10.921 1.266 Z" + fill="currentColor" + stroke="currentColor" + ></path> + <path + d="M 21.122 6.009 C 21.677 6.324 22.019 6.904 22.019 7.534 L 22.019 16.606 C 22.019 17.235 21.677 17.816 21.122 18.131 L 13.11 22.667 C 12.555 22.981 11.872 22.981 11.314 22.667 L 10.388 22.142 C 10.772 21.78 11.159 21.413 11.55 21.047 C 12.722 19.945 13.901 18.834 14.928 17.765 C 15.953 16.698 16.825 15.667 17.382 14.721 C 17.936 13.778 18.187 12.902 17.93 12.154 C 17.671 11.401 16.913 10.813 15.54 10.415 C 13.986 9.966 12.92 9.457 12.272 8.908 C 11.628 8.362 11.403 7.78 11.507 7.17 C 11.617 6.55 12.069 5.883 12.824 5.18 C 13.572 4.488 14.606 3.77 15.874 3.039 L 21.122 6.009 Z" + fill="currentColor" + stroke="currentColor" + ></path> + </symbol> <symbol viewBox="0 0 40 40" id="vercel"> <path d="M35.5 33.5949H4.5L20 6.40511L35.5 33.5949Z" fill="currentColor"></path> </symbol> @@ -175,6 +187,36 @@ fill="currentColor" ></path> </symbol> + <symbol viewBox="0 0 24 24" fill="none" id="stepfun"> + <path + shape-rendering="geometricPrecision" + d="M9.8132 15.9038L9 18.75L8.1868 15.9038C7.75968 14.4089 6.59112 13.2403 5.09619 12.8132L2.25 12L5.09619 11.1868C6.59113 10.7597 7.75968 9.59112 8.1868 8.09619L9 5.25L9.8132 8.09619C10.2403 9.59113 11.4089 10.7597 12.9038 11.1868L15.75 12L12.9038 12.8132C11.4089 13.2403 10.2403 14.4089 9.8132 15.9038Z" + stroke="currentColor" + stroke-width="1.5" + stroke-linecap="round" + stroke-linejoin="round" + ></path> + <path + d="M18.2589 8.71454L18 9.75L17.7411 8.71454C17.4388 7.50533 16.4947 6.56117 15.2855 6.25887L14.25 6L15.2855 5.74113C16.4947 5.43883 17.4388 4.49467 17.7411 3.28546L18 2.25L18.2589 3.28546C18.5612 4.49467 19.5053 5.43883 20.7145 5.74113L21.75 6L20.7145 6.25887C19.5053 6.56117 18.5612 7.50533 18.2589 8.71454Z" + stroke="currentColor" + stroke-width="1.5" + stroke-linecap="round" + stroke-linejoin="round" + ></path> + <path + d="M16.8942 20.5673L16.5 21.75L16.1058 20.5673C15.8818 19.8954 15.3546 19.3682 14.6827 19.1442L13.5 18.75L14.6827 18.3558C15.3546 18.1318 15.8818 17.6046 16.1058 16.9327L16.5 15.75L16.8942 16.9327C17.1182 17.6046 17.6454 18.1318 18.3173 18.3558L19.5 18.75L18.3173 19.1442C17.6454 19.3682 17.1182 19.8954 16.8942 20.5673Z" + stroke="currentColor" + stroke-width="1.5" + stroke-linecap="round" + stroke-linejoin="round" + ></path> + </symbol> + <symbol id="stackit" viewBox="0 0 41.536063 41.536063"> + <path + d="M13.9510149,10.4421038h20.8374634l-1.1608887,5.4412842h-14.5545654l-1.3522339,6.3352661h-6.2828369l2.5130615-11.7765503ZM22.5114397,25.652614H7.9081072l-1.1605225,5.4413452h20.8855591l2.5210571-11.8130493h-6.2828979l-1.3598633,6.3717041Z" + fill="currentColor" + ></path> + </symbol> <symbol viewBox="0 0 40 40" id="siliconflow"> <path d="M34.1033 12.3605H20.6227C19.8778 12.3605 19.2764 12.9839 19.2764 13.7501V17.9223C19.2764 18.2909 19.1346 18.6451 18.8823 18.9058C18.6292 19.1658 18.2869 19.3127 17.9293 19.3118H5.7933C5.04839 19.3118 4.44703 19.9353 4.44703 20.7014V26.2658C4.44618 26.6344 4.58887 26.9886 4.84114 27.2485C5.09341 27.5093 5.43656 27.6562 5.7933 27.6562H19.273C19.6306 27.6562 19.9729 27.5093 20.226 27.2485C20.4783 26.9886 20.6202 26.6344 20.6202 26.2658V22.0944C20.6193 21.7258 20.7612 21.3716 21.0143 21.1108C21.2665 20.8501 21.6097 20.704 21.9673 20.7048H34.0999C34.8457 20.7048 35.447 20.0805 35.447 19.3152V13.7501C35.447 12.9814 34.8423 12.3605 34.0999 12.3605H34.1033Z" @@ -251,6 +293,37 @@ stroke-linejoin="round" ></path> </symbol> + <symbol viewBox="0 0 24 24" id="qiniu-ai"> + <g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> + <g fill="currentColor" fill-rule="nonzero"> + <path + d="M23.568,4.37284513 C23.180619,4.24052218 22.8592977,4.40224993 22.6756964,4.54008596 C20.1236928,7.55961616 16.310265,9.47645197 12.0489207,9.47645197 C10.5856349,9.47645197 9.17375432,9.25040654 7.84814258,8.82954254 C7.5029753,7.57615888 7.25878488,6.68481809 7.25878488,6.68481809 C7.25878488,6.68481809 6.97237307,5.81185554 6.00112785,5.96071698 L6.28019714,8.22306831 C4.39829587,7.36296976 2.74038351,6.09854994 1.42029592,4.53641031 C1.23669698,4.39857428 0.915396329,4.23684654 0.528,4.36916956 C1.62959981,7.32069904 3.8328071,9.73559053 6.63638202,11.1121076 L7.40015707,17.309184 C7.40015707,17.309184 7.74165693,19.68 9.96508874,19.68 L14.7184659,19.68 C16.9418594,19.68 17.2833592,17.309184 17.2833592,17.309184 L17.8212733,12.8690689 C16.3782427,12.7514113 15.4693667,13.7585665 15.1829548,14.7509761 C14.7001288,16.4233728 14.7001288,16.5318144 14.6046071,16.8221952 C14.4100343,17.4194688 13.7692329,17.4912 13.7692329,17.4912 L10.9179278,17.4912 C10.9179278,17.4912 10.2772032,17.4194688 10.0825536,16.8221952 C9.95772321,16.4381184 9.32981155,14.1868033 8.69821712,11.9023719 C9.76307366,12.2037505 10.8885424,12.3654913 12.0507621,12.3654913 C17.3237162,12.3710209 21.8219851,9.04456718 23.568,4.37284513 Z" + ></path> + </g> + </g> + </symbol> + <symbol viewBox="0 0 40 40" fill="none" id="qihang-ai"> + <path + d="M20 2L36.4 11V29L20 38L3.6 29V11L20 2Z M20 20V2 M20 20L36.4 11 M20 20L36.4 29 M20 20V38 M20 20L3.6 29 M20 20L3.6 11" + stroke="currentColor" + stroke-width="3" + stroke-linecap="round" + stroke-linejoin="round" + ></path> + </symbol> + <symbol viewBox="0 0 61 63" fill="none" id="privatemode-ai"> + <path + d="M13.2167 6.71884C13.2167 10.4296 10.258 13.4377 6.60833 13.4377C2.95865 13.4377 0 10.4296 0 6.71884C0 3.00813 2.95865 0 6.60833 0C10.258 0 13.2167 3.00813 13.2167 6.71884Z" + fill="currentColor" + ></path> + <path d="M16.2667 22.7407H28.4667V62.0201H16.2667V22.7407Z" fill="currentColor"></path> + <path + fill-rule="evenodd" + clip-rule="evenodd" + d="M38.6333 33.0774C44.2482 33.0774 48.8 28.4495 48.8 22.7407C48.8 17.0319 44.2482 12.404 38.6333 12.404C33.0184 12.404 28.4667 17.0319 28.4667 22.7407C28.4667 28.4495 33.0184 33.0774 38.6333 33.0774ZM38.6333 45.4814C50.9861 45.4814 61 35.3 61 22.7407C61 10.1814 50.9861 0 38.6333 0C26.2806 0 16.2667 10.1814 16.2667 22.7407C16.2667 35.3 26.2806 45.4814 38.6333 45.4814Z" + fill="currentColor" + ></path> + </symbol> <symbol viewBox="0 0 40 40" id="poe"> <path d="M31.4739 11.8771C31.0962 11.4991 30.5979 11.3159 30.1031 11.3246L30.0936 11.3248C28.6012 11.3248 27.4017 10.115 27.4017 8.62262V8.62092C27.407 8.12944 27.2234 7.63665 26.8488 7.26144C26.485 6.89774 26.0103 6.714 25.5339 6.70853L10.3566 6.70834C9.87999 6.714 9.40529 6.89774 9.04177 7.26126C8.66693 7.63608 8.48319 8.12926 8.48885 8.62054L8.4883 8.61998C8.4883 10.1125 7.27826 11.3225 5.78592 11.3225L5.78781 11.3246C5.29275 11.3158 4.79487 11.4991 4.41684 11.8771C4.04672 12.2473 3.86223 12.7325 3.86279 13.2176V18.0722C3.86223 18.5573 4.04672 19.0422 4.41665 19.4123C4.79468 19.7903 5.29256 19.9735 5.78762 19.9648H5.78913C7.27844 19.9648 8.48359 21.1694 8.48867 22.6576V27.585C8.48867 28.2139 9.28073 28.4918 9.67383 28.0007L12.4096 24.5809L25.5347 24.5807C26.0113 24.5751 26.4858 24.3913 26.8495 24.0278C27.2243 23.653 27.4081 23.1598 27.4024 22.6685V22.6657C27.4024 21.1732 28.6072 19.9647 30.1002 19.9647H30.1036C30.5984 19.9735 31.0967 19.7901 31.4744 19.4121C31.8446 19.042 32.0293 18.5568 32.0285 18.072V13.2178C32.0287 12.7325 31.8438 12.2473 31.4739 11.8771ZM28.2471 18.1246C28.2314 19.604 27.0289 20.7983 25.546 20.7983H10.3445C8.86162 20.7983 7.65912 19.6036 7.64348 18.1246C7.64385 18.1071 7.64385 13.1827 7.64348 13.165C7.65912 11.6857 8.86162 10.4913 10.3445 10.4913L10.3428 10.4896C10.3474 10.4896 10.3519 10.4902 10.3566 10.4902V10.4913H25.5458C27.0287 10.4913 28.2314 11.6861 28.2469 13.1652C28.2465 13.1827 28.2467 18.1071 28.2471 18.1246Z" @@ -325,12 +398,13 @@ </symbol> <symbol viewBox="0 0 24 24" fill="none" id="opencode"> <path - opacity="0.2" - d="M19.2002 17.4H8.40017V13.8H15.6002V10.2H19.2002V17.4ZM8.40017 13.8H4.80017V10.2H8.40017V13.8Z" + d="M8.40005 17.4H19.2001V21H4.80005V13.8H8.40005V17.4ZM15.6001 10.2V13.8H8.40005V10.2H15.6001ZM19.2001 10.2H15.6001V6.6H4.80005V3H19.2001V10.2Z" fill="currentColor" ></path> + </symbol> + <symbol viewBox="0 0 24 24" fill="none" id="opencode-go"> <path - d="M8.40005 17.4H19.2001V21H4.80005V13.8H8.40005V17.4ZM15.6001 10.2V13.8H8.40005V10.2H15.6001ZM19.2001 10.2H15.6001V6.6H4.80005V3H19.2001V10.2Z" + d="M19.4004 21H5V3H19.4004V6.59961H8.59961V17.4004H15.7998V13.7998H12.2002V10.2002H19.4004V21Z" fill="currentColor" ></path> </symbol> @@ -372,6 +446,24 @@ fill="currentColor" ></path> </symbol> + <symbol viewBox="0 0 40 40" fill="none" id="novita-ai"> + <g clip-path="url(#clip0_3135_1230)"> + <path + d="M15.5564 8.26172V16.5239L2.1875 29.8928H15.5564V21.6302L23.8194 29.8928H37.1875L15.5564 8.26172Z" + fill="black" + ></path> + </g> + <defs> + <clipPath id="clip0_3135_1230"> + <rect width="35" height="21.6311" fill="white" transform="translate(2.1875 8.26172)"></rect> + </clipPath> + </defs> + </symbol> + <symbol viewBox="0 0 24 24" fill="currentColor" id="nova"> + <path + d="M13.48 17.46L14.64 18.62C14.69 18.67 14.71 18.75 14.68 18.82L12.87 23.41C12.73 23.76 12.38 24 12 24C11.62 24 11.27 23.76 11.13 23.41L8.52 16.80L4.31 21.02C4.24 21.09 4.12 21.09 4.05 21.02L2.98 19.95C2.91 19.88 2.91 19.76 2.98 19.69L8.18 14.49C8.35 14.32 8.58 14.21 8.81 14.19C9.23 14.17 9.60 14.42 9.74 14.78L12.00 20.51L13.18 17.52C13.23 17.40 13.39 17.37 13.49 17.46H13.48ZM19.69 2.98L15.48 7.20L12.87 0.59C12.71 0.17 12.26 -0.08 11.79 0.02C11.48 0.09 11.23 0.33 11.12 0.63L9.32 5.18C9.29 5.25 9.31 5.33 9.36 5.38L10.52 6.54C10.61 6.63 10.77 6.60 10.82 6.47L12 3.49L14.26 9.21C14.37 9.51 14.63 9.72 14.94 9.79C15.00 9.80 15.07 9.81 15.13 9.81C15.38 9.81 15.62 9.71 15.79 9.53L21.02 4.31C21.09 4.24 21.09 4.12 21.02 4.04L19.96 2.98C19.88 2.91 19.76 2.91 19.69 2.98L19.69 2.98ZM6.47 13.17L3.49 12.00L9.21 9.74C9.58 9.59 9.83 9.23 9.81 8.81C9.79 8.57 9.68 8.35 9.51 8.18L4.31 2.98C4.24 2.91 4.12 2.91 4.05 2.98L2.98 4.05C2.91 4.12 2.91 4.24 2.98 4.31L7.20 8.52L0.59 11.13C0.24 11.27 0 11.62 0 12.00C0 12.38 0.24 12.73 0.59 12.87L5.18 14.68C5.25 14.71 5.33 14.69 5.38 14.64L6.54 13.48C6.64 13.39 6.60 13.23 6.48 13.17H6.47ZM23.41 11.13L18.82 9.32C18.75 9.29 18.67 9.31 18.62 9.36L17.46 10.52C17.36 10.61 17.40 10.77 17.52 10.82L20.51 12.00L14.78 14.26C14.42 14.40 14.17 14.77 14.19 15.19C14.21 15.42 14.32 15.65 14.49 15.82L19.69 21.02C19.76 21.09 19.88 21.09 19.95 21.02L21.02 19.95C21.09 19.88 21.09 19.76 21.02 19.69L16.80 15.48L23.41 12.87C23.76 12.73 24 12.38 24 12.00C24 11.62 23.76 11.27 23.41 11.13V11.13Z" + ></path> + </symbol> <symbol viewBox="0 0 40 40" id="nebius"> <path d="M30.3333 7.53622V29.2323C30.3333 29.2323 35.5 28.9198 35.5 23.013V7.53622H30.3333ZM9.66667 32.9756V11.2795C9.66667 11.2795 4.5 11.5921 4.5 17.5001V32.9743L9.66667 32.9756Z" @@ -435,6 +527,14 @@ ></path> <path d="M33.2218 21.8333V29.3884H25.6667V25.6116H29.445V21.8333H33.2218Z" fill="currentColor"></path> </symbol> + <symbol viewBox="0 0 40 40" fill="none" id="moark"> + <path + fill-rule="evenodd" + clip-rule="evenodd" + d="M25.132 24.3947C25.497 25.7527 25.8984 27.1413 26.3334 28.5834C26.7302 29.8992 25.5459 30.4167 25.0752 29.1758C24.571 27.8466 24.0885 26.523 23.6347 25.1729C21.065 26.4654 18.5025 27.5424 15.5961 28.7541C16.7581 33.0256 17.8309 36.5984 19.4952 39.9935C19.4953 39.9936 19.4953 39.9937 19.4954 39.9938C19.6631 39.9979 19.8313 40 20 40C31.0457 40 40 31.0457 40 20C40 16.0335 38.8453 12.3366 36.8537 9.22729C31.6585 9.69534 27.0513 10.4562 22.8185 11.406C22.8882 12.252 22.9677 13.0739 23.0555 13.855C23.3824 16.7604 23.9112 19.5281 24.6137 22.3836C27.0581 21.2848 29.084 20.3225 30.6816 19.522C32.2154 18.7535 33.6943 18.7062 31.2018 20.6594C29.0388 22.1602 27.0644 23.3566 25.132 24.3947ZM36.1559 8.20846C33.0001 3.89184 28.1561 0.887462 22.5955 0.166882C22.4257 2.86234 22.4785 6.26344 22.681 9.50447C26.7473 8.88859 31.1721 8.46032 36.1559 8.20846ZM19.9369 9.73661e-05C19.7594 2.92694 19.8384 6.65663 20.19 9.91293C17.3748 10.4109 14.7225 11.0064 12.1592 11.7038C12.0486 10.4257 11.9927 9.25764 11.9927 8.24178C11.9927 7.5054 11.3957 6.90844 10.6593 6.90844C9.92296 6.90844 9.32601 7.5054 9.32601 8.24178C9.32601 9.47868 9.42873 10.898 9.61402 12.438C8.33567 12.8278 7.07397 13.2443 5.81918 13.688C5.12493 13.9336 4.76118 14.6954 5.0067 15.3896C5.25223 16.0839 6.01406 16.4476 6.7083 16.2021C7.7931 15.8185 8.88482 15.4388 9.98927 15.0659C10.5222 18.3344 11.3344 21.9428 12.2703 25.4156C12.4336 26.0218 12.6062 26.6262 12.7863 27.2263C9.34168 28.4135 5.82612 29.3782 2.61128 29.8879C0.949407 26.9716 0 23.5967 0 20C0 8.97534 8.92023 0.0341108 19.9369 9.73661e-05ZM4.19152 32.2527C7.45069 36.4516 12.3458 39.3173 17.9204 39.8932C16.5916 37.455 14.9338 33.717 13.5405 29.5901C10.4404 30.7762 7.25883 31.6027 4.19152 32.2527ZM22.9735 23.1135C22.1479 20.41 21.4462 17.5441 20.9225 14.277C20.746 13.5841 20.5918 12.8035 20.4593 11.9636C17.6508 12.6606 14.9992 13.4372 12.4356 14.2598C12.8479 17.4766 13.5448 21.1334 14.5118 24.7218C14.662 25.2792 14.8081 25.8248 14.9514 26.3594L14.9516 26.3603L14.9524 26.3634L14.9526 26.3639L14.973 26.4401C16.1833 25.9872 17.3746 25.5123 18.53 25.0259C20.1235 24.3552 21.6051 23.7165 22.9735 23.1135Z" + fill="currentColor" + ></path> + </symbol> <symbol viewBox="0 0 40 40" id="mistral"> <path d="M8.92783 8.88101H13.357V13.3088H17.7861V17.738H17.7835H22.2152V13.3088H26.6418V8.88101H31.0722V26.5949H35.5V31.0241H22.2139V26.5962H17.7861V22.1671H13.3557V26.5949L17.7861 26.5962V31.0241H4.5V26.5949H8.92783V8.88101ZM22.2139 26.5962H26.6418V22.1671H22.2152V26.5962H22.2139Z" @@ -447,12 +547,66 @@ fill="currentColor" ></path> </symbol> + <symbol viewBox="0 0 24 24" fill="none" id="minimax-coding-plan"> + <path + shape-rendering="geometricPrecision" + d="M9.8132 15.9038L9 18.75L8.1868 15.9038C7.75968 14.4089 6.59112 13.2403 5.09619 12.8132L2.25 12L5.09619 11.1868C6.59113 10.7597 7.75968 9.59112 8.1868 8.09619L9 5.25L9.8132 8.09619C10.2403 9.59113 11.4089 10.7597 12.9038 11.1868L15.75 12L12.9038 12.8132C11.4089 13.2403 10.2403 14.4089 9.8132 15.9038Z" + stroke="currentColor" + stroke-width="1.5" + stroke-linecap="round" + stroke-linejoin="round" + ></path> + <path + d="M18.2589 8.71454L18 9.75L17.7411 8.71454C17.4388 7.50533 16.4947 6.56117 15.2855 6.25887L14.25 6L15.2855 5.74113C16.4947 5.43883 17.4388 4.49467 17.7411 3.28546L18 2.25L18.2589 3.28546C18.5612 4.49467 19.5053 5.43883 20.7145 5.74113L21.75 6L20.7145 6.25887C19.5053 6.56117 18.5612 7.50533 18.2589 8.71454Z" + stroke="currentColor" + stroke-width="1.5" + stroke-linecap="round" + stroke-linejoin="round" + ></path> + <path + d="M16.8942 20.5673L16.5 21.75L16.1058 20.5673C15.8818 19.8954 15.3546 19.3682 14.6827 19.1442L13.5 18.75L14.6827 18.3558C15.3546 18.1318 15.8818 17.6046 16.1058 16.9327L16.5 15.75L16.8942 16.9327C17.1182 17.6046 17.6454 18.1318 18.3173 18.3558L19.5 18.75L18.3173 19.1442C17.6454 19.3682 17.1182 19.8954 16.8942 20.5673Z" + stroke="currentColor" + stroke-width="1.5" + stroke-linecap="round" + stroke-linejoin="round" + ></path> + </symbol> <symbol viewBox="0 0 40 40" id="minimax-cn"> <path d="M17.8758 9.20865C17.8758 8.59461 17.3777 8.09634 16.7663 8.09634C16.155 8.09634 15.6567 8.59575 15.6567 9.20865V27.6446C15.6567 29.0714 14.4985 30.2324 13.0755 30.2324C11.6523 30.2324 10.4941 29.0714 10.4941 27.6446V15.8167C10.4941 15.2027 9.99591 14.7044 9.38453 14.7044C8.77316 14.7044 8.275 15.2038 8.275 15.8167V20.8301C8.275 22.2567 7.11678 23.4179 5.69364 23.4179C4.2705 23.4179 3.1123 22.2567 3.1123 20.8301V19.0129C3.1123 18.6054 3.44177 18.2752 3.84822 18.2752C4.25467 18.2752 4.58413 18.6054 4.58413 19.0129V20.8301C4.58413 21.4441 5.08227 21.9424 5.69364 21.9424C6.30502 21.9424 6.80317 21.443 6.80317 20.8301V15.8167C6.80317 14.39 7.96139 13.2289 9.38453 13.2289C10.8077 13.2289 11.9659 14.39 11.9659 15.8167V27.6446C11.9659 28.2587 12.4641 28.7569 13.0755 28.7569C13.6868 28.7569 14.1849 28.2575 14.1849 27.6446V20.4123V9.20865C14.1849 7.78194 15.3431 6.62082 16.7663 6.62082C18.1894 6.62082 19.3476 7.78194 19.3476 9.20865V24.4746C19.3476 24.8821 19.0182 25.2123 18.6117 25.2123C18.2053 25.2123 17.8758 24.8821 17.8758 24.4746V9.20865ZM31.531 13.2289C30.1079 13.2289 28.9496 14.39 28.9496 15.8167V25.6969C28.9496 26.311 28.4515 26.8093 27.8401 26.8093C27.2287 26.8093 26.7306 26.3099 26.7306 25.6969V9.20865C26.7306 7.78194 25.5723 6.62082 24.1492 6.62082C22.7261 6.62082 21.5679 7.78194 21.5679 9.20865V30.1383C21.5679 30.7523 21.0697 31.2506 20.4583 31.2506C19.8469 31.2506 19.3488 30.7511 19.3488 30.1383V27.5471C19.3488 27.1396 19.0194 26.8093 18.6129 26.8093C18.2065 26.8093 17.877 27.1396 17.877 27.5471V30.1383C17.877 31.565 19.0352 32.7261 20.4583 32.7261C21.8815 32.7261 23.0397 31.565 23.0397 30.1383V9.20865C23.0397 8.59461 23.5378 8.09634 24.1492 8.09634C24.7605 8.09634 25.2587 8.59575 25.2587 9.20865V25.6969C25.2587 27.1237 26.417 28.2848 27.8401 28.2848C29.2632 28.2848 30.4215 27.1237 30.4215 25.6969V15.8167C30.4215 15.2027 30.9196 14.7044 31.531 14.7044C32.1424 14.7044 32.6405 15.2038 32.6405 15.8167V24.4746C32.6405 24.8821 32.97 25.2123 33.3764 25.2123C33.7829 25.2123 34.1123 24.8821 34.1123 24.4746V15.8167C34.1123 14.39 32.9541 13.2289 31.531 13.2289Z" fill="currentColor" ></path> </symbol> + <symbol viewBox="0 0 24 24" fill="none" id="minimax-cn-coding-plan"> + <path + shape-rendering="geometricPrecision" + d="M9.8132 15.9038L9 18.75L8.1868 15.9038C7.75968 14.4089 6.59112 13.2403 5.09619 12.8132L2.25 12L5.09619 11.1868C6.59113 10.7597 7.75968 9.59112 8.1868 8.09619L9 5.25L9.8132 8.09619C10.2403 9.59113 11.4089 10.7597 12.9038 11.1868L15.75 12L12.9038 12.8132C11.4089 13.2403 10.2403 14.4089 9.8132 15.9038Z" + stroke="currentColor" + stroke-width="1.5" + stroke-linecap="round" + stroke-linejoin="round" + ></path> + <path + d="M18.2589 8.71454L18 9.75L17.7411 8.71454C17.4388 7.50533 16.4947 6.56117 15.2855 6.25887L14.25 6L15.2855 5.74113C16.4947 5.43883 17.4388 4.49467 17.7411 3.28546L18 2.25L18.2589 3.28546C18.5612 4.49467 19.5053 5.43883 20.7145 5.74113L21.75 6L20.7145 6.25887C19.5053 6.56117 18.5612 7.50533 18.2589 8.71454Z" + stroke="currentColor" + stroke-width="1.5" + stroke-linecap="round" + stroke-linejoin="round" + ></path> + <path + d="M16.8942 20.5673L16.5 21.75L16.1058 20.5673C15.8818 19.8954 15.3546 19.3682 14.6827 19.1442L13.5 18.75L14.6827 18.3558C15.3546 18.1318 15.8818 17.6046 16.1058 16.9327L16.5 15.75L16.8942 16.9327C17.1182 17.6046 17.6454 18.1318 18.3173 18.3558L19.5 18.75L18.3173 19.1442C17.6454 19.3682 17.1182 19.8954 16.8942 20.5673Z" + stroke="currentColor" + stroke-width="1.5" + stroke-linecap="round" + stroke-linejoin="round" + ></path> + </symbol> + <symbol viewBox="0 0 1000 1000" fill="none" id="meganova"> + <path + d="M534 154C541.732 154 548 160.268 548 168C548 170.518 547.334 172.881 546.17 174.923L602.021 240.338C603.835 239.48 605.861 239 608 239C615.732 239 622 245.268 622 253C622 254.065 621.88 255.102 621.655 256.099L706.818 300.431C709.276 298.294 712.487 297 716 297C723.732 297 730 303.268 730 311C730 311.443 729.978 311.882 729.938 312.314L863.375 379.883C865.943 376.893 869.75 375 874 375C881.732 375 888 381.268 888 389C888 391.789 887.183 394.387 885.777 396.569L946.472 464.134C948.168 463.404 950.037 463 952 463C959.732 463 966 469.268 966 477C966 484.732 959.732 491 952 491C945.627 491 940.248 486.741 938.555 480.914L856.912 472.417C854.794 477.459 849.811 481 844 481C839.112 481 834.811 478.495 832.307 474.699L729.884 506.808C728.997 513.686 723.119 519 716 519C713.249 519 710.684 518.206 708.52 516.835L621.863 571.045C621.953 571.684 622 572.336 622 573C622 580.732 615.732 587 608 587C606.913 587 605.854 586.876 604.838 586.642L545.427 672.909C547.047 675.194 548 677.986 548 681C548 685.573 545.806 689.633 542.415 692.188L562.436 761.104C567.278 761.8 571 765.965 571 771C571 772.011 570.848 772.986 570.569 773.906L603.281 804.182C604.687 803.428 606.293 803 608 803C611.041 803 613.763 804.359 615.597 806.5L702.076 770.468C702.026 769.985 702 769.496 702 769C702 761.268 708.268 755 716 755C723.732 755 730 761.268 730 769C730 776.732 723.732 783 716 783C712.501 783 709.301 781.716 706.847 779.594L617.979 836.371C617.991 836.579 618 836.789 618 837C618 842.523 613.523 847 608 847C602.477 847 598 842.523 598 837C598 836.723 598.014 836.449 598.036 836.178L513.258 779.798C511.544 781.175 509.369 782 507 782C501.477 782 497 777.523 497 772C497 769.373 498.014 766.983 499.671 765.198L467.477 694.922C466.991 694.973 466.499 695 466 695C458.268 695 452 688.732 452 681C452 677.846 453.043 674.935 454.803 672.595L395.197 586.633C394.17 586.873 393.1 587 392 587C384.268 587 378 580.732 378 573C378 572.271 378.055 571.555 378.162 570.856L292.756 515.923C290.358 517.847 287.314 519 284 519C276.58 519 270.509 513.228 270.031 505.929L167.816 474.509C165.332 478.411 160.969 481 156 481C150.213 481 145.246 477.489 143.113 472.48L61.3994 481.062C59.6582 486.813 54.319 491 48 491C40.268 491 34 484.732 34 477C34 469.268 40.268 463 48 463C50.289 463 52.4497 463.549 54.3574 464.523L113.915 396.071C112.698 393.996 112 391.58 112 389C112 381.268 118.268 375 126 375C130.139 375 133.858 376.796 136.421 379.651L270.236 313.574C270.081 312.74 270 311.879 270 311C270 303.268 276.268 297 284 297C287.987 297 291.584 298.667 294.134 301.341L378.38 256.251C378.132 255.208 378 254.119 378 253C378 245.268 384.268 239 392 239C394.155 239 396.197 239.487 398.021 240.357L454.009 175.23C452.734 173.12 452 170.646 452 168C452 160.268 458.268 154 466 154C473.732 154 480 160.268 480 168C480 175.732 473.732 182 466 182C465.903 182 465.806 181.997 465.71 181.995L456.335 215.262C458.572 217.096 460 219.881 460 223C460 223.476 459.964 223.943 459.899 224.401L490.157 243.044C492.686 240.544 496.163 239 500 239C503.689 239 507.043 240.427 509.544 242.759L540.088 224.312C540.032 223.882 540 223.445 540 223C540 219.852 541.455 217.045 543.729 215.212L534.666 181.983C534.445 181.994 534.223 182 534 182C526.268 182 520 175.732 520 168C520 160.268 526.268 154 534 154ZM601.857 829.11C603.553 827.789 605.684 827 608 827C610.386 827 612.575 827.836 614.294 829.23L675.14 790.358L617.926 814.197C617.334 819.155 613.118 823 608 823C602.477 823 598 818.523 598 813C598 812.133 598.11 811.291 598.317 810.488L565.37 779.995C564.05 780.638 562.567 781 561 781C556.709 781 553.05 778.296 551.631 774.5H519.738L601.857 829.11ZM534.745 694.979L512.811 763.863C513.81 764.579 514.673 765.473 515.351 766.5H552.07C552.714 765.226 553.62 764.108 554.72 763.219L534.893 694.97C534.843 694.973 534.794 694.977 534.745 694.979ZM479.419 685C478.611 687.716 477.001 690.086 474.863 691.836L505.827 759.428L526.949 693.097C523.912 691.323 521.604 688.438 520.581 685H479.419ZM472.819 668.771C475.97 670.531 478.37 673.475 479.419 677H520.581C521.664 673.363 524.184 670.345 527.483 668.606L499.583 566.045L472.819 668.771ZM506.869 556.264C506.448 556.662 505.992 557.025 505.507 557.346L535.354 667.064C536.67 667.191 537.934 667.499 539.119 667.965L597.867 582.66C596.132 580.841 594.883 578.555 594.325 576.011L506.869 556.264ZM405.68 575.984C405.128 578.527 403.885 580.811 402.158 582.632L461.236 667.831C462.425 667.401 463.689 667.128 465.003 667.035L493.727 556.786C493.457 556.568 493.198 556.338 492.952 556.094L405.68 575.984ZM508.761 544.178C509.515 545.545 509.956 547.106 509.994 548.769L594.938 567.95C595.639 566.14 596.705 564.512 598.046 563.156L557.757 476.993C557.023 476.976 556.309 476.88 555.622 476.713L508.761 544.178ZM445.066 476.519C444.466 476.712 443.841 476.849 443.197 476.926L402.037 563.241C403.332 564.573 404.364 566.161 405.05 567.922L490.011 548.559C490.068 547.243 490.38 545.994 490.898 544.857L445.066 476.519ZM565.856 473.183C565.642 473.455 565.413 473.716 565.172 473.965L605.076 559.306C606.019 559.105 606.997 559 608 559C612.173 559 615.919 560.826 618.483 563.723L703.216 510.716C702.671 509.5 702.295 508.192 702.117 506.822L565.856 473.183ZM297.766 507.556C297.653 508.166 297.501 508.762 297.312 509.342L381.642 563.581C384.202 560.766 387.895 559 392 559C393.044 559 394.061 559.114 395.039 559.331L435.461 474.562C435.054 474.21 434.675 473.828 434.329 473.415L297.766 507.556ZM451.235 463.162C451.727 464.344 452 465.64 452 467C452 468.48 451.675 469.884 451.098 471.148L496.927 539.482C497.895 539.17 498.928 539 500 539C500.832 539 501.64 539.103 502.412 539.294L549.257 471.854C548.457 470.416 548 468.762 548 467C548 465.371 548.392 463.834 549.083 462.475L501.213 398.924C500.815 398.972 500.411 399 500 399C499.329 399 498.673 398.933 498.039 398.807L451.235 463.162ZM346.938 397.694C345.907 398.281 344.763 398.691 343.546 398.88L295.016 496.359C295.772 497.322 296.404 498.386 296.89 499.528L432.083 465.729C432.175 465.006 432.341 464.306 432.579 463.639L346.938 397.694ZM567.637 464.329C567.737 464.692 567.819 465.062 567.878 465.44L703.396 498.896C704.247 497.143 705.453 495.595 706.92 494.344L659.017 398.948C658.682 398.982 658.343 399 658 399C656.789 399 655.629 398.785 654.555 398.391L567.637 464.329ZM773.415 398.4C772.743 398.645 772.037 398.816 771.307 398.911L726.722 495.999C727.447 496.862 728.07 497.814 728.572 498.836L830 467.039C830 467.026 830 467.013 830 467C830 464.574 830.617 462.293 831.702 460.304L773.415 398.4ZM168.537 460.766C169.446 462.59 169.968 464.64 169.997 466.811L271.812 498.106C272.696 496.546 273.872 495.173 275.265 494.06L230.778 398.967C230.521 398.987 230.262 399 230 399C229.342 399 228.699 398.934 228.076 398.812L168.537 460.766ZM667.337 385.418C667.764 386.53 668 387.737 668 389C668 391.257 667.252 393.338 665.991 395.012L713.5 489.621V324.776C713.053 324.696 712.614 324.594 712.184 324.473L667.337 385.418ZM290.106 323.6C289.907 323.697 289.705 323.789 289.5 323.877V489.49L335.673 396.743C333.431 394.909 332 392.122 332 389C332 386.919 332.636 384.987 333.724 383.387L290.106 323.6ZM239.209 385.098C239.718 386.297 240 387.615 240 389C240 391.341 239.194 393.492 237.847 395.195L281.5 488.509V324.776C281.224 324.727 280.951 324.668 280.681 324.603L239.209 385.098ZM721.5 323.877V488.205L763.549 396.639C761.379 394.804 760 392.064 760 389C760 386.918 760.637 384.985 761.726 383.384L721.64 323.815C721.593 323.836 721.547 323.857 721.5 323.877ZM60.1543 470.048C60.6859 470.975 61.113 471.97 61.4229 473.015L142.217 464.529C142.869 460.867 144.945 457.698 147.852 455.614L125.642 402.995C123.533 402.942 121.541 402.422 119.764 401.536L60.1543 470.048ZM879.71 401.785C877.966 402.565 876.034 403 874 403C873.859 403 873.72 402.996 873.58 402.992L852.339 455.754C855.128 457.825 857.119 460.91 857.77 464.463L938.617 472.877C939.015 471.584 939.595 470.37 940.328 469.267L879.71 401.785ZM508.659 394C508.497 394.28 508.321 394.551 508.133 394.813L555.263 457.382C556.133 457.135 557.051 457 558 457C559.655 457 561.215 457.404 562.59 458.116L647.109 394H508.659ZM438.096 457.791C439.295 457.282 440.615 457 442 457C443.192 457 444.335 457.209 445.396 457.592L491.476 394.23C491.429 394.155 491.385 394.077 491.341 394H355.251L438.096 457.791ZM139.08 394C137.987 396.857 135.986 399.263 133.429 400.867L155.438 453.012C155.624 453.004 155.812 453 156 453C158.578 453 160.993 453.698 163.067 454.913L221.44 394.174C221.406 394.117 221.374 394.058 221.341 394H139.08ZM837.377 454.662C839.349 453.601 841.604 453 844 453C844.273 453 844.544 453.008 844.812 453.023L865.972 400.47C863.702 398.878 861.926 396.63 860.92 394H780.261L837.377 454.662ZM561.53 324.356C560.432 324.771 559.243 325 558 325C557.329 325 556.673 324.933 556.039 324.807L508.931 384.504C509.172 384.982 509.379 385.481 509.542 386H646.656L561.53 324.356ZM768.495 379.112C768.986 379.038 769.489 379 770 379C774.478 379 778.268 381.943 779.542 386H857.747L729.39 321.004L768.495 379.112ZM355.696 386H490.458C490.55 385.708 490.655 385.423 490.771 385.144L444.67 324.637C443.82 324.872 442.925 325 442 325C441.036 325 440.105 324.861 439.223 324.606L355.696 386ZM141.636 386H220.458C221.732 381.943 225.522 379 230 379C231.159 379 232.271 379.199 233.306 379.562L273.545 320.864L141.636 386ZM617.724 263.07C617.275 263.503 616.799 263.906 616.296 264.276L659.187 379.072C660.037 379.173 660.854 379.38 661.625 379.68L705.419 320.167C703.289 317.711 702 314.506 702 311C702 309.687 702.18 308.415 702.519 307.21L617.724 263.07ZM451.826 313.151C451.938 313.751 452 314.368 452 315C452 316.655 451.595 318.215 450.883 319.59L496.599 379.593C497.66 379.209 498.806 379 500 379C500.963 379 501.893 379.139 502.773 379.393L549.469 320.219C548.537 318.699 548 316.913 548 315C548 314.117 548.115 313.26 548.33 312.444L505.47 265.89C503.789 266.604 501.941 267 500 267C497.866 267 495.844 266.521 494.034 265.667L451.826 313.151ZM297.771 308.468C297.921 309.289 298 310.135 298 311C298 313.614 297.283 316.06 296.035 318.154L340.507 379.111C340.994 379.038 341.493 379 342 379C342.385 379 342.765 379.024 343.139 379.066L383.879 264.404C383.354 264.03 382.857 263.62 382.39 263.179L297.771 308.468ZM397.089 266.046C395.512 266.662 393.795 267 392 267C391.816 267 391.634 266.994 391.452 266.987L351.633 379.058L432.961 319.28C432.345 317.983 432 316.532 432 315C432 313.273 432.437 311.648 433.208 310.23L397.089 266.046ZM567.117 310.896C567.682 312.148 568 313.537 568 315C568 316.293 567.751 317.527 567.305 318.661L650.615 378.989L608.765 266.979C608.511 266.992 608.257 267 608 267C606.25 267 604.576 266.678 603.031 266.092L567.117 310.896ZM405.818 250.75C405.937 251.483 406 252.234 406 253C406 256.03 405.037 258.836 403.4 261.127L439.519 305.31C440.312 305.107 441.143 305 442 305C443.87 305 445.62 305.515 447.117 306.408L488.073 260.334C486.759 258.201 486 255.689 486 253C486 251.995 486.106 251.014 486.308 250.069L455.703 231.212C454.085 232.338 452.12 233 450 233C447.634 233 445.462 232.177 443.75 230.804L405.818 250.75ZM556.249 230.805C554.537 232.177 552.365 233 550 233C547.847 233 545.855 232.317 544.224 231.16L513.598 249.657C513.86 250.728 514 251.848 514 253C514 255.88 513.129 258.556 511.639 260.781L553.387 306.128C554.767 305.409 556.336 305 558 305C559.11 305 560.177 305.183 561.175 305.517L596.675 261.23C594.993 258.92 594 256.076 594 253C594 252.234 594.061 251.483 594.18 250.751L556.249 230.805ZM551.447 213.105C556.284 213.807 560 217.969 560 223C560 223.243 559.988 223.485 559.971 223.724L591.452 240.279L543.561 184.188L551.447 213.105ZM408.715 240.19L440.028 223.724C440.011 223.485 440 223.243 440 223C440 217.94 443.758 213.761 448.635 213.095L456.745 184.319L408.715 240.19Z" + fill="currentColor" + ></path> + </symbol> <symbol viewBox="0 0 24 24" fill="none" id="lucidquery"> <path d="M9.60783 3.46101C9.64016 3.48017 9.67275 3.49889 9.70534 3.51763C9.71858 3.52526 9.73182 3.53289 9.74507 3.54052C9.75164 3.54431 9.75822 3.5481 9.76499 3.552C9.79789 3.57096 9.83078 3.58994 9.86367 3.60892C9.8768 3.61649 9.88993 3.62407 9.90307 3.63165C10.4152 3.9271 10.4152 3.9271 10.9273 4.22255C10.9338 4.2263 10.9403 4.23005 10.947 4.23392C10.9601 4.24149 10.9732 4.24906 10.9864 4.25663C11.0193 4.27565 11.0523 4.29467 11.0853 4.31367C11.1486 4.35017 11.2119 4.38677 11.275 4.42369C11.3276 4.45444 11.3804 4.48481 11.4334 4.51497C11.4923 4.54855 11.551 4.58245 11.6095 4.61669C11.6731 4.65387 11.7369 4.69064 11.8008 4.72741C11.8223 4.73983 11.8438 4.75228 11.8654 4.76473C11.8762 4.771 11.887 4.77726 11.8979 4.78352C11.9081 4.78946 11.9184 4.79541 11.9287 4.80136C11.9349 4.80495 11.9411 4.80855 11.9475 4.81225C11.953 4.81542 11.9585 4.81858 11.9641 4.82184C11.9689 4.82458 11.9738 4.82731 11.9788 4.83012C11.9828 4.83281 11.9868 4.8355 11.9909 4.83827C12.0035 4.84381 12.0035 4.84381 12.0178 4.83672C12.0232 4.83342 12.0287 4.83013 12.0343 4.82674C12.0406 4.82307 12.0468 4.81939 12.0532 4.81561C12.0599 4.81152 12.0666 4.80744 12.0735 4.80323C12.0806 4.79902 12.0876 4.79482 12.0947 4.79063C12.1094 4.78192 12.1241 4.77315 12.1388 4.76436C12.1721 4.74444 12.2058 4.7252 12.2394 4.70588C12.2525 4.69831 12.2657 4.69073 12.2788 4.68315C13.303 4.09225 13.303 4.09225 13.3227 4.08088C13.3359 4.07331 13.349 4.06574 13.3621 4.05817C13.3951 4.03915 13.4281 4.02013 13.461 4.00113C13.5244 3.96463 13.5877 3.92803 13.6508 3.89111C13.7069 3.85826 13.7634 3.82587 13.8199 3.79365C13.8752 3.76213 13.9303 3.73025 13.9853 3.69811C14.049 3.66081 14.1131 3.62393 14.1771 3.58705C14.2034 3.57187 14.2298 3.55667 14.2561 3.54147C14.2692 3.53393 14.2822 3.5264 14.2953 3.51888C14.329 3.49945 14.3627 3.47993 14.3963 3.46025C14.568 3.35985 14.7407 3.28118 14.9451 3.33127C14.9606 3.33546 14.9756 3.34022 14.9909 3.34528C14.9968 3.3472 15.0026 3.34911 15.0086 3.35108C15.1125 3.39027 15.2095 3.45509 15.3049 3.51115C15.3433 3.53371 15.3819 3.556 15.4205 3.57824C15.427 3.58201 15.4335 3.58578 15.4403 3.58967C15.4536 3.59732 15.4668 3.60496 15.4801 3.61261C15.513 3.63157 15.5459 3.65055 15.5788 3.66952C15.5919 3.6771 15.605 3.68468 15.6182 3.69225C15.697 3.73771 15.7758 3.78316 15.8545 3.82861C15.861 3.83236 15.8675 3.83612 15.8742 3.83998C15.8874 3.84755 15.9005 3.85512 15.9136 3.86269C15.9466 3.88172 15.9796 3.90073 16.0125 3.91974C16.0759 3.95623 16.1392 3.99284 16.2023 4.02975C16.2549 4.06051 16.3077 4.09087 16.3606 4.12104C16.4195 4.15461 16.4782 4.18851 16.5368 4.22275C16.6005 4.26005 16.6646 4.29694 16.7286 4.33382C16.7615 4.35277 16.7944 4.37175 16.8273 4.39073C16.8404 4.39831 16.8535 4.40588 16.8667 4.41346C17.103 4.54982 17.3394 4.68618 17.5757 4.82255C17.5855 4.82817 17.5855 4.82817 17.5954 4.83392C17.6085 4.84147 17.6216 4.84903 17.6347 4.85658C17.6681 4.87587 17.7016 4.89512 17.735 4.91431C17.768 4.93322 17.8009 4.95222 17.8337 4.97131C17.8451 4.9779 17.8564 4.98447 17.8678 4.99101C17.9298 5.02675 17.9832 5.06351 18.0333 5.11497C18.04 5.12167 18.04 5.12167 18.0468 5.12851C18.1733 5.26233 18.1988 5.43146 18.1986 5.60719C18.1987 5.61939 18.1987 5.63159 18.1987 5.64379C18.1988 5.6771 18.1989 5.71041 18.1989 5.74372C18.1989 5.77972 18.199 5.81572 18.1991 5.85173C18.1992 5.91808 18.1993 5.98443 18.1994 6.05079C18.1994 6.11204 18.1995 6.17329 18.1996 6.23455C18.1996 6.23861 18.1996 6.24268 18.1996 6.24688C18.1997 6.26754 18.1997 6.28821 18.1998 6.30887C18.2 6.45503 18.2003 6.60119 18.2004 6.74736C18.2006 6.8893 18.2008 7.03125 18.2011 7.17319C18.2011 7.17757 18.2011 7.18195 18.2011 7.18647C18.2012 7.23045 18.2013 7.27443 18.2013 7.31842C18.2015 7.40801 18.2016 7.4976 18.2018 7.58719C18.2018 7.59131 18.2018 7.59543 18.2018 7.59967C18.2023 7.87446 18.2026 8.14925 18.203 8.42404C18.2078 8.42675 18.2125 8.42946 18.2174 8.43226C18.2354 8.44254 18.2535 8.45283 18.2715 8.46311C18.2792 8.46753 18.2869 8.47194 18.2947 8.47635C18.3453 8.50525 18.3958 8.53436 18.4462 8.56381C18.4524 8.56744 18.4586 8.57107 18.465 8.57481C18.4706 8.57807 18.4761 8.58133 18.4819 8.58469C18.5397 8.61849 18.5978 8.65187 18.6558 8.6853C18.6887 8.70426 18.7216 8.72324 18.7545 8.74222C18.7676 8.74979 18.7808 8.75737 18.7939 8.76494C19.1878 8.99221 19.5818 9.21949 19.9757 9.44676C19.9822 9.45051 19.9887 9.45426 19.9954 9.45812C20.0085 9.46569 20.0217 9.47326 20.0348 9.48083C20.0678 9.49986 20.1007 9.51888 20.1337 9.53788C20.1971 9.57438 20.2603 9.61098 20.3234 9.64789C20.3725 9.67655 20.4216 9.7049 20.471 9.73301C20.5029 9.7512 20.5347 9.76943 20.5666 9.78766C20.5734 9.79151 20.5801 9.79536 20.587 9.79933C20.7794 9.90961 20.925 10.0179 20.9862 10.241C20.9954 10.2793 20.9978 10.315 20.9977 10.3541C20.9978 10.3599 20.9978 10.3657 20.9978 10.3716C20.9978 10.391 20.9978 10.4104 20.9978 10.4297C20.9978 10.4437 20.9979 10.4578 20.9979 10.4718C20.9979 10.5103 20.998 10.5489 20.998 10.5874C20.998 10.6247 20.9981 10.662 20.9981 10.6993C20.9982 10.7992 20.9983 10.8991 20.9983 10.999C20.9984 11.0463 20.9984 11.0936 20.9984 11.1409C20.9985 11.3028 20.9986 11.4648 20.9987 11.6267C20.9987 11.6368 20.9987 11.647 20.9987 11.6572C20.9987 11.6647 20.9987 11.6647 20.9987 11.6724C20.9987 11.698 20.9987 11.7235 20.9987 11.7491C20.9987 11.7541 20.9987 11.7592 20.9987 11.7644C20.9988 11.9286 20.9989 12.0929 20.9991 12.2571C20.9993 12.4308 20.9994 12.6045 20.9995 12.7782C20.9995 12.7973 20.9995 12.8164 20.9995 12.8355C20.9995 12.8425 20.9995 12.8425 20.9995 12.8497C20.9995 12.9252 20.9996 13.0007 20.9997 13.0762C20.9998 13.1522 20.9999 13.2281 20.9998 13.3041C20.9998 13.3452 20.9998 13.3863 20.9999 13.4275C21 13.4651 21 13.5028 20.9999 13.5405C20.9999 13.5541 20.9999 13.5677 21 13.5813C21.0009 13.7615 20.9511 13.9105 20.8238 14.0422C20.7544 14.1113 20.667 14.1549 20.582 14.202C20.5443 14.2228 20.5071 14.2443 20.47 14.266C20.4198 14.2955 20.3694 14.3248 20.3189 14.3539C20.3124 14.3577 20.3058 14.3615 20.2991 14.3654C20.2858 14.373 20.2725 14.3806 20.2592 14.3883C20.2263 14.4072 20.1935 14.4262 20.1606 14.4452C20.1474 14.4528 20.1343 14.4604 20.1212 14.4679C20.1147 14.4717 20.1082 14.4754 20.1015 14.4793C18.9394 15.1497 18.9394 15.1497 18.9197 15.1611C18.9065 15.1687 18.8934 15.1763 18.8803 15.1838C18.8473 15.2028 18.8144 15.2219 18.7814 15.2409C18.718 15.2774 18.6547 15.314 18.5916 15.3509C18.5327 15.3853 18.4735 15.4193 18.4142 15.453C18.401 15.4606 18.3879 15.4684 18.375 15.4764C18.3548 15.4882 18.335 15.4951 18.3127 15.502C18.2683 15.5181 18.2316 15.5368 18.203 15.5755C18.1723 15.6528 18.1842 15.7509 18.1859 15.8322C18.1865 15.8679 18.1862 15.9037 18.1861 15.9395C18.1859 16.0014 18.1863 16.0634 18.1871 16.1253C18.1878 16.1903 18.1883 16.2553 18.1884 16.3203C18.1884 16.3244 18.1884 16.3284 18.1884 16.3326C18.1884 16.3532 18.1884 16.3738 18.1884 16.3944C18.1885 16.54 18.1893 16.6857 18.1904 16.8314C18.1916 16.9726 18.1924 17.1138 18.1929 17.255C18.1929 17.2594 18.1929 17.2637 18.193 17.2682C18.1933 17.3548 18.1935 17.4415 18.1938 17.5281C18.1939 17.5703 18.194 17.6124 18.1942 17.6545C18.1942 17.667 18.1943 17.6795 18.1943 17.6919C18.1946 17.8054 18.1953 17.9189 18.196 18.0324C18.1963 18.0779 18.1966 18.1234 18.1969 18.1689C18.1971 18.2109 18.1974 18.253 18.1978 18.2951C18.198 18.3208 18.1982 18.3464 18.1983 18.3721C18.1983 18.3837 18.1984 18.3954 18.1986 18.407C18.2006 18.5819 18.1645 18.739 18.0454 18.8724C18.041 18.8774 18.0366 18.8824 18.0321 18.8875C17.9613 18.9628 17.8686 19.0086 17.7792 19.0581C17.7496 19.0744 17.7203 19.0912 17.6913 19.1084C17.649 19.1335 17.6066 19.1581 17.564 19.1827C17.5539 19.1885 17.5539 19.1885 17.5437 19.1944C17.5299 19.2023 17.5161 19.2102 17.5024 19.2182C17.4692 19.2373 17.4361 19.2564 17.403 19.2755C17.3899 19.2831 17.3768 19.2906 17.3636 19.2982C17.3571 19.302 17.3506 19.3057 17.3439 19.3096C17.2848 19.3437 17.2848 19.3437 17.2651 19.355C17.252 19.3626 17.2389 19.3702 17.2258 19.3777C17.1928 19.3968 17.1598 19.4158 17.1268 19.4348C17.0635 19.4713 17.0002 19.5079 16.9371 19.5448C16.8809 19.5776 16.8245 19.61 16.7679 19.6423C16.7126 19.6738 16.6576 19.7057 16.6026 19.7378C16.5388 19.7751 16.4748 19.812 16.4108 19.8489C16.3779 19.8678 16.345 19.8868 16.3121 19.9058C16.299 19.9133 16.2858 19.9209 16.2727 19.9285C16.2662 19.9323 16.2597 19.936 16.253 19.9399C15.8295 20.1842 15.8295 20.1842 15.4061 20.4285C15.3996 20.4323 15.393 20.436 15.3863 20.4399C15.3733 20.4474 15.3602 20.455 15.3471 20.4625C15.3135 20.4818 15.28 20.5012 15.2466 20.5207C15.2079 20.5431 15.1691 20.5654 15.1303 20.5876C15.1253 20.5905 15.1203 20.5934 15.1151 20.5964C14.9819 20.6727 14.8302 20.7018 14.6777 20.6717C14.6648 20.6682 14.6521 20.6644 14.6394 20.6603C14.6323 20.6582 14.6252 20.6561 14.6179 20.654C14.5453 20.6308 14.482 20.5901 14.417 20.551C14.3861 20.5326 14.3549 20.5149 14.3236 20.4971C14.3057 20.4869 14.2877 20.4767 14.2698 20.4664C14.2662 20.4644 14.2627 20.4624 14.259 20.4603C14.2023 20.4279 14.1458 20.3952 14.0892 20.3625C14.0564 20.3436 14.0237 20.3247 13.9909 20.3058C13.9778 20.2982 13.9647 20.2906 13.9515 20.283C13.9418 20.2774 13.9418 20.2774 13.9318 20.2717C13.8071 20.1997 13.6823 20.1277 13.5576 20.0558C13.5478 20.0501 13.5478 20.0501 13.5379 20.0444C13.5248 20.0368 13.5116 20.0293 13.4985 20.0217C13.4655 20.0027 13.4326 19.9837 13.3996 19.9647C13.3362 19.9282 13.273 19.8916 13.2099 19.8546C13.1573 19.8239 13.1045 19.7935 13.0515 19.7633C12.9926 19.7298 12.9339 19.6959 12.8754 19.6616C12.8116 19.6243 12.7476 19.5874 12.6835 19.5506C12.6506 19.5316 12.6178 19.5126 12.5849 19.4937C12.5717 19.4861 12.5586 19.4785 12.5455 19.4709C12.3091 19.3346 12.3091 19.3346 12.2894 19.3232C12.2764 19.3157 12.2633 19.3081 12.2503 19.3006C12.2196 19.2829 12.1889 19.2652 12.1583 19.2475C12.1438 19.2391 12.1294 19.2308 12.115 19.2224C12.1048 19.2165 12.0947 19.2107 12.0846 19.2048C12.0784 19.2012 12.0722 19.1976 12.0658 19.1939C12.0604 19.1908 12.055 19.1877 12.0494 19.1844C12.0441 19.1815 12.0388 19.1785 12.0334 19.1755C12.0273 19.1718 12.0212 19.1682 12.015 19.1644C11.9977 19.1555 11.9977 19.1555 11.982 19.1616C11.9771 19.1646 11.9722 19.1677 11.9672 19.1709C11.9615 19.1743 11.9559 19.1777 11.9501 19.1812C11.9441 19.1851 11.938 19.1889 11.9318 19.1929C11.9187 19.2009 11.9056 19.2089 11.8925 19.2169C11.8823 19.2232 11.8823 19.2232 11.872 19.2296C11.8395 19.2495 11.8065 19.2683 11.7735 19.2872C11.7603 19.2948 11.747 19.3025 11.7338 19.3101C11.7272 19.3139 11.7206 19.3177 11.7139 19.3216C11.681 19.3405 11.6481 19.3595 11.6152 19.3785C11.602 19.3861 11.5889 19.3937 11.5758 19.4012C11.5693 19.405 11.5628 19.4087 11.5561 19.4126C11.0243 19.7194 11.0243 19.7194 11.0046 19.7308C10.9914 19.7383 10.9783 19.7459 10.9652 19.7535C10.9322 19.7725 10.8993 19.7915 10.8663 19.8105C10.8029 19.847 10.7396 19.8836 10.6765 19.9205C10.6204 19.9534 10.5639 19.9858 10.5074 20.018C10.4521 20.0495 10.397 20.0814 10.3421 20.1136C10.2783 20.1508 10.2143 20.1877 10.1502 20.2246C10.1173 20.2436 10.0844 20.2626 10.0515 20.2815C10.0384 20.2891 10.0253 20.2967 10.0122 20.3043C10.0057 20.308 9.99916 20.3118 9.99246 20.3156C9.92024 20.3573 9.84802 20.399 9.77579 20.4406C9.76929 20.4444 9.76278 20.4481 9.75608 20.452C9.74301 20.4595 9.72994 20.4671 9.71686 20.4746C9.68309 20.4941 9.64935 20.5136 9.61566 20.5332C9.43912 20.636 9.26685 20.7189 9.05648 20.669C8.95425 20.6416 8.86572 20.5864 8.77526 20.5331C8.74223 20.5137 8.70901 20.4946 8.6758 20.4755C8.66267 20.4679 8.64954 20.4603 8.63641 20.4527C8.62666 20.4471 8.62666 20.4471 8.61671 20.4414C8.22934 20.2179 7.84197 19.9944 7.4546 19.7709C7.44485 19.7653 7.44485 19.7653 7.4349 19.7596C7.42178 19.752 7.40866 19.7444 7.39553 19.7368C7.36256 19.7178 7.32958 19.6988 7.2966 19.6798C7.23325 19.6433 7.16998 19.6067 7.10687 19.5698C7.05428 19.539 7.00147 19.5087 6.94854 19.4785C6.88963 19.4449 6.83091 19.411 6.77238 19.3768C6.7086 19.3395 6.64458 19.3026 6.58056 19.2657C6.54766 19.2468 6.51477 19.2278 6.48188 19.2088C6.46875 19.2012 6.45562 19.1937 6.44248 19.1861C6.41622 19.1709 6.38996 19.1558 6.3637 19.1406C6.35719 19.1369 6.35068 19.1331 6.34398 19.1293C6.33092 19.1217 6.31786 19.1142 6.30481 19.1066C6.27447 19.0891 6.24411 19.0716 6.21365 19.0543C6.20298 19.0483 6.19233 19.0422 6.18168 19.0361C6.16841 19.0285 6.15512 19.021 6.14181 19.0135C5.98413 18.9234 5.87421 18.804 5.82405 18.6286C5.81287 18.5874 5.80827 18.5489 5.80841 18.5063C5.8084 18.5012 5.8084 18.4961 5.80839 18.4909C5.80837 18.4738 5.8084 18.4568 5.80843 18.4397C5.80842 18.4274 5.80842 18.4151 5.80841 18.4027C5.8084 18.3688 5.80842 18.3349 5.80845 18.301C5.80848 18.2644 5.80847 18.2279 5.80847 18.1913C5.80846 18.1279 5.80848 18.0646 5.80852 18.0012C5.80855 17.9348 5.80857 17.8683 5.80858 17.8019C5.80858 17.7978 5.80858 17.7936 5.80858 17.7894C5.80858 17.7684 5.80859 17.7474 5.80859 17.7264C5.8086 17.5778 5.80864 17.4292 5.8087 17.2806C5.80875 17.1362 5.8088 16.9918 5.80882 16.8475C5.80882 16.843 5.80882 16.8386 5.80883 16.834C5.80883 16.7893 5.80884 16.7446 5.80885 16.6999C5.80886 16.6089 5.80888 16.5178 5.8089 16.4268C5.8089 16.4226 5.8089 16.4184 5.8089 16.4141C5.80896 16.1346 5.80905 15.855 5.80916 15.5755C5.80217 15.5728 5.80217 15.5728 5.79504 15.57C5.77715 15.5627 5.76106 15.5538 5.74431 15.5442C5.73757 15.5403 5.73082 15.5364 5.72387 15.5325C5.71656 15.5282 5.70926 15.524 5.70196 15.5198C5.69434 15.5154 5.68672 15.5111 5.67911 15.5067C5.65954 15.4955 5.63999 15.4842 5.62045 15.4729C5.60313 15.4629 5.58579 15.453 5.56846 15.443C5.53599 15.4243 5.50353 15.4055 5.47108 15.3868C5.43833 15.3678 5.40556 15.3489 5.3728 15.33C5.35966 15.3225 5.34653 15.3149 5.3334 15.3073C5.3269 15.3036 5.3204 15.2998 5.3137 15.296C5.24148 15.2543 5.16926 15.2126 5.09704 15.171C5.09054 15.1672 5.08404 15.1635 5.07734 15.1596C5.06422 15.152 5.0511 15.1445 5.03798 15.1369C5.005 15.1179 4.97203 15.0988 4.93904 15.0798C4.8757 15.0433 4.81242 15.0067 4.74932 14.9698C4.69672 14.9391 4.64392 14.9087 4.59098 14.8785C4.53207 14.845 4.47335 14.8111 4.41482 14.7768C4.35104 14.7395 4.28702 14.7026 4.223 14.6658C4.1901 14.6468 4.15721 14.6278 4.12432 14.6088C4.11119 14.6013 4.09806 14.5937 4.08493 14.5861C3.95361 14.5104 3.8223 14.4346 3.69099 14.3588C3.68449 14.3551 3.67799 14.3513 3.67129 14.3475C3.65817 14.3399 3.64505 14.3323 3.63193 14.3248C3.59232 14.3019 3.55271 14.2791 3.51308 14.2563C3.49342 14.2449 3.47378 14.2336 3.45413 14.2222C3.42807 14.2071 3.40194 14.1922 3.37577 14.1773C3.20758 14.0813 3.07753 13.9697 3.02023 13.7781C3.0083 13.7285 3.00131 13.681 3.00156 13.63C3.00153 13.6242 3.00151 13.6184 3.00149 13.6125C3.00144 13.5933 3.00147 13.5742 3.00149 13.555C3.00147 13.5411 3.00144 13.5271 3.00141 13.5132C3.00134 13.475 3.00134 13.4368 3.00135 13.3986C3.00136 13.3616 3.0013 13.3246 3.00125 13.2876C3.00113 13.2027 3.0011 13.1177 3.00109 13.0327C3.00109 12.9671 3.00106 12.9014 3.00102 12.8358C3.00101 12.8168 3.001 12.7979 3.00099 12.779C3.00099 12.7743 3.00098 12.7696 3.00098 12.7648C3.00091 12.6325 3.00086 12.5003 3.00086 12.368C3.00086 12.3631 3.00086 12.3581 3.00086 12.3529C3.00087 12.3277 3.00087 12.3024 3.00087 12.2772C3.00087 12.2722 3.00087 12.2671 3.00087 12.262C3.00087 12.2518 3.00087 12.2417 3.00087 12.2316C3.00088 12.0738 3.00079 11.916 3.00062 11.7583C3.00043 11.5809 3.00033 11.4036 3.00034 11.2262C3.00034 11.2073 3.00034 11.1884 3.00034 11.1695C3.00034 11.1648 3.00034 11.1601 3.00034 11.1553C3.00034 11.0805 3.00027 11.0056 3.00016 10.9308C3.00006 10.8555 3.00005 10.7802 3.00013 10.7049C3.00017 10.6642 3.00017 10.6234 3.00006 10.5826C2.99997 10.5453 2.99999 10.5079 3.00009 10.4706C3.00011 10.4571 3.00009 10.4436 3.00002 10.4302C2.99919 10.2527 3.0432 10.0969 3.16909 9.96714C3.21289 9.92334 3.25865 9.89154 3.3122 9.86039C3.31763 9.85723 3.32306 9.85408 3.32865 9.85082C3.36862 9.82762 3.40868 9.80457 3.44876 9.78156C3.4823 9.76229 3.51581 9.74297 3.54932 9.72365C3.55586 9.71988 3.56239 9.71612 3.56912 9.71223C3.61261 9.68714 3.65599 9.66188 3.69932 9.63653C3.7555 9.60367 3.81195 9.57129 3.86849 9.53906C3.92379 9.50754 3.97887 9.47566 4.03382 9.44352C4.0976 9.40623 4.16162 9.36934 4.22564 9.33246C4.25854 9.3135 4.29143 9.29452 4.32432 9.27555C4.33745 9.26797 4.35058 9.26039 4.36371 9.25282C4.37346 9.24719 4.37346 9.24719 4.38341 9.24146C5.38795 8.66191 5.38795 8.66191 5.40765 8.65055C5.42076 8.64298 5.43387 8.63542 5.44698 8.62785C5.4801 8.60874 5.51323 8.58964 5.54637 8.57058C5.55973 8.56289 5.57308 8.55521 5.58643 8.54752C5.59289 8.54381 5.59934 8.54009 5.606 8.53626C5.63839 8.51758 5.67068 8.49874 5.70281 8.4796C5.70899 8.47592 5.71517 8.47224 5.72153 8.46845C5.73323 8.46147 5.74491 8.45446 5.75658 8.44742C5.76432 8.4428 5.76432 8.4428 5.77222 8.43808C5.77674 8.43535 5.78126 8.43263 5.78592 8.42983C5.79703 8.42404 5.79703 8.42404 5.80916 8.42404C5.80915 8.41462 5.80915 8.41462 5.80913 8.40501C5.80883 8.12828 5.80855 7.85154 5.80839 7.5748C5.80838 7.57061 5.80838 7.56642 5.80838 7.5621C5.80832 7.47099 5.80827 7.37989 5.80823 7.28878C5.8082 7.2441 5.80818 7.19942 5.80816 7.15474C5.80815 7.15029 5.80815 7.14584 5.80815 7.14126C5.80807 6.99723 5.80794 6.8532 5.80777 6.70917C5.8076 6.56112 5.80749 6.41308 5.80745 6.26503C5.80744 6.2441 5.80744 6.22317 5.80743 6.20224C5.80743 6.19813 5.80743 6.19401 5.80743 6.18976C5.80741 6.12355 5.80732 6.05735 5.80721 5.99114C5.80711 5.92452 5.80707 5.8579 5.80709 5.79129C5.8071 5.75522 5.80709 5.71914 5.80699 5.68307C5.8069 5.65001 5.8069 5.61696 5.80696 5.5839C5.80697 5.57197 5.80694 5.56004 5.80689 5.54812C5.80609 5.37288 5.85858 5.2276 5.9816 5.09949C6.05754 5.0265 6.15464 4.97945 6.24556 4.92783C6.28815 4.90364 6.33053 4.87913 6.37279 4.85436C6.42512 4.82372 6.47767 4.79348 6.53036 4.76346C6.58928 4.72988 6.64799 4.69598 6.70652 4.66174C6.77031 4.62444 6.83432 4.58756 6.89835 4.55068C6.93125 4.53172 6.96414 4.51274 6.99703 4.49376C7.01016 4.48619 7.02329 4.47861 7.03642 4.47103C7.04292 4.46728 7.04942 4.46353 7.05612 4.45967C8.21823 3.78922 8.21823 3.78922 8.23793 3.77786C8.25105 3.77029 8.26417 3.76271 8.27729 3.75514C8.31027 3.73612 8.34324 3.7171 8.37623 3.6981C8.43957 3.6616 8.50285 3.625 8.56595 3.58809C8.62611 3.55291 8.6865 3.51817 8.74707 3.48372C8.77982 3.4651 8.81251 3.4464 8.84498 3.42729C8.90419 3.39256 8.96182 3.36053 9.02731 3.33922C9.03341 3.33718 9.0395 3.33515 9.04578 3.33305C9.25469 3.27614 9.43305 3.3568 9.60783 3.46101ZM9.15359 4.59833C9.14426 4.60378 9.14426 4.60378 9.13474 4.60934C9.12804 4.61332 9.12134 4.61731 9.11444 4.62141C9.10738 4.62556 9.10031 4.62969 9.09325 4.63383C9.07856 4.64243 9.06388 4.65105 9.04921 4.65969C9.01554 4.6795 8.98164 4.69891 8.94777 4.71838C8.89767 4.74725 8.84768 4.77631 8.79777 4.8055C8.74159 4.83836 8.68515 4.87074 8.6286 4.90297C8.5733 4.93449 8.51822 4.96637 8.46328 4.99851C8.3995 5.0358 8.33548 5.07269 8.27145 5.10957C8.23855 5.12853 8.20566 5.14751 8.17278 5.16648C8.15964 5.17406 8.14651 5.18164 8.13338 5.18921C8.12688 5.19296 8.12038 5.19671 8.11368 5.20057C7.26672 5.68921 7.26672 5.68921 7.24699 5.70059C7.23397 5.7081 7.22095 5.71561 7.20794 5.72312C7.17711 5.74092 7.14627 5.7587 7.11542 5.77645C7.10081 5.78486 7.0862 5.79328 7.0716 5.80169C7.06126 5.80764 7.05092 5.81359 7.04057 5.81953C7.03434 5.82313 7.0281 5.82672 7.02167 5.83042C7.01617 5.83359 7.01066 5.83676 7.00499 5.84002C6.99405 5.84648 6.98336 5.85337 6.97278 5.86042C6.97003 5.87925 6.97003 5.87925 6.97055 5.90195C6.97053 5.90629 6.9705 5.91063 6.97048 5.91511C6.97043 5.92981 6.97052 5.9445 6.9706 5.9592C6.97059 5.96979 6.97057 5.98037 6.97055 5.99096C6.97051 6.02016 6.97058 6.04936 6.97067 6.07856C6.97075 6.11001 6.97073 6.14146 6.97071 6.1729C6.9707 6.22743 6.97076 6.28195 6.97086 6.33647C6.97101 6.4153 6.97106 6.49413 6.97108 6.57297C6.97112 6.70085 6.97124 6.82874 6.97141 6.95663C6.97158 7.08089 6.97171 7.20515 6.97179 7.32941C6.97179 7.33706 6.97179 7.34472 6.9718 7.3526C6.97182 7.391 6.97185 7.4294 6.97187 7.4678C6.97206 7.78654 6.97238 8.10529 6.97278 8.42404C6.97987 8.42808 6.97987 8.42808 6.9871 8.43221C7.00504 8.44246 7.02298 8.4527 7.04092 8.46295C7.0486 8.46734 7.05629 8.47173 7.06398 8.47612C7.13629 8.51741 7.20845 8.55898 7.28055 8.60065C7.30674 8.61577 7.33293 8.63088 7.35912 8.64599C7.37881 8.65735 7.3985 8.66871 7.41819 8.68007C7.4446 8.69531 7.47102 8.71054 7.49745 8.72576C7.56079 8.76226 7.62407 8.79886 7.68717 8.83578C7.73976 8.86653 7.79257 8.8969 7.8455 8.92706C7.90442 8.96064 7.96313 8.99454 8.02167 9.02878C8.08545 9.06608 8.14946 9.10296 8.21349 9.13984C8.24639 9.1588 8.27928 9.17778 8.31217 9.19676C8.3253 9.20433 8.33843 9.21191 8.35156 9.21949C8.90307 9.53766 8.90307 9.53767 8.9228 9.54905C8.93582 9.55656 8.94885 9.56407 8.96187 9.57157C8.9927 9.58933 9.0235 9.60713 9.05422 9.62507C9.06876 9.63355 9.08331 9.64202 9.09786 9.65048C9.10815 9.65647 9.11842 9.6625 9.12869 9.66852C9.13491 9.67214 9.14112 9.67575 9.14753 9.67947C9.15574 9.68427 9.15574 9.68427 9.16411 9.68916C9.18278 9.69882 9.18278 9.69882 9.20307 9.70282C9.21687 9.69779 9.21687 9.69779 9.23082 9.68916C9.23628 9.68602 9.24174 9.68288 9.24736 9.67965C9.25324 9.67617 9.25913 9.67269 9.26519 9.6691C9.27137 9.66553 9.27755 9.66195 9.28391 9.65827C9.30347 9.64693 9.32297 9.63548 9.34246 9.62403C9.35446 9.61704 9.36647 9.61005 9.37847 9.60308C9.40253 9.58908 9.42656 9.57505 9.45058 9.56098C9.50876 9.52696 9.5672 9.49337 9.6256 9.45973C9.6585 9.44078 9.69139 9.4218 9.72428 9.40282C9.73741 9.39524 9.75054 9.38767 9.76367 9.38009C9.77342 9.37447 9.77342 9.37447 9.78337 9.36873C10.7879 8.78919 10.7879 8.78919 10.8076 8.77782C10.8207 8.77025 10.8339 8.76268 10.847 8.75511C10.8799 8.73608 10.9129 8.71707 10.9459 8.69806C11.0151 8.65817 11.0843 8.61811 11.1532 8.57774C11.187 8.55806 11.2208 8.53855 11.2547 8.51923C11.2585 8.51704 11.2624 8.51485 11.2663 8.51259C11.2851 8.5019 11.3039 8.49122 11.3227 8.48057C11.3329 8.47478 11.3329 8.47478 11.3433 8.46887C11.3492 8.46548 11.3552 8.46208 11.3614 8.45859C11.3672 8.45518 11.3729 8.45178 11.3788 8.44828C11.3882 8.44426 11.3882 8.44426 11.3978 8.44017C11.4178 8.42156 11.418 8.41775 11.4197 8.39162C11.4198 8.3776 11.4198 8.36358 11.4195 8.34957C11.4196 8.34185 11.4196 8.33413 11.4196 8.32618C11.4197 8.30474 11.4196 8.28331 11.4194 8.26187C11.4192 8.23876 11.4193 8.21565 11.4193 8.19254C11.4193 8.1525 11.4192 8.11245 11.419 8.07241C11.4187 8.01451 11.4186 7.95661 11.4186 7.89872C11.4185 7.80478 11.4183 7.71085 11.4179 7.61692C11.4176 7.52567 11.4173 7.43441 11.4172 7.34316C11.4172 7.33753 11.4172 7.33191 11.4171 7.32612C11.4171 7.29791 11.4171 7.26969 11.417 7.24148C11.4166 7.00739 11.416 6.77329 11.4152 6.5392C11.3923 6.54811 11.3716 6.55829 11.3503 6.57052C11.3436 6.57439 11.3368 6.57826 11.3299 6.58224C11.3226 6.58646 11.3153 6.59067 11.308 6.59488C11.3004 6.59926 11.2927 6.60363 11.2851 6.60801C11.2656 6.61925 11.246 6.63051 11.2265 6.64178C11.2091 6.65177 11.1918 6.66175 11.1745 6.67173C11.142 6.69044 11.1096 6.70918 11.0771 6.72793C11.0444 6.74686 11.0116 6.76575 10.9788 6.78465C10.9723 6.7884 10.9658 6.79215 10.9591 6.79601C10.9262 6.81503 10.8932 6.83405 10.8602 6.85305C10.7969 6.88955 10.7336 6.92615 10.6705 6.96306C10.6179 6.99382 10.5651 7.02418 10.5122 7.05435C10.4567 7.08595 10.4014 7.11771 10.3462 7.1498C10.3403 7.15327 10.3343 7.15674 10.3281 7.16031C10.3226 7.16356 10.317 7.16681 10.3113 7.17016C10.3064 7.17297 10.3016 7.17578 10.2966 7.17868C10.2893 7.18314 10.2893 7.18314 10.2819 7.18768C10.2756 7.19082 10.2693 7.19396 10.2629 7.19719C10.2431 7.21065 10.2431 7.21065 10.242 7.23466C10.2423 7.244 10.2428 7.25333 10.2435 7.26265C10.2438 7.27031 10.2438 7.27031 10.2441 7.27813C10.2446 7.28923 10.2451 7.30032 10.2457 7.31142C10.2469 7.33512 10.2474 7.35883 10.248 7.38256C10.249 7.4267 10.2504 7.47079 10.2528 7.51488C10.2636 7.71511 10.2636 7.71511 10.2321 7.76229C10.195 7.80348 10.1426 7.82261 10.0914 7.84016C10.0572 7.85299 10.0272 7.87189 9.99625 7.89109C9.98436 7.89808 9.97247 7.90504 9.96055 7.91197C9.95462 7.91543 9.9487 7.91889 9.94259 7.92246C9.89071 7.95269 9.83863 7.9826 9.7866 8.01258C9.75369 8.03153 9.72081 8.05052 9.68792 8.06949C9.67478 8.07707 9.66165 8.08465 9.64852 8.09222C9.63877 8.09785 9.63877 8.09785 9.62883 8.10358C9.56973 8.13767 9.56973 8.13767 9.55002 8.14905C9.53694 8.15659 9.52387 8.16414 9.51079 8.17169C9.47715 8.1911 9.44349 8.2105 9.40982 8.22986C9.40296 8.23381 9.39611 8.23775 9.38905 8.24182C9.37559 8.24956 9.36213 8.25729 9.34866 8.265C9.32045 8.28122 9.29241 8.29754 9.26496 8.31502C9.26075 8.31767 9.25654 8.32032 9.25221 8.32306C9.24154 8.32986 9.23095 8.3368 9.22038 8.34376C9.20307 8.35131 9.20307 8.35131 9.18887 8.34682C9.17229 8.33896 9.15629 8.33056 9.14029 8.32158C9.13408 8.3181 9.12787 8.31462 9.12148 8.31104C9.11162 8.30547 9.11162 8.30547 9.10156 8.29979C9.09473 8.29595 9.0879 8.29211 9.08086 8.28816C9.03971 8.26495 8.99877 8.24141 8.95813 8.21731C8.91988 8.19463 8.88138 8.17238 8.84285 8.15017C8.83278 8.14437 8.83278 8.14437 8.82251 8.13846C8.80875 8.13053 8.79499 8.1226 8.78123 8.11468C8.74809 8.09559 8.71498 8.07648 8.68186 8.05737C8.66873 8.0498 8.6556 8.04222 8.64247 8.03465C8.61621 8.01949 8.58994 8.00434 8.56368 7.98919C8.55393 7.98356 8.55393 7.98356 8.54398 7.97782C8.53087 7.97026 8.51776 7.96269 8.50464 7.95513C8.47153 7.93602 8.4384 7.91692 8.40525 7.89786C8.3919 7.89017 8.37855 7.88248 8.3652 7.8748C8.35874 7.87108 8.35228 7.86737 8.34563 7.86354C8.31323 7.84486 8.28095 7.82602 8.24882 7.80688C8.24264 7.8032 8.23646 7.79952 8.2301 7.79573C8.2184 7.78875 8.20671 7.78174 8.19505 7.7747C8.18988 7.77162 8.18472 7.76853 8.1794 7.76535C8.17262 7.76127 8.17262 7.76127 8.16571 7.7571C8.15489 7.75038 8.15489 7.75038 8.14247 7.75131C8.14547 7.14832 8.14547 7.14832 8.14853 6.53314C8.18453 6.51314 8.22053 6.49314 8.25762 6.47254C8.28092 6.45911 8.30416 6.44564 8.32732 6.43201C8.33977 6.42471 8.35222 6.41742 8.36468 6.41013C8.37098 6.40644 8.37729 6.40275 8.38379 6.39894C8.41616 6.38005 8.44863 6.36133 8.48111 6.34261C8.48765 6.33884 8.49419 6.33507 8.50093 6.33118C8.51421 6.32354 8.52748 6.31589 8.54076 6.30824C8.57366 6.28928 8.60655 6.2703 8.63944 6.25132C8.65257 6.24375 8.6657 6.23617 8.67883 6.2286C8.68533 6.22485 8.69183 6.2211 8.69853 6.21723C8.80686 6.15473 8.80686 6.15473 8.91519 6.09223C8.9217 6.08848 8.92821 6.08472 8.93492 6.08085C8.94794 6.07334 8.96097 6.06585 8.974 6.05837C9.00489 6.04063 9.03568 6.02275 9.06618 6.00436C9.08064 5.99566 9.09514 5.98704 9.10965 5.97842C9.11991 5.97229 9.13009 5.96603 9.14028 5.95978C9.14647 5.95611 9.15267 5.95243 9.15906 5.94865C9.16722 5.94371 9.16722 5.94371 9.17555 5.93867C9.19095 5.93314 9.19095 5.93315 9.20616 5.93719C9.21114 5.93985 9.21612 5.94252 9.22125 5.94527C9.22622 5.94785 9.23118 5.95043 9.23629 5.95308C9.24156 5.95604 9.24682 5.95899 9.25224 5.96203C9.25823 5.96538 9.26422 5.96873 9.27039 5.97219C9.2768 5.9758 9.28321 5.97942 9.28981 5.98314C9.29986 5.9888 9.29987 5.9888 9.31012 5.99457C9.35582 6.02035 9.40131 6.04648 9.44663 6.07292C9.45254 6.07636 9.45846 6.0798 9.46455 6.08335C9.4952 6.10127 9.52565 6.11945 9.55591 6.13802C9.56199 6.14172 9.56806 6.14541 9.57432 6.14922C9.58589 6.15626 9.59741 6.16338 9.60888 6.17059C9.61405 6.17372 9.61922 6.17686 9.62454 6.18009C9.63129 6.18428 9.63129 6.18428 9.63818 6.18855C9.65572 6.19537 9.66403 6.19345 9.68186 6.18769C9.69358 6.1819 9.70509 6.17565 9.7164 6.16908C9.72314 6.16519 9.72989 6.16131 9.73684 6.1573C9.74414 6.15304 9.75145 6.14877 9.75875 6.14451C9.76636 6.1401 9.77398 6.1357 9.7816 6.1313C9.79729 6.12224 9.81296 6.11315 9.82861 6.10405C9.85629 6.08796 9.88403 6.07199 9.91177 6.05602C9.93774 6.04106 9.96368 6.02607 9.98962 6.01108C10.0224 5.99216 10.0551 5.97326 10.0879 5.95436C10.101 5.94678 10.1142 5.93921 10.1273 5.93163C10.5212 5.70436 10.5212 5.70436 10.541 5.69298C10.554 5.68546 10.567 5.67794 10.5801 5.67041C10.6107 5.65269 10.6415 5.635 10.6722 5.61742C10.6867 5.60914 10.7012 5.60084 10.7157 5.59254C10.7259 5.58671 10.7361 5.5809 10.7463 5.5751C10.7525 5.57154 10.7587 5.56799 10.7651 5.56433C10.7705 5.56122 10.776 5.55812 10.7816 5.55492C10.7979 5.54471 10.8125 5.53331 10.8273 5.52103C10.7942 5.49724 10.7596 5.47696 10.7239 5.45739C10.6802 5.43341 10.637 5.40872 10.594 5.38353C10.5428 5.35356 10.4916 5.32374 10.4402 5.29413C10.4336 5.29036 10.4271 5.28659 10.4204 5.28271C10.4071 5.27506 10.3938 5.26741 10.3805 5.25976C10.3476 5.24081 10.3147 5.22183 10.2819 5.20285C10.2687 5.19527 10.2556 5.1877 10.2425 5.18012C10.0061 5.04376 9.76973 4.90739 9.53337 4.77103C9.52686 4.76728 9.52035 4.76352 9.51365 4.75965C9.5006 4.75213 9.48756 4.7446 9.47452 4.73707C9.44398 4.71945 9.41343 4.70183 9.38285 4.68425C9.37205 4.67805 9.36126 4.67184 9.35047 4.66562C9.33694 4.65784 9.32342 4.65007 9.30989 4.6423C9.27917 4.62462 9.24886 4.6068 9.21957 4.5868C9.19374 4.57403 9.17595 4.58513 9.15359 4.59833ZM14.7698 4.59589C14.7643 4.59901 14.7589 4.60212 14.7532 4.60533C14.7473 4.60876 14.7413 4.6122 14.7352 4.61573C14.7259 4.62105 14.7259 4.62105 14.7164 4.62648C14.6606 4.65849 14.605 4.69096 14.5495 4.72347C14.4913 4.7575 14.4328 4.79108 14.3744 4.82472C14.3415 4.84368 14.3087 4.86266 14.2758 4.88164C14.2626 4.88921 14.2495 4.89679 14.2364 4.90436C14.2299 4.90811 14.2234 4.91186 14.2167 4.91573C13.2121 5.49527 13.2121 5.49527 13.1924 5.50663C13.1793 5.5142 13.1662 5.52178 13.1531 5.52935C13.1201 5.54837 13.0871 5.56739 13.0541 5.58639C12.9849 5.62629 12.9158 5.66635 12.8468 5.70671C12.8131 5.7264 12.7793 5.7459 12.7454 5.76522C12.7415 5.76742 12.7377 5.76961 12.7337 5.77187C12.7149 5.78256 12.6962 5.79323 12.6774 5.80388C12.6672 5.80967 12.6672 5.80967 12.6568 5.81558C12.6508 5.81898 12.6448 5.82237 12.6386 5.82587C12.6329 5.82927 12.6271 5.83267 12.6212 5.83618C12.615 5.83951 12.6087 5.84284 12.6023 5.84627C12.5832 5.85888 12.5832 5.85888 12.5802 5.87977C12.5801 5.8875 12.5801 5.89523 12.58 5.9032C12.5799 5.90753 12.5798 5.91186 12.5797 5.91633C12.5795 5.93092 12.5795 5.94549 12.5795 5.96009C12.5794 5.97062 12.5793 5.98116 12.5791 5.99169C12.5787 6.0207 12.5786 6.04971 12.5785 6.07872C12.5784 6.10999 12.578 6.14126 12.5777 6.17252C12.577 6.24807 12.5766 6.32362 12.5763 6.39917C12.5761 6.43475 12.5759 6.47033 12.5758 6.50591C12.5751 6.6242 12.5746 6.74249 12.5743 6.86078C12.5743 6.89148 12.5742 6.92218 12.5741 6.95288C12.5741 6.96051 12.5741 6.96814 12.5741 6.97601C12.5738 7.09958 12.5729 7.22314 12.5717 7.34671C12.5705 7.47359 12.5698 7.60046 12.5697 7.72734C12.5696 7.79858 12.5693 7.8698 12.5684 7.94103C12.5676 8.00172 12.5673 8.06238 12.5676 8.12306C12.5678 8.15402 12.5677 8.18493 12.567 8.21589C12.5592 8.33505 12.5592 8.33505 12.5993 8.44212C12.6336 8.47119 12.6712 8.48835 12.7135 8.50285C12.7355 8.51074 12.7537 8.52143 12.7735 8.53386C12.7851 8.54056 12.7967 8.54726 12.8083 8.55396C12.8216 8.56159 12.8348 8.56922 12.8481 8.57685C12.8546 8.58064 12.8612 8.58443 12.868 8.58833C12.9009 8.60729 12.9338 8.62627 12.9667 8.64525C12.9798 8.65282 12.9929 8.6604 13.0061 8.66797C13.2424 8.80434 13.4788 8.9407 13.7152 9.07706C13.7217 9.08081 13.7282 9.08456 13.7349 9.08843C13.748 9.096 13.7611 9.10357 13.7742 9.11114C13.8072 9.13016 13.8402 9.14918 13.8732 9.16818C13.9365 9.20468 13.9998 9.24128 14.0629 9.2782C14.1155 9.30896 14.1683 9.33932 14.2212 9.36948C14.2801 9.40306 14.3388 9.43696 14.3974 9.4712C14.4678 9.51236 14.5384 9.55303 14.6091 9.59373C14.6345 9.60838 14.66 9.62304 14.6854 9.6377C14.6956 9.64358 14.7058 9.64946 14.716 9.65534C14.7222 9.65891 14.7284 9.66248 14.7348 9.66617C14.7429 9.67087 14.7429 9.67087 14.7513 9.67567C14.7619 9.68188 14.7725 9.6883 14.7829 9.6949C14.7964 9.70405 14.7964 9.70405 14.8113 9.70248C14.8328 9.69479 14.8515 9.68363 14.8708 9.67175C14.8801 9.6662 14.8893 9.66065 14.8986 9.65511C14.9036 9.65207 14.9087 9.64904 14.9139 9.64591C14.9443 9.62781 14.975 9.61023 15.0057 9.59259C15.0193 9.58474 15.0329 9.57689 15.0466 9.56903C15.0568 9.56312 15.0568 9.56312 15.0673 9.55709C15.1004 9.53801 15.1335 9.5189 15.1667 9.49979C15.1798 9.49221 15.1929 9.48463 15.2061 9.47706C15.2158 9.47143 15.2158 9.47143 15.2258 9.4657C15.4424 9.3407 15.4424 9.3407 15.4621 9.32933C15.4752 9.32176 15.4884 9.31419 15.5015 9.30662C15.5345 9.28759 15.5674 9.26858 15.6004 9.24958C15.6638 9.21308 15.727 9.17648 15.7901 9.13956C15.8463 9.1067 15.9028 9.07432 15.9593 9.0421C16.0146 9.0106 16.0696 8.97875 16.1245 8.94662C16.1696 8.92023 16.2149 8.89406 16.2602 8.86797C16.3201 8.83346 16.3799 8.79865 16.4394 8.76343C16.4194 8.74672 16.3994 8.73295 16.3766 8.72039C16.3673 8.71523 16.3673 8.71523 16.3578 8.70997C16.3512 8.70636 16.3446 8.70275 16.3379 8.69903C16.2938 8.6746 16.2498 8.65016 16.2064 8.62441C16.1642 8.59935 16.1217 8.57469 16.0792 8.55017C16.0691 8.54437 16.0691 8.54437 16.0588 8.53845C16.0451 8.53053 16.0313 8.5226 16.0175 8.51468C15.9844 8.49559 15.9513 8.47648 15.9182 8.45737C15.905 8.44979 15.8919 8.44222 15.8788 8.43464C15.8 8.38919 15.7212 8.34373 15.6424 8.29828C15.6359 8.29453 15.6294 8.29077 15.6227 8.28691C15.6096 8.27936 15.5966 8.27182 15.5835 8.26427C15.5498 8.24485 15.5162 8.22546 15.4825 8.20609C15.4132 8.16622 15.344 8.12622 15.2758 8.08464C15.2714 8.08716 15.267 8.08968 15.2625 8.09227C15.2212 8.11598 15.1797 8.13939 15.1381 8.16259C15.0856 8.19189 15.0331 8.22139 14.9812 8.25175C14.9688 8.25897 14.9565 8.26615 14.9441 8.27329C14.9183 8.2882 14.893 8.30317 14.8685 8.3202C14.8629 8.32392 14.8629 8.32392 14.8572 8.32772C14.8479 8.33402 14.8388 8.34061 14.8296 8.34724C14.7939 8.35432 14.7667 8.33262 14.7364 8.31495C14.7308 8.31179 14.7252 8.30864 14.7194 8.30539C14.7025 8.29574 14.6857 8.28587 14.6689 8.27593C14.6562 8.26842 14.6434 8.2609 14.6306 8.25339C14.6241 8.24955 14.6175 8.24571 14.6108 8.24175C14.5782 8.22268 14.5456 8.20385 14.5129 8.18502C14.5031 8.17937 14.5031 8.17937 14.4931 8.1736C14.4798 8.16595 14.4665 8.1583 14.4532 8.15065C14.4203 8.13169 14.3874 8.11271 14.3545 8.09374C14.3414 8.08616 14.3283 8.07858 14.3152 8.07101C14.0788 7.93465 14.0788 7.93465 14.0591 7.92327C14.046 7.91574 14.033 7.90822 14.02 7.9007C13.9893 7.88304 13.9587 7.86538 13.9281 7.84771C13.9173 7.84145 13.9064 7.8352 13.8956 7.82894C13.882 7.82109 13.8684 7.81324 13.8548 7.80539C13.8486 7.80183 13.8425 7.79828 13.8361 7.79461C13.8307 7.79151 13.8254 7.78841 13.8198 7.78521C13.8001 7.77387 13.7804 7.7626 13.7606 7.75131C13.7606 7.34932 13.7606 6.94732 13.7606 6.53314C13.8166 6.50114 13.8726 6.46914 13.9303 6.43617C13.9849 6.40436 13.9849 6.40436 14.0395 6.37249C14.0973 6.33869 14.1554 6.30531 14.2134 6.27188C14.2463 6.25292 14.2792 6.23394 14.3121 6.21496C14.3253 6.20739 14.3384 6.19981 14.3515 6.19223C14.358 6.18848 14.3645 6.18473 14.3712 6.18087C14.4303 6.14678 14.4303 6.14678 14.45 6.13541C14.4631 6.12786 14.4762 6.12032 14.4893 6.11277C14.5229 6.09335 14.5565 6.07396 14.5902 6.05459C14.5971 6.05065 14.6039 6.0467 14.611 6.04264C14.6245 6.03489 14.6379 6.02716 14.6514 6.01945C14.6796 6.00327 14.7075 5.98699 14.7349 5.96944C14.7411 5.96546 14.7411 5.96546 14.7475 5.9614C14.7581 5.9546 14.7686 5.94766 14.7791 5.9407C14.8025 5.93081 14.8101 5.93597 14.8333 5.94527C14.8443 5.95092 14.8551 5.9569 14.8658 5.96314C14.872 5.96673 14.8782 5.97033 14.8845 5.97403C14.8911 5.97791 14.8977 5.9818 14.9045 5.9858C14.9116 5.98989 14.9186 5.99398 14.9256 5.99806C14.9402 6.00654 14.9547 6.01503 14.9693 6.02354C15.0027 6.04305 15.0362 6.06233 15.0697 6.08163C15.0828 6.0892 15.096 6.09678 15.1091 6.10436C15.1188 6.10998 15.1188 6.10998 15.1288 6.11572C15.2535 6.18769 15.3783 6.25966 15.503 6.33163C15.5095 6.33538 15.516 6.33913 15.5227 6.343C15.5358 6.35054 15.5489 6.35807 15.5619 6.36561C15.5923 6.38311 15.6226 6.40061 15.6529 6.41809C15.6635 6.42421 15.6741 6.43033 15.6847 6.43644C15.698 6.44406 15.7112 6.45168 15.7244 6.45929C15.7362 6.46609 15.7479 6.47299 15.7595 6.48003C15.7783 6.4911 15.7783 6.4911 15.798 6.49778C15.8204 6.50711 15.8347 6.51544 15.8515 6.53314C15.8629 6.56593 15.8599 6.60221 15.8587 6.63641C15.858 6.65423 15.8578 6.672 15.8577 6.68983C15.8574 6.72764 15.8566 6.76542 15.8557 6.80321C15.8547 6.84705 15.854 6.89087 15.8537 6.93471C15.8535 6.95224 15.8529 6.96974 15.8523 6.98726C15.8492 7.04052 15.8492 7.04052 15.8691 7.08753C15.8833 7.09716 15.8961 7.10312 15.9121 7.10889C15.9202 7.11337 15.9283 7.11796 15.9362 7.12272C15.9444 7.12722 15.9527 7.1317 15.961 7.13617C16.0044 7.15998 16.0474 7.18458 16.0901 7.20965C16.1437 7.24106 16.1975 7.27209 16.2515 7.30283C16.3104 7.3364 16.3691 7.37031 16.4277 7.40455C16.4914 7.44185 16.5555 7.47873 16.6195 7.51561C16.6589 7.53831 16.6983 7.56104 16.7376 7.58377C16.7681 7.60133 16.7985 7.61889 16.829 7.63642C16.8397 7.64258 16.8504 7.64875 16.8611 7.65491C16.8745 7.66261 16.8878 7.67031 16.9012 7.678C16.9355 7.69778 16.9696 7.71789 17.0033 7.73878C17.0147 7.74622 17.0147 7.74622 17.0273 7.74525C17.0303 7.50648 17.0327 7.26771 17.0341 7.02893C17.0342 7.00072 17.0344 6.9725 17.0346 6.94429C17.0346 6.93868 17.0347 6.93306 17.0347 6.92727C17.0353 6.83642 17.0363 6.74557 17.0375 6.65472C17.0388 6.56146 17.0395 6.46819 17.0398 6.37491C17.04 6.31738 17.0406 6.25988 17.0416 6.20236C17.0424 6.16287 17.0426 6.1234 17.0424 6.08391C17.0423 6.06114 17.0424 6.03842 17.0432 6.01565C17.0491 5.92484 17.0491 5.92484 17.0141 5.84551C16.9822 5.8199 16.9474 5.8031 16.9096 5.78806C16.889 5.7796 16.8709 5.76892 16.852 5.75725C16.8402 5.75047 16.8284 5.7437 16.8167 5.73693C16.8033 5.72925 16.7899 5.72156 16.7766 5.71388C16.7666 5.70814 16.7666 5.70814 16.7564 5.70228C16.7235 5.68331 16.6905 5.66429 16.6576 5.64527C16.6444 5.63769 16.6313 5.63012 16.6182 5.62254C16.1848 5.37254 16.1848 5.37254 15.7515 5.12254C15.745 5.11879 15.7385 5.11504 15.7318 5.11118C15.7187 5.10361 15.7056 5.09604 15.6924 5.08847C15.6595 5.06944 15.6265 5.05042 15.5935 5.03142C15.5302 4.99492 15.4669 4.95832 15.4038 4.92141C15.3512 4.89065 15.2984 4.86029 15.2455 4.83012C15.1866 4.7966 15.128 4.76275 15.0695 4.72855C15.0231 4.70139 14.9765 4.67442 14.9299 4.64755C14.9233 4.64374 14.9167 4.63994 14.9099 4.63602C14.8978 4.62901 14.8856 4.62202 14.8734 4.61504C14.8637 4.6094 14.854 4.60371 14.8443 4.59791C14.8137 4.57963 14.8005 4.57829 14.7698 4.59589ZM11.9675 9.45284C11.9612 9.45647 11.9549 9.46011 11.9484 9.46385C11.9416 9.46783 11.9347 9.47182 11.9277 9.47592C11.9205 9.48007 11.9134 9.48421 11.9062 9.48835C11.8913 9.49697 11.8764 9.5056 11.8616 9.51423C11.8279 9.53371 11.7943 9.55311 11.7606 9.57251C11.7475 9.58009 11.7344 9.58766 11.7212 9.59524C10.697 10.1861 10.697 10.1861 10.6773 10.1975C10.6642 10.2051 10.6511 10.2127 10.6379 10.2202C10.605 10.2392 10.572 10.2583 10.539 10.2773C10.4757 10.3138 10.4124 10.3504 10.3493 10.3873C10.2931 10.4201 10.2366 10.4525 10.1801 10.4847C10.1249 10.5162 10.0699 10.548 10.0151 10.5801C9.98259 10.5991 9.95005 10.618 9.91741 10.6368C9.912 10.6399 9.912 10.6399 9.90647 10.643C9.88893 10.6531 9.87138 10.6632 9.85382 10.6732C9.84754 10.6768 9.84126 10.6804 9.83479 10.6841C9.82924 10.6873 9.82369 10.6905 9.81798 10.6937C9.81306 10.6967 9.80814 10.6997 9.80307 10.7028C9.7967 10.7063 9.7967 10.7063 9.79021 10.7098C9.77701 10.7206 9.77701 10.7206 9.77575 10.7396C9.77573 10.7473 9.77571 10.7551 9.77569 10.7631C9.77564 10.7674 9.7756 10.7717 9.77556 10.7762C9.77544 10.7908 9.77549 10.8054 9.77554 10.82C9.77549 10.8306 9.77543 10.8411 9.77536 10.8516C9.7752 10.8807 9.77519 10.9097 9.77521 10.9388C9.7752 10.9701 9.77506 11.0014 9.77493 11.0327C9.77471 11.094 9.77462 11.1554 9.77458 11.2167C9.77455 11.2666 9.77449 11.3164 9.7744 11.3663C9.77415 11.5075 9.77401 11.6487 9.774 11.79C9.774 11.7976 9.774 11.8052 9.774 11.8131C9.774 11.8207 9.774 11.8283 9.774 11.8362C9.77398 11.9598 9.7737 12.0835 9.7733 12.2072C9.7729 12.334 9.7727 12.4609 9.77271 12.5878C9.77271 12.6591 9.77262 12.7303 9.77232 12.8016C9.77206 12.8623 9.77199 12.923 9.77216 12.9836C9.77224 13.0146 9.77224 13.0456 9.772 13.0766C9.77178 13.1049 9.77181 13.1332 9.77204 13.1616C9.77208 13.1719 9.77203 13.1821 9.77188 13.1924C9.76919 13.246 9.76919 13.246 9.79083 13.2925C9.80474 13.3019 9.81781 13.3086 9.83337 13.3149C9.84163 13.3199 9.84163 13.3199 9.85005 13.3249C9.85699 13.3288 9.85699 13.3288 9.86407 13.3327C9.86944 13.3357 9.8748 13.3387 9.88032 13.3418C9.88595 13.3449 9.89158 13.3481 9.89738 13.3513C9.9464 13.3787 9.99514 13.4066 10.0436 13.435C10.0966 13.466 10.1497 13.4966 10.2031 13.527C10.262 13.5606 10.3207 13.5945 10.3792 13.6287C10.443 13.666 10.507 13.7029 10.571 13.7398C10.6039 13.7588 10.6368 13.7777 10.6697 13.7967C10.6829 13.8043 10.696 13.8119 10.7091 13.8195C10.998 13.9861 11.2869 14.1528 11.5758 14.3194C11.5823 14.3232 11.5888 14.327 11.5955 14.3308C11.6086 14.3384 11.6217 14.346 11.6348 14.3535C11.6678 14.3726 11.7008 14.3916 11.7338 14.4106C11.7404 14.4144 11.7469 14.4182 11.7537 14.4221C11.7668 14.4296 11.7799 14.4371 11.7931 14.4446C11.8265 14.4636 11.8591 14.4833 11.8912 14.5044C11.8977 14.5085 11.9041 14.5126 11.9107 14.5169C11.923 14.5247 11.935 14.5327 11.9469 14.541C11.964 14.5518 11.9773 14.5591 11.997 14.5634C12.0245 14.5563 12.0461 14.5424 12.0697 14.527C12.0808 14.5207 12.0919 14.5144 12.1031 14.5081C12.1145 14.5014 12.1258 14.4947 12.1371 14.488C12.1499 14.4805 12.1627 14.473 12.1755 14.4655C12.182 14.4616 12.1886 14.4578 12.1953 14.4538C12.2278 14.4348 12.2605 14.4159 12.2932 14.3971C12.2997 14.3933 12.3063 14.3896 12.313 14.3857C12.3263 14.378 12.3396 14.3704 12.3529 14.3627C12.3858 14.3438 12.4186 14.3248 12.4515 14.3058C12.4647 14.2982 12.4778 14.2907 12.4909 14.2831C12.5007 14.2775 12.5007 14.2775 12.5106 14.2717C13.2 13.874 13.2 13.874 13.2197 13.8626C13.2328 13.8551 13.246 13.8475 13.2591 13.8399C13.292 13.8209 13.325 13.8019 13.358 13.7829C13.4214 13.7464 13.4846 13.7098 13.5477 13.6729C13.6039 13.64 13.6604 13.6076 13.7169 13.5754C13.7722 13.5439 13.8272 13.512 13.8822 13.4799C13.9268 13.4538 13.9715 13.4279 14.0163 13.402C14.0222 13.3986 14.0281 13.3952 14.0341 13.3917C14.0964 13.3558 14.1588 13.3203 14.2212 13.2846C14.2212 12.4366 14.2212 11.5886 14.2212 10.7149C14.1462 10.6729 14.1462 10.6729 14.0697 10.6301C14.0186 10.6002 14.0186 10.6002 13.9941 10.5857C13.96 10.5655 13.9256 10.5457 13.8913 10.5259C13.8812 10.5201 13.8812 10.5201 13.871 10.5142C13.8572 10.5063 13.8434 10.4983 13.8297 10.4904C13.7965 10.4713 13.7634 10.4522 13.7303 10.4331C13.7172 10.4255 13.704 10.418 13.6909 10.4104C13.6647 10.3952 13.6384 10.3801 13.6121 10.3649C13.6056 10.3612 13.5991 10.3574 13.5924 10.3536C13.5793 10.346 13.5662 10.3384 13.5531 10.3309C13.5201 10.3118 13.4871 10.2928 13.4541 10.2738C13.3908 10.2373 13.3275 10.2007 13.2644 10.1638C13.2118 10.133 13.159 10.1027 13.1061 10.0725C13.0472 10.0389 12.9884 10.005 12.9299 9.97079C12.8661 9.93349 12.8021 9.89661 12.7381 9.85973C12.7052 9.84077 12.6723 9.82179 12.6394 9.80281C12.6263 9.79524 12.6131 9.78766 12.6 9.78009C12.3637 9.64372 12.3637 9.64372 12.3439 9.63235C12.3309 9.62481 12.3178 9.61727 12.3047 9.60973C12.271 9.59027 12.2373 9.5708 12.2035 9.55132C12.1706 9.53233 12.1377 9.51336 12.1048 9.49439C12.0942 9.48825 12.0835 9.48211 12.0729 9.47597C12.0606 9.46887 12.0483 9.46179 12.036 9.45471C12.0296 9.45103 12.0232 9.44735 12.0167 9.44356C11.9945 9.43149 11.989 9.44034 11.9675 9.45284ZM17.5933 9.44053C17.5881 9.44364 17.5829 9.44675 17.5775 9.44995C17.5715 9.4534 17.5656 9.45685 17.5594 9.4604C17.5499 9.46621 17.5499 9.46621 17.5401 9.47214C17.5334 9.47605 17.5267 9.47996 17.5199 9.484C17.5059 9.49219 17.4919 9.50043 17.478 9.50876C17.459 9.52012 17.4399 9.5313 17.4208 9.5424C17.3968 9.55629 17.3729 9.57024 17.349 9.58426C17.3108 9.60665 17.2725 9.62881 17.2341 9.65092C17.2243 9.65658 17.2243 9.65658 17.2142 9.66235C17.201 9.67 17.1877 9.67765 17.1744 9.68529C17.1415 9.70425 17.1086 9.72323 17.0757 9.74221C17.0626 9.74978 17.0495 9.75736 17.0363 9.76494C17.0298 9.76869 17.0233 9.77244 17.0167 9.7763C16.9576 9.81039 16.9576 9.81039 16.9379 9.82176C16.9247 9.82933 16.9116 9.8369 16.8985 9.84447C16.8655 9.86349 16.8325 9.88251 16.7996 9.90151C16.7362 9.93801 16.6729 9.97461 16.6098 10.0115C16.5537 10.0444 16.4972 10.0768 16.4407 10.109C16.3854 10.1405 16.3303 10.1724 16.2753 10.2045C16.2116 10.2418 16.1475 10.2787 16.0835 10.3156C16.0506 10.3345 16.0177 10.3535 15.9848 10.3725C15.9717 10.3801 15.9586 10.3877 15.9454 10.3952C15.9357 10.4009 15.9357 10.4009 15.9258 10.4066C15.8535 10.4483 15.7813 10.4899 15.7091 10.5316C15.6993 10.5372 15.6993 10.5372 15.6894 10.543C15.6763 10.5505 15.6633 10.558 15.6502 10.5655C15.6196 10.5832 15.589 10.6009 15.5584 10.6185C15.5476 10.6248 15.5367 10.631 15.5259 10.6373C15.5123 10.6452 15.4987 10.653 15.4851 10.6609C15.4789 10.6644 15.4727 10.668 15.4664 10.6716C15.461 10.6747 15.4556 10.6778 15.4501 10.681C15.4304 10.6924 15.4106 10.7036 15.3909 10.7149C15.3909 11.5629 15.3909 12.4109 15.3909 13.2846C15.4469 13.3166 15.5029 13.3486 15.5606 13.3816C15.6066 13.4081 15.6527 13.4346 15.6987 13.4612C15.7314 13.4801 15.7642 13.499 15.797 13.5179C15.8101 13.5255 15.8232 13.5331 15.8364 13.5407C15.8429 13.5444 15.8494 13.5482 15.8561 13.552C16.0333 13.6543 16.2106 13.7566 16.3879 13.8588C16.3944 13.8626 16.4009 13.8663 16.4076 13.8702C16.4207 13.8778 16.4338 13.8854 16.4469 13.8929C16.4799 13.9119 16.5129 13.931 16.5459 13.95C16.6092 13.9865 16.6725 14.0231 16.7356 14.06C16.7865 14.0897 16.8376 14.1193 16.8887 14.1486C16.8961 14.1528 16.9035 14.1571 16.9109 14.1613C16.9213 14.1673 16.9317 14.1732 16.942 14.1792C16.948 14.1826 16.9539 14.1859 16.96 14.1894C16.9746 14.1975 16.9893 14.2051 17.0042 14.2125C17.0085 14.2147 17.0129 14.2168 17.0173 14.2191C17.0206 14.2207 17.0239 14.2223 17.0273 14.224C17.0285 14.0492 17.0295 13.8744 17.0301 13.6996C17.0301 13.6835 17.0302 13.6673 17.0303 13.6512C17.0303 13.6471 17.0303 13.6431 17.0303 13.639C17.0305 13.578 17.0309 13.5171 17.0314 13.4561C17.0319 13.3854 17.0323 13.3147 17.0324 13.2439C17.0325 13.2065 17.0326 13.169 17.033 13.1316C17.0334 13.0963 17.0335 13.0611 17.0334 13.0258C17.0334 13.0129 17.0336 12.9999 17.0338 12.987C17.0379 12.9216 17.0379 12.9216 17.0155 12.8631C17.0014 12.8534 16.9889 12.8477 16.9727 12.8422C16.9646 12.8377 16.9566 12.8331 16.9486 12.8284C16.9404 12.8239 16.9321 12.8194 16.9238 12.8149C16.8799 12.7908 16.8364 12.766 16.7932 12.7407C16.7841 12.7354 16.7841 12.7354 16.7749 12.73C16.7422 12.7109 16.7096 12.6917 16.677 12.6724C16.6703 12.6685 16.6636 12.6646 16.6567 12.6606C16.6439 12.653 16.631 12.6454 16.6181 12.6377C16.6123 12.6344 16.6066 12.631 16.6006 12.6275C16.5929 12.6229 16.5929 12.6229 16.5851 12.6183C16.5733 12.611 16.5733 12.611 16.5606 12.6119C16.5606 12.2079 16.5606 11.8039 16.5606 11.3877C16.5706 11.3837 16.5806 11.3797 16.5909 11.3755C16.6018 11.3698 16.6126 11.3639 16.6234 11.3579C16.6296 11.3544 16.6358 11.351 16.6422 11.3474C16.6488 11.3437 16.6553 11.34 16.6621 11.3361C16.6689 11.3323 16.6758 11.3285 16.6828 11.3245C16.724 11.3013 16.7649 11.2778 16.8055 11.2536C16.8438 11.231 16.8823 11.2087 16.9208 11.1865C16.9275 11.1827 16.9342 11.1788 16.9412 11.1748C16.9549 11.1669 16.9687 11.1589 16.9824 11.151C17.0156 11.1319 17.0487 11.1128 17.0818 11.0937C17.0949 11.0861 17.1081 11.0786 17.1212 11.071C17.1277 11.0672 17.1342 11.0635 17.1409 11.0596C17.1606 11.0483 17.1803 11.0369 17.2 11.0255C17.2065 11.0218 17.213 11.018 17.2197 11.0142C17.2328 11.0066 17.2459 10.999 17.259 10.9915C17.299 10.9684 17.3389 10.9454 17.3788 10.9223C17.392 10.9147 17.4053 10.9071 17.4185 10.8995C17.4501 10.8813 17.4816 10.863 17.5129 10.8444C17.5187 10.8409 17.5245 10.8375 17.5305 10.8339C17.5414 10.8275 17.5523 10.821 17.5631 10.8144C17.5704 10.8102 17.5704 10.8102 17.5778 10.8058C17.584 10.8021 17.584 10.8021 17.5904 10.7983C17.6072 10.7922 17.6163 10.7945 17.6333 10.7998C17.6476 10.8068 17.6476 10.8068 17.6626 10.8157C17.6682 10.8191 17.6739 10.8224 17.6797 10.8259C17.6858 10.8295 17.6918 10.8331 17.6981 10.8369C17.7113 10.8447 17.7244 10.8525 17.7376 10.8603C17.7444 10.8643 17.7512 10.8683 17.7582 10.8725C17.7909 10.8918 17.8239 10.9108 17.8568 10.9297C17.87 10.9373 17.8833 10.945 17.8965 10.9526C17.9064 10.9583 17.9064 10.9583 17.9165 10.9641C17.9494 10.983 17.9822 11.002 18.0151 11.021C18.0283 11.0286 18.0414 11.0361 18.0545 11.0437C18.1333 11.0892 18.2121 11.1346 18.2909 11.1801C18.2974 11.1838 18.3039 11.1876 18.3106 11.1915C18.3237 11.199 18.3368 11.2065 18.3498 11.2141C18.3835 11.2335 18.4171 11.2529 18.4508 11.2723C18.4577 11.2762 18.4646 11.2802 18.4717 11.2843C18.4847 11.2918 18.4977 11.2992 18.5106 11.3067C18.5225 11.3135 18.5342 11.3204 18.5459 11.3275C18.5607 11.3358 18.5743 11.3426 18.5898 11.3492C18.6495 11.3762 18.6495 11.3762 18.6629 11.4052C18.6716 11.4396 18.6701 11.475 18.6695 11.5102C18.6696 11.5221 18.6698 11.5339 18.67 11.5458C18.6705 11.5779 18.6704 11.6099 18.6702 11.642C18.67 11.6688 18.6702 11.6957 18.6703 11.7225C18.6706 11.7858 18.6705 11.8491 18.6701 11.9124C18.6696 11.9776 18.6699 12.0428 18.6705 12.108C18.671 12.1641 18.6712 12.2202 18.6709 12.2762C18.6708 12.3097 18.6708 12.3431 18.6712 12.3766C18.6716 12.4081 18.6714 12.4395 18.6709 12.471C18.6707 12.4825 18.6708 12.494 18.6711 12.5055C18.6725 12.5764 18.6725 12.5764 18.6575 12.6058C18.6324 12.6319 18.6 12.6467 18.5671 12.6608C18.549 12.6689 18.5325 12.6788 18.5155 12.689C18.5034 12.696 18.4913 12.703 18.4791 12.71C18.4657 12.7178 18.4522 12.7255 18.4387 12.7333C18.4319 12.7372 18.4251 12.7411 18.418 12.7452C18.3964 12.7576 18.3749 12.7701 18.3533 12.7825C18.3497 12.7846 18.3462 12.7866 18.3425 12.7888C18.3254 12.7986 18.3082 12.8085 18.2911 12.8184C18.285 12.822 18.2788 12.8255 18.2724 12.8292C18.2644 12.8338 18.2644 12.8338 18.2562 12.8386C18.2364 12.8499 18.2167 12.8612 18.1969 12.8725C18.1969 13.3185 18.1969 13.7645 18.1969 14.224C18.2914 14.1725 18.3857 14.1206 18.4783 14.0657C18.5165 14.0431 18.555 14.0208 18.5935 13.9986C18.6002 13.9948 18.607 13.9909 18.6139 13.9869C18.6276 13.979 18.6414 13.971 18.6552 13.9631C18.6883 13.944 18.7214 13.9249 18.7545 13.9058C18.7676 13.8982 18.7808 13.8907 18.7939 13.8831C18.8037 13.8775 18.8037 13.8775 18.8136 13.8717C19.1878 13.6558 19.1878 13.6558 19.2075 13.6445C19.2207 13.6369 19.2338 13.6293 19.2469 13.6217C19.2799 13.6027 19.3129 13.5837 19.3458 13.5647C19.4151 13.5248 19.4843 13.4847 19.5532 13.4443C19.5867 13.4248 19.6203 13.4054 19.654 13.3863C19.6597 13.383 19.6597 13.383 19.6655 13.3797C19.684 13.3692 19.7025 13.3587 19.721 13.3483C19.7278 13.3444 19.7345 13.3406 19.7414 13.3367C19.7473 13.3334 19.7532 13.33 19.7593 13.3266C19.7657 13.3227 19.7721 13.3189 19.7788 13.3149C19.7832 13.3131 19.7877 13.3113 19.7923 13.3094C19.8098 13.3009 19.8206 13.2933 19.8333 13.2785C19.8418 13.245 19.8407 13.2118 19.8402 13.1773C19.8403 13.1668 19.8404 13.1562 19.8405 13.1457C19.8407 13.1166 19.8406 13.0876 19.8404 13.0586C19.8403 13.0274 19.8405 12.9961 19.8406 12.9648C19.8409 12.9035 19.8408 12.8422 19.8407 12.7809C19.8406 12.7311 19.8405 12.6813 19.8406 12.6315C19.8406 12.6245 19.8406 12.6174 19.8406 12.6101C19.8406 12.5957 19.8407 12.5813 19.8407 12.5669C19.8408 12.4319 19.8407 12.297 19.8404 12.162C19.8401 12.0462 19.8402 11.9303 19.8404 11.8144C19.8407 11.68 19.8408 11.5455 19.8406 11.411C19.8406 11.3967 19.8406 11.3823 19.8406 11.368C19.8406 11.3574 19.8406 11.3574 19.8406 11.3466C19.8405 11.2969 19.8406 11.2471 19.8407 11.1974C19.8409 11.1368 19.8408 11.0761 19.8406 11.0155C19.8404 10.9846 19.8404 10.9537 19.8405 10.9227C19.8407 10.8944 19.8406 10.8661 19.8403 10.8378C19.8403 10.8276 19.8403 10.8173 19.8404 10.8071C19.843 10.7535 19.843 10.7535 19.8213 10.7071C19.8074 10.6976 19.7943 10.6909 19.7788 10.6846C19.7696 10.6792 19.7696 10.6792 19.7603 10.6737C19.7549 10.6707 19.7495 10.6677 19.7439 10.6646C19.7378 10.6612 19.7316 10.6578 19.7253 10.6543C19.719 10.6508 19.7126 10.6473 19.706 10.6437C19.6625 10.6195 19.619 10.5953 19.5761 10.5699C19.5339 10.5448 19.4914 10.5201 19.4488 10.4956C19.4388 10.4898 19.4388 10.4898 19.4285 10.4839C19.4147 10.476 19.401 10.468 19.3872 10.4601C19.3541 10.441 19.321 10.4219 19.2878 10.4028C19.2747 10.3952 19.2616 10.3877 19.2485 10.3801C18.9727 10.221 18.9727 10.221 18.6969 10.0619C18.6904 10.0582 18.6839 10.0544 18.6772 10.0505C18.6641 10.043 18.651 10.0354 18.6379 10.0278C18.6049 10.0088 18.5719 9.98978 18.5389 9.97078C18.4756 9.93428 18.4123 9.89768 18.3492 9.86077C18.2966 9.83001 18.2438 9.79965 18.1909 9.76948C18.132 9.73591 18.0733 9.702 18.0147 9.66776C17.9577 9.63443 17.9005 9.60142 17.8433 9.56846C17.819 9.55444 17.7946 9.54039 17.7703 9.5263C17.7559 9.51795 17.7415 9.50961 17.7271 9.50127C17.7169 9.4954 17.7068 9.48951 17.6966 9.48363C17.6905 9.48006 17.6843 9.47648 17.6779 9.4728C17.6725 9.46966 17.6671 9.46653 17.6615 9.4633C17.6562 9.46034 17.6509 9.45738 17.6454 9.45433C17.6394 9.45067 17.6334 9.447 17.6272 9.44322C17.6097 9.43429 17.6097 9.43429 17.5933 9.44053ZM5.76957 9.79091C5.76101 9.79594 5.76101 9.79594 5.75227 9.80108C5.74604 9.80478 5.73982 9.80848 5.7334 9.81228C5.72006 9.82013 5.70673 9.82798 5.69339 9.83582C5.68822 9.83886 5.68822 9.83886 5.68294 9.84197C5.64661 9.86336 5.61009 9.88443 5.57355 9.90547C5.56375 9.91111 5.56375 9.91111 5.55375 9.91688C5.54047 9.92453 5.52718 9.93219 5.5139 9.93984C5.481 9.95879 5.44811 9.97777 5.41522 9.99675C5.37569 10.0196 5.33616 10.0424 5.29661 10.0651C5.23327 10.1016 5.16999 10.1382 5.10689 10.1752C5.05071 10.208 4.99426 10.2404 4.93772 10.2726C4.88242 10.3041 4.82734 10.336 4.77239 10.3682C4.70861 10.4055 4.6446 10.4423 4.58057 10.4792C4.54767 10.4982 4.51478 10.5172 4.48189 10.5361C4.44506 10.5574 4.40823 10.5786 4.37139 10.5999C4.36078 10.606 4.35017 10.6121 4.33956 10.6182C4.32636 10.6258 4.31314 10.6335 4.29993 10.6411C4.28816 10.6479 4.27643 10.6547 4.26478 10.6617C4.24553 10.6725 4.24553 10.6725 4.22641 10.6802C4.20498 10.6897 4.1897 10.6986 4.1728 10.7149C4.16188 10.749 4.16328 10.7821 4.16406 10.8176C4.16403 10.8282 4.16396 10.8389 4.16387 10.8495C4.16371 10.8787 4.164 10.9079 4.16436 10.9371C4.16468 10.9686 4.16457 11.0001 4.16452 11.0316C4.16448 11.0862 4.16471 11.1407 4.16511 11.1953C4.16571 11.2742 4.1659 11.3531 4.16599 11.432C4.16615 11.56 4.16663 11.688 4.16732 11.816C4.16799 11.9404 4.1685 12.0647 4.16881 12.1891C4.16883 12.1967 4.16885 12.2044 4.16887 12.2123C4.16896 12.2507 4.16905 12.2892 4.16914 12.3276C4.1699 12.6466 4.17118 12.9656 4.1728 13.2846C4.17756 13.2873 4.18232 13.29 4.18722 13.2928C4.20524 13.3031 4.22325 13.3134 4.24127 13.3237C4.249 13.3281 4.25673 13.3325 4.26445 13.3369C4.31511 13.3658 4.36564 13.3949 4.41598 13.4244C4.42219 13.428 4.4284 13.4316 4.4348 13.4354C4.44037 13.4386 4.44594 13.4419 4.45168 13.4453C4.50952 13.4791 4.56759 13.5124 4.62564 13.5459C4.65854 13.5648 4.69143 13.5838 4.72432 13.6028C4.73745 13.6104 4.75058 13.6179 4.76371 13.6255C5.10512 13.8225 5.44653 14.0195 5.78794 14.2164C5.79445 14.2202 5.80095 14.2239 5.80764 14.2278C5.82077 14.2354 5.83389 14.2429 5.84701 14.2505C5.87998 14.2695 5.91296 14.2885 5.94594 14.3075C6.00333 14.3406 6.0607 14.3737 6.11787 14.4071C6.14172 14.4211 6.1656 14.435 6.18949 14.4489C6.20354 14.4571 6.21758 14.4653 6.23161 14.4735C6.25109 14.4849 6.2706 14.4962 6.29014 14.5075C6.29771 14.5119 6.30527 14.5163 6.31282 14.5207C6.32335 14.5269 6.33391 14.533 6.34447 14.5391C6.35356 14.5444 6.35356 14.5444 6.36283 14.5498C6.37955 14.559 6.37955 14.559 6.40309 14.5573C6.41924 14.5495 6.43454 14.5413 6.45006 14.5323C6.45481 14.5296 6.45957 14.5269 6.46447 14.5242C6.51631 14.4947 6.56776 14.4645 6.61924 14.4343C6.65795 14.4117 6.69679 14.3892 6.73566 14.3668C6.74221 14.363 6.74875 14.3593 6.75549 14.3554C6.76877 14.3477 6.78204 14.3401 6.79532 14.3324C6.82822 14.3135 6.86111 14.2945 6.894 14.2755C6.90713 14.2679 6.92026 14.2604 6.93339 14.2528C6.94314 14.2472 6.94314 14.2472 6.95309 14.2414C8.1152 13.571 8.1152 13.571 8.1349 13.5596C8.14802 13.552 8.16114 13.5445 8.17426 13.5369C8.20724 13.5179 8.24021 13.4988 8.2732 13.4798C8.39639 13.4095 8.39639 13.4095 8.51839 13.3372C8.53641 13.327 8.53641 13.327 8.55527 13.3195C8.57678 13.3099 8.59215 13.301 8.60914 13.2846C8.62008 13.2506 8.61866 13.2174 8.61788 13.182C8.61791 13.1713 8.61798 13.1607 8.61807 13.15C8.61823 13.1208 8.61794 13.0916 8.61758 13.0624C8.61726 13.0309 8.61737 12.9994 8.61742 12.9679C8.61746 12.9134 8.61723 12.8588 8.61683 12.8042C8.61623 12.7253 8.61604 12.6464 8.61595 12.5675C8.61579 12.4395 8.61531 12.3115 8.61462 12.1835C8.61395 12.0592 8.61344 11.9348 8.61313 11.8105C8.6131 11.799 8.6131 11.799 8.61307 11.7873C8.61298 11.7488 8.61289 11.7104 8.6128 11.6719C8.61204 11.3529 8.61076 11.0339 8.60914 10.7149C8.60477 10.7124 8.60041 10.7099 8.59592 10.7073C8.42962 10.6114 8.26332 10.5154 8.09702 10.4195C8.09052 10.4157 8.08402 10.412 8.07732 10.4081C8.0642 10.4005 8.05108 10.393 8.03795 10.3854C8.00498 10.3664 7.972 10.3474 7.93902 10.3284C7.87567 10.2919 7.8124 10.2553 7.74929 10.2183C7.6967 10.1876 7.64389 10.1572 7.59096 10.1271C7.53205 10.0935 7.47333 10.0596 7.4148 10.0253C7.37083 9.99962 7.32676 9.97409 7.28263 9.94865C7.27615 9.94491 7.26968 9.94118 7.263 9.93733C7.23593 9.92173 7.20885 9.90613 7.18177 9.89054C7.16749 9.88232 7.15321 9.8741 7.13893 9.86587C7.12557 9.85818 7.11221 9.85049 7.09885 9.8428C7.06452 9.82302 7.03046 9.80291 6.99679 9.78202C6.98539 9.77458 6.98539 9.77458 6.97278 9.77554C6.97066 9.95002 6.96906 10.1245 6.96807 10.299C6.96798 10.3151 6.96789 10.3313 6.96779 10.3474C6.96777 10.3514 6.96774 10.3554 6.96772 10.3595C6.96735 10.4204 6.96671 10.4812 6.96593 10.542C6.96502 10.6127 6.96443 10.6833 6.96423 10.7539C6.96411 10.7913 6.96383 10.8287 6.96317 10.866C6.96255 10.9013 6.96236 10.9364 6.9625 10.9717C6.96248 10.9846 6.9623 10.9975 6.96195 11.0104C6.95778 11.0745 6.95778 11.0745 6.98159 11.1314C7.00304 11.1491 7.02659 11.1605 7.05229 11.1707C7.06966 11.178 7.08542 11.1878 7.1015 11.1975C7.11377 11.2046 7.12604 11.2117 7.13831 11.2187C7.15193 11.2265 7.16554 11.2344 7.17915 11.2422C7.18964 11.2483 7.20014 11.2543 7.21063 11.2603C7.23561 11.2747 7.26058 11.2891 7.28555 11.3035C7.29886 11.3111 7.31217 11.3188 7.32549 11.3264C7.33159 11.33 7.3377 11.3335 7.34399 11.3371C7.34927 11.3401 7.35456 11.3432 7.36 11.3463C7.36622 11.35 7.37243 11.3536 7.37884 11.3573C7.38374 11.359 7.38865 11.3606 7.3937 11.3623C7.41349 11.3705 7.42505 11.3777 7.43945 11.3937C7.44876 11.432 7.44711 11.4699 7.44633 11.5091C7.44631 11.5211 7.44632 11.533 7.44635 11.545C7.44637 11.5774 7.44602 11.6098 7.44559 11.6422C7.44521 11.676 7.44518 11.7099 7.44511 11.7438C7.44492 11.8079 7.44442 11.8721 7.44381 11.9362C7.44313 12.0092 7.4428 12.0822 7.4425 12.1552C7.44186 12.3054 7.4408 12.4556 7.43945 12.6058C7.43285 12.6096 7.43285 12.6096 7.42612 12.6135C7.40944 12.6231 7.39276 12.6327 7.37608 12.6424C7.36546 12.6485 7.35483 12.6546 7.34421 12.6607C7.29935 12.6866 7.25459 12.7126 7.2099 12.7388C7.15371 12.7716 7.09728 12.804 7.04073 12.8362C6.98543 12.8678 6.93035 12.8996 6.87541 12.9318C6.83144 12.9575 6.78737 12.983 6.74324 13.0085C6.73673 13.0122 6.73022 13.016 6.72352 13.0198C6.6967 13.0353 6.66989 13.0507 6.64307 13.0662C6.6293 13.0741 6.61554 13.082 6.60178 13.09C6.58841 13.0977 6.57504 13.1054 6.56166 13.113C6.53235 13.1299 6.50319 13.1469 6.4744 13.1646C6.46728 13.1689 6.46728 13.1689 6.46002 13.1734C6.45142 13.1787 6.44286 13.184 6.43436 13.1894C6.40694 13.2062 6.40694 13.2062 6.38863 13.2044C6.37133 13.1993 6.35748 13.1925 6.3418 13.1836C6.33581 13.1802 6.32982 13.1768 6.32365 13.1734C6.31724 13.1697 6.31083 13.166 6.30423 13.1623C6.29751 13.1585 6.29079 13.1546 6.28387 13.1507C6.22655 13.1182 6.1696 13.085 6.11273 13.0517C6.07451 13.0293 6.03617 13.0071 5.99779 12.985C5.99124 12.9812 5.9847 12.9774 5.97795 12.9736C5.96468 12.9659 5.95141 12.9583 5.93814 12.9506C5.90524 12.9317 5.87235 12.9127 5.83946 12.8937C5.82633 12.8861 5.8132 12.8786 5.80007 12.871C5.7738 12.8558 5.74754 12.8407 5.72128 12.8255C5.71477 12.8218 5.70827 12.818 5.70156 12.8141C5.68849 12.8066 5.67541 12.7991 5.66233 12.7915C5.62869 12.7721 5.59503 12.7527 5.56136 12.7333C5.54762 12.7254 5.53388 12.7175 5.52014 12.7096C5.51029 12.7039 5.51029 12.7039 5.50024 12.6982C5.45983 12.6749 5.41962 12.6513 5.37998 12.6266C5.36253 12.6153 5.36253 12.6153 5.34249 12.6119C5.34249 12.2079 5.34249 11.8039 5.34249 11.3877C5.35249 11.3837 5.36249 11.3797 5.3728 11.3755C5.38441 11.3693 5.39592 11.3629 5.40734 11.3563C5.41409 11.3525 5.42084 11.3486 5.42779 11.3446C5.43509 11.3404 5.44239 11.3362 5.44969 11.332C5.45727 11.3276 5.46484 11.3233 5.47242 11.3189C5.49197 11.3077 5.5115 11.2964 5.53102 11.2852C5.54904 11.2748 5.56707 11.2644 5.5851 11.2541C5.64387 11.2202 5.70257 11.1863 5.76105 11.152C5.76531 11.1496 5.76957 11.1471 5.77396 11.1445C5.79263 11.1342 5.79263 11.1342 5.80916 11.121C5.80975 11.1037 5.80994 11.0865 5.80988 11.0692C5.80989 11.0637 5.8099 11.0582 5.8099 11.0525C5.80991 11.0339 5.80988 11.0154 5.80984 10.9968C5.80984 10.9835 5.80984 10.9703 5.80985 10.957C5.80985 10.9209 5.80981 10.8848 5.80977 10.8487C5.80973 10.811 5.80973 10.7733 5.80972 10.7356C5.80971 10.6723 5.80967 10.609 5.80961 10.5457C5.80956 10.4805 5.80951 10.4153 5.80949 10.35C5.80949 10.346 5.80949 10.342 5.80948 10.3379C5.80948 10.3177 5.80947 10.2976 5.80946 10.2774C5.8094 10.1101 5.80929 9.94283 5.80916 9.77554C5.79244 9.77554 5.78396 9.78239 5.76957 9.79091ZM9.16174 14.3123C9.15569 14.3157 9.14964 14.3191 9.14341 14.3226C9.13357 14.3282 9.13357 14.3282 9.12353 14.3338C9.11672 14.3377 9.10992 14.3415 9.10292 14.3455C9.04524 14.378 8.98802 14.4113 8.93089 14.4448C8.89267 14.4672 8.85433 14.4894 8.81595 14.5115C8.80613 14.5172 8.80613 14.5172 8.79611 14.5229C8.78284 14.5306 8.76957 14.5382 8.7563 14.5459C8.7234 14.5648 8.69051 14.5838 8.65762 14.6028C8.64449 14.6104 8.63136 14.6179 8.61823 14.6255C8.61173 14.6293 8.60523 14.633 8.59853 14.6369C7.90914 15.0346 7.90914 15.0346 7.88942 15.046C7.87636 15.0535 7.8633 15.061 7.85024 15.0686C7.81991 15.0861 7.78958 15.1036 7.75925 15.1211C7.74864 15.1272 7.73803 15.1333 7.72742 15.1394C7.71421 15.147 7.701 15.1546 7.68779 15.1623C7.64533 15.1867 7.60297 15.2114 7.56066 15.2361C7.57841 15.25 7.59666 15.2616 7.6162 15.2728C7.62242 15.2763 7.62864 15.2799 7.63504 15.2836C7.64175 15.2874 7.64845 15.2913 7.65535 15.2952C7.66243 15.2993 7.6695 15.3033 7.67657 15.3074C7.69125 15.3158 7.70594 15.3242 7.72063 15.3327C7.75421 15.3519 7.78773 15.3713 7.82126 15.3907C7.83439 15.3982 7.84752 15.4058 7.86066 15.4134C8.13641 15.5725 8.13641 15.5725 8.41217 15.7316C8.41868 15.7353 8.42519 15.7391 8.4319 15.7429C8.44492 15.7505 8.45795 15.758 8.47098 15.7655C8.5017 15.7832 8.53243 15.8009 8.56316 15.8187C8.57765 15.827 8.59214 15.8354 8.60662 15.8437C8.61683 15.8496 8.62704 15.8555 8.63725 15.8614C8.64345 15.8649 8.64965 15.8685 8.65603 15.8722C8.66147 15.8753 8.66691 15.8785 8.67252 15.8817C8.68319 15.8879 8.69374 15.8943 8.70419 15.9009C8.71759 15.91 8.71759 15.91 8.73231 15.9085C8.75496 15.9005 8.77505 15.8893 8.79588 15.8774C8.80061 15.8747 8.80535 15.8721 8.81023 15.8693C8.8553 15.8438 8.89999 15.8176 8.94469 15.7914C8.99094 15.7643 9.03729 15.7375 9.08377 15.7108C9.09128 15.7065 9.09878 15.7022 9.10627 15.6979C9.11677 15.6918 9.12729 15.6858 9.1378 15.6798C9.14383 15.6763 9.14985 15.6728 9.15606 15.6693C9.17168 15.6609 9.18611 15.6534 9.20307 15.6482C9.21911 15.6554 9.23206 15.6626 9.24663 15.6721C9.25587 15.6778 9.26512 15.6835 9.27438 15.6892C9.27944 15.6924 9.28449 15.6955 9.28971 15.6988C9.31992 15.7173 9.35074 15.7348 9.38148 15.7524C9.39511 15.7602 9.40874 15.7681 9.42236 15.7759C9.42921 15.7799 9.43605 15.7838 9.4431 15.7879C9.47623 15.807 9.50935 15.8261 9.54246 15.8452C9.55559 15.8528 9.56872 15.8603 9.58186 15.8679C9.66064 15.9134 9.73943 15.9588 9.81822 16.0043C9.82472 16.008 9.83122 16.0118 9.83792 16.0157C9.85104 16.0232 9.86416 16.0308 9.87728 16.0384C9.91025 16.0574 9.94323 16.0764 9.97622 16.0954C9.98287 16.0992 9.98953 16.1031 9.99639 16.107C10.0087 16.1141 10.0209 16.1212 10.0332 16.1282C10.0452 16.1352 10.0571 16.1424 10.0689 16.1498C10.0884 16.1614 10.1077 16.168 10.1293 16.1748C10.1737 16.1911 10.2106 16.2098 10.2394 16.2482C10.2704 16.324 10.2601 16.42 10.259 16.5C10.2586 16.5337 10.2589 16.5673 10.2592 16.601C10.2594 16.6575 10.2591 16.7139 10.2584 16.7704C10.2576 16.8356 10.2579 16.9007 10.2587 16.9658C10.2593 17.0219 10.2594 17.078 10.259 17.1341C10.2588 17.1676 10.2588 17.201 10.2593 17.2344C10.2618 17.4366 10.2618 17.4366 10.2249 17.4857C10.1908 17.5155 10.1536 17.5321 10.1108 17.5456C10.0885 17.5531 10.0707 17.5637 10.0508 17.5762C10.0392 17.5829 10.0276 17.5896 10.0159 17.5963C10.0027 17.604 9.98946 17.6116 9.97622 17.6192C9.96964 17.623 9.96307 17.6268 9.95629 17.6307C9.92339 17.6496 9.8905 17.6686 9.85761 17.6876C9.84448 17.6952 9.83135 17.7028 9.81822 17.7103C9.80847 17.716 9.80847 17.716 9.79852 17.7217C9.58186 17.8467 9.58186 17.8467 9.56215 17.8581C9.54906 17.8656 9.53597 17.8732 9.52289 17.8807C9.48939 17.9001 9.45588 17.9194 9.42236 17.9387C9.41557 17.9426 9.40878 17.9465 9.40178 17.9505C9.38841 17.9582 9.37502 17.9659 9.36162 17.9736C9.33232 17.9904 9.30321 18.0074 9.27459 18.0254C9.26751 18.0298 9.26751 18.0298 9.26029 18.0342C9.25175 18.0396 9.24327 18.045 9.23488 18.0505C9.21752 18.0613 9.20676 18.0669 9.18621 18.0642C9.15729 18.0495 9.1294 18.0334 9.10156 18.0168C9.08844 18.009 9.07533 18.0013 9.06221 17.9936C9.05545 17.9896 9.04868 17.9856 9.04171 17.9815C9.009 17.9622 8.97612 17.9433 8.94322 17.9243C8.92998 17.9167 8.91674 17.9091 8.9035 17.9015C8.89692 17.8977 8.89035 17.8939 8.88357 17.89C8.85067 17.871 8.81778 17.852 8.78489 17.8331C8.77176 17.8255 8.75863 17.8179 8.7455 17.8103C8.50914 17.674 8.50914 17.674 8.48942 17.6626C8.47635 17.6551 8.46328 17.6475 8.45021 17.64C8.41999 17.6225 8.38977 17.6051 8.35955 17.5877C8.34904 17.5816 8.33852 17.5755 8.32801 17.5694C8.31495 17.5619 8.3019 17.5544 8.28885 17.5468C8.27981 17.5416 8.27981 17.5416 8.2706 17.5363C8.26499 17.5329 8.25938 17.5295 8.25361 17.526C8.23357 17.5144 8.23357 17.5144 8.21152 17.5065C8.15503 17.4825 8.15503 17.4825 8.14371 17.4545C8.1359 17.4175 8.13791 17.3799 8.13892 17.3423C8.13894 17.3302 8.13893 17.318 8.13888 17.3059C8.13884 17.274 8.13932 17.2421 8.1399 17.2102C8.1404 17.1776 8.14042 17.1451 8.14048 17.1125C8.14068 17.0486 8.1414 16.9848 8.14247 16.9209C8.1378 16.9184 8.1378 16.9184 8.13304 16.9157C8.11876 16.9078 8.10448 16.8999 8.09021 16.892C8.08286 16.8879 8.08286 16.8879 8.07537 16.8837C8.0381 16.863 8.00117 16.8418 7.96444 16.8202C7.91086 16.7888 7.85705 16.7578 7.80308 16.727C7.74416 16.6934 7.68545 16.6595 7.62692 16.6253C7.56314 16.588 7.49912 16.5511 7.4351 16.5142C7.4022 16.4953 7.36931 16.4763 7.33642 16.4573C7.29653 16.4343 7.25664 16.4113 7.21675 16.3883C7.21001 16.3844 7.20328 16.3805 7.19635 16.3765C7.18306 16.3689 7.16977 16.3612 7.15648 16.3535C7.12593 16.3359 7.09541 16.3183 7.06499 16.3004C7.05963 16.2973 7.05426 16.2941 7.04873 16.2909C7.03877 16.2851 7.02882 16.2792 7.01889 16.2734C6.99729 16.2593 6.99729 16.2593 6.97278 16.2543C6.96945 16.493 6.96689 16.7316 6.96536 16.9703C6.96517 16.9985 6.96499 17.0267 6.96479 17.0549C6.96476 17.0605 6.96472 17.0661 6.96468 17.0719C6.96405 17.1627 6.9629 17.2535 6.96156 17.3443C6.9602 17.4376 6.95939 17.5308 6.9591 17.6241C6.9589 17.6816 6.95827 17.739 6.95709 17.7965C6.95632 17.836 6.95609 17.8755 6.95627 17.9149C6.95637 17.9377 6.95623 17.9604 6.95545 17.9832C6.94961 18.0752 6.94961 18.0752 6.98716 18.1546C7.02221 18.1819 7.0604 18.2003 7.10138 18.2169C7.12276 18.2259 7.14166 18.2368 7.16137 18.2489C7.173 18.2556 7.18463 18.2623 7.19627 18.269C7.20951 18.2767 7.22275 18.2843 7.23599 18.2919C7.24257 18.2957 7.24914 18.2995 7.25592 18.3034C7.28882 18.3224 7.32171 18.3414 7.3546 18.3603C7.36773 18.3679 7.38086 18.3755 7.39399 18.3831C7.84045 18.6406 8.28692 18.8982 8.73338 19.1558C8.73988 19.1595 8.74638 19.1633 8.75308 19.1671C8.7662 19.1747 8.77932 19.1823 8.79244 19.1899C8.82541 19.2089 8.85839 19.2279 8.89138 19.2469C8.95761 19.2851 9.02378 19.3233 9.08981 19.3618C9.09589 19.3654 9.10196 19.3689 9.10822 19.3726C9.15401 19.3993 9.15401 19.3993 9.16967 19.4103C9.18434 19.4192 9.18434 19.4192 9.20016 19.4169C9.21585 19.4116 9.22916 19.4052 9.24353 19.397C9.24897 19.3939 9.25441 19.3908 9.26001 19.3876C9.26585 19.3842 9.27168 19.3808 9.27769 19.3774C9.28693 19.3721 9.28693 19.3721 9.29635 19.3667C9.34555 19.3385 9.39452 19.3099 9.44345 19.2812C9.49042 19.2537 9.53761 19.2267 9.58489 19.1997C9.6438 19.1661 9.70252 19.1322 9.76105 19.098C9.82483 19.0607 9.88885 19.0238 9.95287 18.9869C9.98577 18.968 10.0187 18.949 10.0515 18.93C10.0647 18.9224 10.0778 18.9149 10.0909 18.9073C10.1007 18.9017 10.1007 18.9017 10.1106 18.8959C11.1152 18.3164 11.1152 18.3164 11.1349 18.305C11.1479 18.2975 11.161 18.29 11.174 18.2825C11.2047 18.2647 11.2355 18.247 11.2663 18.2293C11.2809 18.221 11.2954 18.2126 11.31 18.2042C11.3202 18.1983 11.3305 18.1925 11.3408 18.1866C11.347 18.183 11.3532 18.1794 11.3596 18.1758C11.3651 18.1726 11.3706 18.1695 11.3762 18.1663C11.3811 18.1633 11.3859 18.1603 11.3909 18.1573C11.3952 18.155 11.3994 18.1527 11.4038 18.1503C11.417 18.1395 11.417 18.1395 11.4183 18.1205C11.4183 18.1127 11.4184 18.105 11.4184 18.097C11.4185 18.0927 11.4185 18.0883 11.4186 18.0839C11.4187 18.0692 11.4187 18.0546 11.4187 18.04C11.4188 18.0294 11.4189 18.0189 11.419 18.0083C11.4192 17.9792 11.4193 17.9502 11.4193 17.9211C11.4194 17.8897 11.4196 17.8584 11.4198 17.8271C11.4203 17.7514 11.4205 17.6756 11.4207 17.5999C11.4208 17.5643 11.4209 17.5287 11.421 17.493C11.4214 17.3746 11.4217 17.2561 11.4219 17.1377C11.4219 17.1069 11.422 17.0762 11.422 17.0454C11.422 17.034 11.422 17.034 11.422 17.0223C11.4222 16.8985 11.4228 16.7746 11.4235 16.6508C11.4242 16.5237 11.4246 16.3967 11.4247 16.2696C11.4248 16.1982 11.425 16.1269 11.4255 16.0555C11.426 15.9947 11.4262 15.9339 11.426 15.8732C11.4259 15.8421 11.4259 15.8111 11.4263 15.7801C11.4267 15.7517 11.4267 15.7233 11.4264 15.6949C11.4263 15.6847 11.4264 15.6744 11.4267 15.6641C11.4292 15.6114 11.4292 15.6114 11.4063 15.5662C11.3846 15.5492 11.3608 15.5373 11.3357 15.5262C11.3185 15.5183 11.3026 15.5086 11.2865 15.4989C11.2742 15.4919 11.2619 15.4848 11.2496 15.4778C11.2359 15.4699 11.2222 15.462 11.2084 15.4541C11.2015 15.4501 11.1946 15.4461 11.1875 15.442C11.1543 15.4229 11.1211 15.4037 11.0879 15.3846C11.0748 15.377 11.0616 15.3694 11.0485 15.3619C10.7071 15.1649 10.3657 14.9679 10.0243 14.771C10.0178 14.7672 10.0113 14.7635 10.0046 14.7596C9.99146 14.752 9.97833 14.7445 9.96521 14.7369C9.93224 14.7179 9.89926 14.6988 9.86628 14.6798C9.80293 14.6433 9.73965 14.6067 9.67655 14.5698C9.6204 14.537 9.56398 14.5046 9.50745 14.4724C9.45659 14.4434 9.40589 14.4142 9.35534 14.3846C9.34639 14.3794 9.34639 14.3794 9.33726 14.374C9.2917 14.3474 9.2917 14.3474 9.27364 14.3369C9.2615 14.3298 9.24933 14.3227 9.23716 14.3157C9.23074 14.3119 9.22432 14.3082 9.2177 14.3043C9.19343 14.2917 9.18454 14.2995 9.16174 14.3123ZM14.7663 14.3134C14.76 14.317 14.7538 14.3207 14.7474 14.3244C14.7372 14.3304 14.7372 14.3304 14.7269 14.3365C14.7198 14.3406 14.7127 14.3448 14.7056 14.3489C14.6908 14.3575 14.6761 14.3662 14.6613 14.3748C14.6279 14.3944 14.5942 14.4137 14.5606 14.4331C14.5475 14.4407 14.5343 14.4482 14.5212 14.4558C14.1273 14.6831 14.1273 14.6831 14.1076 14.6944C14.0945 14.702 14.0813 14.7096 14.0682 14.7172C14.0352 14.7362 14.0023 14.7552 13.9693 14.7742C13.9059 14.8107 13.8427 14.8473 13.7796 14.8842C13.7234 14.9171 13.6669 14.9495 13.6104 14.9817C13.5551 15.0132 13.5 15.0451 13.4451 15.0772C13.3813 15.1145 13.3173 15.1514 13.2532 15.1883C13.2203 15.2072 13.1874 15.2262 13.1546 15.2452C13.1414 15.2528 13.1283 15.2604 13.1152 15.2679C13.1054 15.2736 13.1054 15.2736 13.0955 15.2793C12.8788 15.4043 12.8788 15.4043 12.8591 15.4157C12.8461 15.4232 12.833 15.4307 12.82 15.4382C12.7892 15.456 12.7584 15.4738 12.7275 15.4915C12.7129 15.4999 12.6983 15.5084 12.6837 15.5168C12.6733 15.5227 12.663 15.5287 12.6527 15.5346C12.6464 15.5382 12.6402 15.5418 12.6338 15.5455C12.6282 15.5487 12.6227 15.5518 12.6171 15.5551C12.6061 15.5616 12.5954 15.5685 12.5849 15.5755C12.5821 15.5896 12.5821 15.5896 12.5826 15.6064C12.5826 15.613 12.5826 15.6196 12.5825 15.6264C12.5826 15.6337 12.5826 15.641 12.5827 15.6485C12.5827 15.6562 12.5826 15.6639 12.5826 15.6719C12.5826 15.6933 12.5827 15.7148 12.5828 15.7363C12.5828 15.7594 12.5828 15.7825 12.5828 15.8056C12.5828 15.8457 12.5828 15.8858 12.5829 15.9258C12.5831 15.9838 12.5831 16.0417 12.5832 16.0997C12.5832 16.1937 12.5833 16.2877 12.5835 16.3817C12.5837 16.473 12.5838 16.5644 12.5839 16.6557C12.5839 16.6613 12.5839 16.667 12.5839 16.6728C12.5839 16.701 12.5839 16.7292 12.584 16.7574C12.5841 16.9917 12.5845 17.226 12.5849 17.4603C12.6028 17.4533 12.62 17.4461 12.6369 17.4368C12.643 17.4334 12.643 17.4334 12.6492 17.4299C12.6536 17.4275 12.658 17.425 12.6625 17.4225C12.6673 17.4198 12.672 17.4172 12.6769 17.4144C12.7221 17.3891 12.7668 17.3629 12.8116 17.3367C12.8591 17.3089 12.9068 17.2815 12.9546 17.2543C13.0135 17.2207 13.0722 17.1868 13.1307 17.1526C13.1945 17.1153 13.2585 17.0784 13.3225 17.0415C13.362 17.0188 13.4014 16.996 13.4408 16.9733C13.4744 16.9539 13.5081 16.9345 13.5417 16.9151C13.6274 16.8659 13.6274 16.8659 13.7125 16.8156C13.7162 16.8134 13.7199 16.8112 13.7237 16.809C13.74 16.7995 13.74 16.7995 13.7546 16.7876C13.7553 16.7708 13.7557 16.7542 13.7558 16.7374C13.7559 16.7321 13.7559 16.7269 13.756 16.7215C13.7562 16.704 13.7563 16.6865 13.7565 16.669C13.7566 16.6569 13.7567 16.6449 13.7569 16.6328C13.7572 16.6009 13.7575 16.569 13.7578 16.5372C13.7581 16.5047 13.7584 16.4722 13.7588 16.4397C13.7594 16.3759 13.76 16.312 13.7606 16.2482C13.7649 16.2458 13.7693 16.2434 13.7737 16.2409C13.79 16.2318 13.8063 16.2227 13.8225 16.2136C13.8329 16.2078 13.8434 16.202 13.8538 16.1962C13.8905 16.1756 13.9271 16.1549 13.9633 16.1335C13.9675 16.1309 13.9717 16.1284 13.9761 16.1259C13.9799 16.1236 13.9837 16.1213 13.9877 16.119C14.0218 16.0988 14.0562 16.079 14.0905 16.0592C14.0972 16.0553 14.104 16.0515 14.1109 16.0475C14.1246 16.0396 14.1384 16.0316 14.1522 16.0237C14.1853 16.0046 14.2184 15.9855 14.2515 15.9664C14.2647 15.9588 14.2778 15.9513 14.2909 15.9437C14.2974 15.9399 14.3039 15.9362 14.3106 15.9323C14.4189 15.8698 14.4189 15.8698 14.5273 15.8073C14.5338 15.8036 14.5403 15.7998 14.547 15.7959C14.56 15.7884 14.5731 15.7809 14.5862 15.7735C14.617 15.7559 14.6474 15.7381 14.6772 15.7188C14.6912 15.7098 14.7053 15.701 14.7194 15.6922C14.7293 15.6859 14.739 15.6793 14.7486 15.6727C14.7671 15.6613 14.7819 15.6531 14.803 15.6482C14.8308 15.6553 14.8522 15.6687 14.8758 15.6846C14.8838 15.6892 14.8918 15.6937 14.8999 15.6982C14.9072 15.7026 14.9146 15.707 14.922 15.7115C14.9308 15.7168 14.9397 15.722 14.9486 15.7273C14.9533 15.7301 14.9581 15.733 14.9631 15.7359C14.9933 15.7538 15.0237 15.7712 15.0542 15.7888C15.0609 15.7926 15.0676 15.7965 15.0745 15.8005C15.0882 15.8084 15.102 15.8163 15.1158 15.8243C15.1489 15.8433 15.182 15.8624 15.2151 15.8816C15.2283 15.8891 15.2414 15.8967 15.2545 15.9043C15.2808 15.9194 15.3071 15.9346 15.3333 15.9497C15.3398 15.9535 15.3463 15.9572 15.353 15.9611C15.3662 15.9687 15.3793 15.9762 15.3924 15.9838C15.4254 16.0028 15.4583 16.0219 15.4913 16.0409C15.5618 16.0815 15.6322 16.1222 15.7023 16.1633C15.7517 16.1923 15.8016 16.2201 15.8515 16.2482C15.8515 16.6502 15.8515 17.0522 15.8515 17.4664C15.7675 17.5144 15.7675 17.5144 15.6818 17.5634C15.6052 17.6075 15.5286 17.6517 15.4523 17.6963C15.3961 17.7292 15.3396 17.7616 15.2831 17.7938C15.2278 17.8253 15.1728 17.8571 15.1179 17.8892C15.0595 17.9234 15.001 17.9573 14.9424 17.9909C14.92 18.0038 14.8977 18.0168 14.8756 18.0301C14.8712 18.0328 14.8667 18.0354 14.8621 18.0382C14.8541 18.0429 14.8461 18.0478 14.8382 18.0527C14.8277 18.0588 14.8277 18.0588 14.8091 18.0664C14.7856 18.0591 14.7651 18.047 14.7438 18.0349C14.7336 18.029 14.7336 18.029 14.7232 18.023C14.7158 18.0188 14.7085 18.0146 14.7011 18.0103C14.6935 18.006 14.6859 18.0016 14.6783 17.9972C14.6297 17.9693 14.5813 17.9412 14.533 17.913C14.5271 17.9096 14.5212 17.9061 14.5151 17.9026C14.4866 17.886 14.4583 17.8692 14.4301 17.8521C14.4248 17.849 14.4195 17.8458 14.4141 17.8426C14.4042 17.8367 14.3944 17.8307 14.3847 17.8246C14.3803 17.8221 14.376 17.8195 14.3715 17.8168C14.3678 17.8145 14.364 17.8122 14.3602 17.8099C14.3439 17.8042 14.3346 17.8068 14.3182 17.8118C14.3024 17.8194 14.3024 17.8194 14.2863 17.8291C14.2801 17.8327 14.2739 17.8364 14.2675 17.8401C14.2609 17.844 14.2542 17.8479 14.2474 17.852C14.2403 17.8561 14.2333 17.8602 14.2262 17.8643C14.2116 17.8729 14.197 17.8814 14.1824 17.89C14.149 17.9096 14.1154 17.9289 14.0818 17.9482C14.0687 17.9558 14.0556 17.9634 14.0424 17.9709C13.8061 18.1073 13.8061 18.1073 13.7864 18.1187C13.7732 18.1262 13.7601 18.1338 13.747 18.1414C13.714 18.1604 13.6811 18.1794 13.6481 18.1984C13.5847 18.2349 13.5214 18.2715 13.4583 18.3084C13.3833 18.3523 13.3078 18.3954 13.2322 18.4385C13.2124 18.4498 13.1926 18.4611 13.1727 18.4725C13.1874 18.4887 13.2031 18.4985 13.2221 18.5093C13.2284 18.5129 13.2347 18.5165 13.2411 18.5202C13.2479 18.5241 13.2547 18.5279 13.2618 18.5319C13.2725 18.5381 13.2833 18.5442 13.2941 18.5504C13.3014 18.5546 13.3088 18.5588 13.3162 18.563C13.3511 18.583 13.3858 18.6033 13.4205 18.6236C13.4731 18.6543 13.5259 18.6847 13.5788 18.7149C13.6377 18.7484 13.6964 18.7823 13.755 18.8166C13.8187 18.8539 13.8828 18.8908 13.9468 18.9277C13.9797 18.9466 14.0126 18.9656 14.0455 18.9846C14.0586 18.9921 14.0717 18.9997 14.0849 19.0073C14.4788 19.2346 14.4788 19.2346 14.4985 19.2459C14.5116 19.2535 14.5246 19.261 14.5376 19.2685C14.5682 19.2862 14.5989 19.3038 14.6295 19.3215C14.6403 19.3278 14.6512 19.334 14.662 19.3403C14.6756 19.3481 14.6892 19.356 14.7028 19.3638C14.7148 19.3708 14.7269 19.3777 14.7389 19.3846C14.7485 19.3901 14.758 19.3959 14.7673 19.4018C14.7878 19.4149 14.7878 19.4149 14.8113 19.4165C14.8292 19.4113 14.8431 19.404 14.8592 19.3946C14.8654 19.3909 14.8716 19.3873 14.8779 19.3836C14.8846 19.3797 14.8913 19.3757 14.8981 19.3717C14.9051 19.3676 14.9122 19.3635 14.9192 19.3593C14.9339 19.3508 14.9485 19.3422 14.9631 19.3337C14.9965 19.3141 15.0301 19.2948 15.0636 19.2755C15.0768 19.2679 15.0899 19.2603 15.103 19.2527C15.3394 19.1164 15.3394 19.1164 15.3591 19.105C15.3722 19.0974 15.3853 19.0899 15.3985 19.0823C15.4314 19.0633 15.4644 19.0443 15.4974 19.0253C15.5607 18.9888 15.624 18.9522 15.6871 18.9152C15.7433 18.8824 15.7997 18.85 15.8563 18.8178C15.9116 18.7863 15.9667 18.7544 16.0216 18.7222C16.0854 18.6849 16.1494 18.6481 16.2134 18.6112C16.2463 18.5922 16.2792 18.5732 16.3121 18.5543C16.3252 18.5467 16.3384 18.5391 16.3515 18.5315C16.3613 18.5259 16.3613 18.5259 16.3712 18.5202C16.7454 18.3043 16.7454 18.3043 16.7652 18.2929C16.7782 18.2854 16.7912 18.2779 16.8042 18.2704C16.8351 18.2525 16.8661 18.2347 16.8971 18.2169C16.9118 18.2084 16.9265 18.1999 16.9412 18.1915C16.9517 18.1854 16.9622 18.1794 16.9727 18.1734C16.9789 18.1698 16.9852 18.1662 16.9917 18.1625C17 18.1577 17 18.1577 17.0085 18.1528C17.0207 18.1462 17.0207 18.1462 17.0273 18.1391C17.0279 18.1255 17.028 18.1119 17.028 18.0983C17.028 18.0918 17.028 18.0918 17.028 18.0852C17.028 18.0705 17.028 18.0558 17.028 18.0411C17.028 18.0305 17.028 18.0199 17.028 18.0093C17.028 17.9801 17.028 17.9509 17.028 17.9217C17.0279 17.8902 17.0279 17.8588 17.0279 17.8273C17.028 17.7728 17.0279 17.7182 17.0279 17.6637C17.0278 17.5849 17.0278 17.506 17.0278 17.4271C17.0278 17.2992 17.0278 17.1713 17.0277 17.0434C17.0277 16.9191 17.0276 16.7948 17.0276 16.6705C17.0276 16.6628 17.0276 16.6552 17.0276 16.6473C17.0276 16.6089 17.0276 16.5705 17.0276 16.532C17.0275 16.2132 17.0274 15.8943 17.0273 15.5755C17.0229 15.573 17.0185 15.5704 17.0139 15.5678C16.9973 15.5582 16.9806 15.5486 16.9639 15.539C16.9533 15.5328 16.9426 15.5267 16.932 15.5206C16.8872 15.4947 16.8424 15.4687 16.7977 15.4425C16.7451 15.4118 16.6923 15.3814 16.6394 15.3513C16.5805 15.3177 16.5218 15.2838 16.4632 15.2495C16.3994 15.2122 16.3354 15.1754 16.2714 15.1385C16.2385 15.1195 16.2056 15.1005 16.1727 15.0816C16.1596 15.074 16.1465 15.0664 16.1333 15.0588C15.7919 14.8619 15.4505 14.6649 15.1091 14.4679C15.1026 14.4642 15.0961 14.4604 15.0894 14.4566C15.0763 14.449 15.0633 14.4415 15.0503 14.434C15.0195 14.4162 14.9886 14.3984 14.9578 14.3807C14.9432 14.3723 14.9286 14.3639 14.914 14.3555C14.9036 14.3495 14.8933 14.3436 14.8829 14.3376C14.8767 14.334 14.8705 14.3304 14.864 14.3267C14.8585 14.3236 14.853 14.3204 14.8474 14.3171C14.8364 14.3107 14.8257 14.3038 14.8152 14.2967C14.7933 14.2967 14.785 14.3024 14.7663 14.3134Z" @@ -489,12 +643,35 @@ fill="currentColor" ></path> </symbol> + <symbol viewBox="0 0 40 40" id="kuae-cloud-coding-plan"> + <path + d="M20.1312 7.5L17.4088 11.1912H5.81625L8.5375 7.5H20.1325H20.1312ZM34.0675 28.81L31.3475 32.5H19.795L22.5125 28.81H34.0675ZM35 7.5L16.58 32.5H5L23.42 7.5H35Z" + fill="currentColor" + ></path> + </symbol> <symbol viewBox="0 0 24 24" fill="none" id="kimi-for-coding"> <path d="M3.51531 15.81L10.908 17.7878C10.8981 18.3134 10.9136 18.8392 10.9545 19.3633L15.5704 20.5979C14.2013 21.163 12.7171 21.3928 11.2413 21.2683L11.1018 21.2559L11.0677 21.2528L11.0026 21.2458L10.9297 21.238C10.8891 21.2332 10.8486 21.228 10.808 21.2225L10.7251 21.2117L10.6399 21.1993C10.557 21.1872 10.4743 21.1741 10.3919 21.1598L10.3593 21.1536L10.3012 21.1435L10.2183 21.128L10.164 21.1164L10.0919 21.1016L10.0338 21.0892L9.96019 21.0737L9.88501 21.0559L9.81216 21.0389L9.75946 21.0257L9.69126 21.0086L9.62151 20.99L9.54789 20.9707L9.48434 20.9528L9.39986 20.9296L9.35181 20.9141L9.28671 20.8947L9.21464 20.873L9.13326 20.8467L9.08831 20.8319L9.02631 20.8118L8.95656 20.7878L8.90541 20.7692C8.89403 20.7653 8.88267 20.7615 8.87131 20.7575L8.81861 20.7382L8.74034 20.7095L8.69617 20.6924L8.63417 20.6692L8.56674 20.6421L8.49854 20.6149L8.43732 20.5901L8.36369 20.5591L8.31487 20.5374L8.26604 20.5165C8.25543 20.5119 8.24484 20.5073 8.23427 20.5026L8.18312 20.4793L8.10329 20.4429L8.06299 20.4243L7.98859 20.3886L7.94054 20.3654L7.87544 20.3344L7.80879 20.3003L7.73672 20.2639L7.69642 20.2429L7.61659 20.2003L7.57242 20.1771L7.52747 20.1523C7.51556 20.1456 7.50367 20.1389 7.49182 20.1321L7.41897 20.091L7.37247 20.0647L7.33294 20.0414L7.27714 20.0097L7.21359 19.9709L7.14152 19.9275L7.10122 19.9027L7.03612 19.8616L6.98885 19.8314L6.92762 19.7927L6.87337 19.7562L6.8323 19.7291C6.81831 19.7199 6.80436 19.7106 6.79045 19.7012L6.75635 19.678L6.72225 19.6547C6.71188 19.6475 6.70155 19.6403 6.69125 19.633L6.64707 19.602L6.58817 19.5602L6.5347 19.5214L6.47735 19.4796L6.43395 19.447L6.37505 19.4028L6.31615 19.3571L6.2495 19.3052L6.21462 19.2781L6.16502 19.2378L6.10767 19.1913L6.0387 19.1347L6.00305 19.1045L5.9674 19.0742C5.95625 19.0647 5.94515 19.0552 5.93407 19.0456L5.8992 19.0146L5.85192 18.9735L5.79767 18.9255L5.74497 18.8789L5.69692 18.834L5.645 18.786L5.60392 18.7472L5.53572 18.6821C5.51002 18.6572 5.48444 18.6321 5.459 18.6069L5.43653 18.5852L5.40475 18.5527L5.35128 18.4984L5.31253 18.4589L5.27378 18.4178C5.2295 18.3724 5.18609 18.3262 5.14358 18.2791L5.08158 18.2109L5.03353 18.1567L4.9785 18.0947L4.94595 18.0567L4.90488 18.0086L4.85993 17.9559L4.82428 17.9125C4.81728 17.904 4.8103 17.8955 4.80335 17.887L4.76848 17.8443L4.71733 17.7808L4.68555 17.7405L4.6468 17.6909L4.6313 17.6715C4.18786 17.0967 3.81331 16.4719 3.51531 15.81ZM2.72481 11.3196L11.5234 13.6733C11.3761 14.1864 11.2547 14.7065 11.1599 15.2318L19.543 17.4747C19.1266 18.0449 18.6469 18.5662 18.1132 19.0285L3.20918 15.0404L3.19678 15.0047L3.16966 14.9241C3.15647 14.8847 3.14356 14.8452 3.13091 14.8056L3.12548 14.7877C3.06583 14.5981 3.01233 14.4066 2.96506 14.2135L2.94181 14.1158L2.92786 14.0538L2.91158 13.9786L2.89763 13.9159L2.88368 13.8461L2.87051 13.781L2.85656 13.7082C2.83641 13.5989 2.81781 13.4888 2.80153 13.378L2.78836 13.2866L2.77983 13.2222L2.76976 13.1432C2.76457 13.1016 2.75966 13.06 2.75503 13.0184L2.75116 12.982C2.69326 12.4297 2.68444 11.8734 2.72481 11.3196ZM3.95938 7.32839L13.2191 9.80528C12.9339 10.2742 12.6727 10.7593 12.4363 11.2584L21.1899 13.6004C21.0799 14.2359 20.9047 14.8497 20.6722 15.4333L11.721 13.0386L2.79611 10.6516L2.80773 10.5741L2.81393 10.5361L2.82168 10.4842L2.83331 10.4168L2.84726 10.3408C2.86741 10.2261 2.89066 10.1122 2.91546 9.99825L2.93716 9.90215L2.95266 9.83628L2.97126 9.7611C2.98831 9.69135 3.00613 9.6216 3.02551 9.5534L3.04721 9.47435L3.06503 9.41003L3.08828 9.33253L3.10766 9.26898L3.13091 9.19458L3.15106 9.13103L3.17508 9.05741C3.37577 8.45541 3.63808 7.87573 3.95783 7.32761L3.95938 7.32839ZM7.40192 3.9184L16.1478 6.25734C15.6862 6.67623 15.2494 7.12157 14.8396 7.59111L20.9024 9.21318C21.1093 9.87348 21.2449 10.5648 21.3 11.2785L4.33215 6.74016L4.36703 6.68979L4.38795 6.65879L4.41895 6.61616L4.4546 6.56579L4.49723 6.50689L4.53908 6.45109L4.58868 6.38444L4.62743 6.33406L4.6716 6.27749L4.71423 6.22324L4.76073 6.16589L4.80335 6.11241L4.85373 6.05274L4.89558 6.00159L4.94673 5.94192L4.9878 5.89542L5.0436 5.83187L5.08468 5.78537L5.1366 5.72802L5.17845 5.68307L5.23503 5.62262L5.27998 5.57612L5.3288 5.52419L5.459 5.39244L5.5365 5.31649L5.58222 5.27309L5.64112 5.21807C6.17525 4.71752 6.76621 4.28132 7.40192 3.9184ZM12.0132 2.7001H12.0883L12.1519 2.70088L12.2054 2.70165L12.2472 2.7032L12.2999 2.70475L12.3356 2.70553L12.3945 2.70785L12.4309 2.7094L12.4774 2.71173L12.5192 2.71328L12.5867 2.71715L12.668 2.72258L12.7796 2.7311L12.8478 2.73653L12.8819 2.73963L12.9416 2.74583L13.0052 2.75203L13.0416 2.7559L13.1206 2.7652L13.1594 2.76985L13.2431 2.7807L13.3059 2.78845L13.3384 2.7931L13.3888 2.80085L13.5492 2.82565L13.6035 2.83495L13.6538 2.84348L13.7623 2.86363L13.8336 2.87758L13.9189 2.89462L13.9545 2.90237L14.0126 2.91477L14.0444 2.92252L14.0925 2.9326L14.125 2.94035L14.1754 2.95197L14.2134 2.96127L14.2684 2.97445L14.3428 2.99305L14.4296 3.0163L14.5172 3.03955L14.6047 3.06435L14.6435 3.07597L14.6977 3.09147L14.7582 3.11007L14.8148 3.1279L14.8535 3.1403L14.8923 3.1527L14.9512 3.17207L15.0279 3.19765L15.1069 3.22555L15.1441 3.23872L15.1937 3.25655L15.2658 3.2829L15.3511 3.31467L15.441 3.34955L15.5185 3.38055L15.5549 3.39605L15.6014 3.41465L15.6332 3.4286L15.682 3.44875L15.713 3.4627L15.7572 3.48207L15.8424 3.51927L15.9199 3.55492L15.9773 3.58205L16.0354 3.60995L16.0819 3.63165L16.1532 3.6673L16.2237 3.70217L16.3028 3.74247L16.3438 3.76417L16.3818 3.78432L16.4175 3.80292L16.464 3.8285L16.4957 3.84555L16.536 3.86802L16.6042 3.90677L16.6864 3.95327L16.7538 3.9928L16.798 4.01915L16.8391 4.04395L16.9135 4.08967L16.9817 4.1323L17.0576 4.18035L17.0855 4.19895L17.1351 4.23072L17.2002 4.27412L17.2312 4.29505L17.2793 4.3276L17.3273 4.36092L17.3451 4.3741C17.387 4.40277 17.4288 4.43222 17.4699 4.46244L17.5342 4.50894L17.5846 4.54614L17.628 4.57947L17.6947 4.62984L17.7582 4.67944L17.7892 4.70269L17.828 4.73447L17.8946 4.78794L17.9558 4.83832L18.0217 4.89334C18.5735 5.35834 19.0703 5.88767 19.5012 6.46736L8.29704 3.47045L8.34509 3.44952L8.39547 3.42782L8.45824 3.40147L8.52489 3.37435C8.61247 3.33947 8.70082 3.3046 8.78916 3.27282L8.86356 3.2457L8.93564 3.22012L9.00074 3.19687L9.07514 3.17285C9.14256 3.1496 9.21154 3.1279 9.27974 3.10697L9.35026 3.08605L9.41691 3.06667L9.49596 3.04342L9.56184 3.0256L9.63934 3.00545L9.70599 2.98685L9.77574 2.96902L9.84626 2.95197L9.91989 2.93492L9.98964 2.91942L10.0656 2.90315L10.1361 2.88765L10.2097 2.8737L10.281 2.85975L10.3585 2.8458L10.4291 2.8334L10.505 2.82023L10.5763 2.80938L10.6515 2.79775L10.7228 2.78768L10.8018 2.7776L10.8724 2.7683L10.9537 2.759L11.0235 2.75125L11.1049 2.7435C11.1769 2.73575 11.249 2.72955 11.3219 2.7249L11.404 2.7187L11.4738 2.71483L11.559 2.71018L11.6311 2.70708L11.7086 2.70398L11.7838 2.70243L11.8605 2.70088L12.0132 2.69933V2.7001Z" fill="currentColor" ></path> </symbol> + <symbol viewBox="0 0 24 24" fill="none" id="kilo"> + <path d="M5 3v18" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"></path> + <path + d="M17.5 4.5 9.5 12l8 7.5" + stroke="currentColor" + stroke-width="2.4" + stroke-linecap="round" + stroke-linejoin="round" + ></path> + </symbol> + <symbol viewBox="0 0 24 24" fill="none" id="jiekou"> + <path + d="M16 4H4V20H16C18.2091 20 20 18.2091 20 16V8H24V16C24 20.4183 20.4183 24 16 24H4C1.79086 24 1.61064e-08 22.2091 0 20V0H16V4Z" + fill="currentColor" + ></path> + <path d="M20 4H24V0H20V4Z" fill="currentColor"></path> + </symbol> <symbol viewBox="0 0 24 24" fill="none" id="io-net"> <path d="M2.3999 9.60101L4.41977 10.9695H2.3999V16.0618H4.41977V10.9695V7.91422H2.3999V9.60101Z" @@ -626,6 +803,12 @@ stroke-linejoin="round" ></path> </symbol> + <symbol viewBox="0 0 380 380" id="gitlab"> + <path + d="M265.26416,174.37243l-.2134-.55822-21.19899-55.30908c-.4236-1.08359-1.18542-1.99642-2.17699-2.62689-.98837-.63373-2.14749-.93253-3.32305-.87014-1.1689.06239-2.29195.48925-3.20809,1.21821-.90957.73554-1.56629,1.73047-1.87493,2.85346l-14.31327,43.80662h-57.90965l-14.31327-43.80662c-.30864-1.12299-.96536-2.11791-1.87493-2.85346-.91614-.72895-2.03911-1.15582-3.20809-1.21821-1.17548-.06239-2.33468.23641-3.32297.87014-.99166.63047-1.75348,1.5433-2.17707,2.62689l-21.19891,55.31237-.21348.55493c-6.28158,16.38521-.92929,34.90803,13.05891,45.48782.02621.01641.04922.03611.07552.05582l.18719.14119,32.29094,24.17392,15.97151,12.09024,9.71951,7.34871c2.34117,1.77316,5.57877,1.77316,7.92002,0l9.71943-7.34871,15.96822-12.09024,32.48142-24.31511c.02958-.02299.05588-.04269.08538-.06568,13.97834-10.57977,19.32735-29.09604,13.04905-45.47796Z" + fill="currentColor" + ></path> + </symbol> <symbol viewBox="0 0 40 40" id="github-models"> <path d="M20.0015 4.4704C11.4373 4.4704 4.50074 11.407 4.50074 19.9712C4.49793 23.2252 5.52031 26.3975 7.42272 29.0376C9.32512 31.6776 12.0109 33.6513 15.0986 34.6783C15.8737 34.8132 16.1651 34.3481 16.1651 33.9405C16.1651 33.5731 16.1449 32.3532 16.1449 31.0542C12.2511 31.7719 11.2436 30.1056 10.9336 29.2329C10.7584 28.7865 10.0035 27.4115 9.34473 27.0426C8.8022 26.7528 8.02716 26.0351 9.32458 26.0165C10.546 25.9963 11.4172 27.1403 11.7086 27.6053C13.1037 29.949 15.3311 29.2902 16.2224 28.8841C16.3588 27.8766 16.7649 27.1992 17.2114 26.8117C13.7624 26.4241 10.1585 25.0864 10.1585 19.1574C10.1585 17.4709 10.7584 16.0774 11.7473 14.9923C11.5923 14.6048 11.0498 13.016 11.9024 10.8846C11.9024 10.8846 13.1998 10.4769 16.1651 12.4719C17.4271 12.1226 18.7308 11.9468 20.0403 11.9495C21.3578 11.9495 22.6754 12.1231 23.9155 12.4719C26.8808 10.4568 28.1782 10.8846 28.1782 10.8846C29.0307 13.016 28.4882 14.6048 28.3332 14.9923C29.3206 16.0774 29.922 17.4523 29.922 19.1574C29.922 25.1066 26.2995 26.4241 22.8506 26.8117C23.4117 27.2953 23.8969 28.2253 23.8969 29.6793C23.8969 31.7518 23.8767 33.4181 23.8767 33.942C23.8767 34.3481 24.1681 34.8318 24.9432 34.6768C28.0193 33.6368 30.6922 31.6589 32.5859 29.0211C34.4796 26.3833 35.499 23.2183 35.5007 19.9712C35.5007 11.407 28.5641 4.4704 20 4.4704" @@ -644,6 +827,16 @@ fill="currentColor" ></path> </symbol> + <symbol viewBox="0 0 40 40" id="firmware"> + <g transform="matrix(1.149971,0,0,1.149971,-166.19831,2.0845471)"> + <path + fill-rule="evenodd" + clip-rule="evenodd" + d="m 172.24982,31.21868 h 7.05286 l -1.46587,-2.792842 -2.50031,-0.56255 -2.45857,-4.899805 3.20956,-5.39366 -1.27352,-2.509532 h 0.94075 l 1.69977,-1.097102 v -1.003566 h 0.71098 V 9.2006456 L 174.88883,8.1743823 174.04436,7.011809 h -4.20939 l -3.18164,3.546614 -3.17106,-6.3194202 -18.92307,-4.2721087 12.5905,14.1419309 h -1.44316 l -5.16203,3.661439 -2.60981,5.055178 -1.10108,0.311349 v -4.257417 l 1.09698,-0.720257 -2.41204,-3.676132 V 24.87269 l 3.32207,-0.936862 2.7234,-5.278272 2.87418,-2.038852 -4.19705,8.442439 v 3.325965 l 1.15171,2.831572 h 4.45518 v -1.428443 l -0.53832,-1.131806 -1.25751,-0.768529 v -0.657318 l 2.58945,-4.280136 v 2.792842 l 2.26644,2.614989 0.9823,1.749313 v 1.109088 h 5.15662 v -1.420438 l -0.56666,-1.276122 -1.34817,-0.728284 -1.59828,-2.366603 1.227,-2.275513 3.72559,0.583754 -0.87541,4.810663 -0.0108,2.672543 h 5.18498 v -1.362885 l -0.2419,-0.956983 -0.7378,-0.720063 0.56233,-1.122936 1.88194,2.918767 z m 1.89753,-17.471965 h 1.21987 l 0.77242,-0.49844 v -0.288652 h -0.6333 v -1.313575 h 1.34557 V 10.16544 L 174.0805,9.298183 173.37493,8.3253836 h -1.97867 z m -4.04409,-5.0676393 -0.923,1.0293789 4.59754,9.1729964 0.81029,-1.362407 z m -2.81664,3.1414493 0.95115,-1.060904 4.74272,9.462472 -0.80185,1.347868 z m -10.78667,3.601874 -4.94523,9.945983 V 28.1305 l 0.72157,1.773328 h 2.17144 l -0.15644,-0.32736 -1.55263,-0.948762 v -1.761212 l 3.65462,-6.042799 12.81381,2.008454 4.35629,6.754921 v 0.316758 h 3.56526 l -0.17244,-0.328875 -2.51502,-0.566443 -0.14021,-0.27803 -8.12582,-16.195842 -7.43798,2.887761 z m 9.08324,-4.067925 -2.99624,-5.9715919 -3.20783,-0.7241093 4.77108,7.2521282 z m -2.68532,1.04275 -5.3652,-8.1552571 -3.82404,-0.8631672 7.71645,9.5903223 z m -2.75757,1.070727 -8.49168,-10.5541849 -3.38785,-0.7647211 10.52054,11.818147 -0.0569,0.0506 z m -2.18485,11.788137 v -2.857102 l 3.42916,0.537235 -1.38344,2.567173 2.2223,3.292645 1.23739,0.668135 0.19517,0.439654 h -2.45208 V 29.76622 l -1.21619,-2.164949 z m 11.58527,0.51668 -1.11818,-1.733951 -0.63784,-0.09996 -0.86936,4.784916 v 1.180055 h 2.52692 l -0.0816,-0.324764 -1.15994,-1.130508 z m 0.29555,-21.8290604 h -0.001 v 2.1928393 h 4.20916 V 3.9437076 h -0.003 l -1.04894,1.0503231 -1.05046,-1.0503231 h -0.005 l -1.05046,1.0503231 z" + fill="currentColor" + ></path> + </g> + </symbol> <symbol viewBox="0 0 24 24" fill="none" id="fireworks-ai"> <path d="M14.45 5.74999L11.9991 11.6956L9.54562 5.74999H7.97237L10.6604 12.2495C10.7678 12.5138 10.9515 12.7402 11.1882 12.8996C11.4248 13.059 11.7036 13.1442 11.9889 13.1444C12.2742 13.1446 12.5531 13.0597 12.79 12.9006C13.0268 12.7415 13.2109 12.5154 13.3186 12.2512L16.0232 5.74999H14.45ZM15.4965 14.808L19.98 10.2195L19.3684 8.75911L14.4719 13.7807C14.272 13.9856 14.1369 14.2448 14.0835 14.5261C14.0301 14.8073 14.0608 15.098 14.1718 15.3619C14.2807 15.624 14.4648 15.848 14.7008 16.0056C14.9369 16.1632 15.2144 16.2473 15.4983 16.2474L15.5 16.25L22.5 16.2325L21.8884 14.7721L15.4983 14.808H15.4965ZM4.02 10.216L4.63162 8.75561L9.52813 13.7772C9.93763 14.1964 10.0557 14.8176 9.82825 15.3584C9.71925 15.6204 9.53511 15.8443 9.29905 16.0019C9.06299 16.1595 8.78557 16.2437 8.50175 16.2439L1.50175 16.2281L1.5 16.2299L2.11163 14.7695L8.50175 14.8062L4.02 10.216Z" @@ -656,6 +849,11 @@ fill="currentColor" ></path> </symbol> + <symbol fill="inherit" viewBox="0 0 100 25" id="evroc"> + <path + d="M79.01 5.863c-4.066 0-6.511 2.92-6.511 6.535 0 3.635 2.445 6.555 6.511 6.555 4.046 0 6.512-2.92 6.512-6.555s-2.466-6.535-6.512-6.535Zm0 10.968c-2.633 0-4.172-1.933-4.172-4.433s1.539-4.455 4.172-4.455c2.635 0 4.151 1.933 4.151 4.434 0 2.521-1.516 4.454-4.15 4.454Zm14.393 2.096c3.393 0 5.542-1.808 5.837-4.539h-2.36c-.316 1.555-1.517 2.437-3.477 2.437-2.423 0-3.878-1.68-3.878-4.433 0-2.774 1.476-4.434 3.878-4.434 1.96 0 3.14.862 3.477 2.5h2.36c-.295-2.773-2.444-4.622-5.837-4.622-3.856 0-6.217 2.669-6.217 6.535 0 3.887 2.36 6.556 6.217 6.556Zm-29.543-.311h2.36v-6.01c0-2.752 1.348-4.244 3.772-4.244h2.276V6.177h-2.255c-2.128 0-3.288.735-3.898 2.605l-.443-.063.527-2.542h-2.36v12.439h.02Zm-24.445-7.332c.106-2.101 1.517-3.53 3.793-3.53 2.276 0 3.646 1.345 3.646 3.53h-7.439Zm9.778.4c0-3.426-2.381-5.821-5.943-5.821-3.73 0-6.174 2.563-6.174 6.535 0 4.013 2.423 6.555 6.28 6.555 2.929 0 5.247-1.597 5.669-3.887h-2.36c-.507 1.156-1.666 1.828-3.31 1.828-2.38 0-3.877-1.408-3.94-3.803h9.694c.042-.588.084-.861.084-1.408Zm5.69 6.932h1.939l5.5-12.44h-2.529L56 15.99l-.316.021-3.793-9.833h-2.508l5.5 12.439ZM32.23 12.35c0-.882-.359-1.701-.99-2.437a8.594 8.594 0 0 1-1.497 1.093c.337.42.527.861.527 1.345 0 2.731-5.837 4.811-14.14 4.811-8.281.021-14.118-2.059-14.118-4.811 0-.463.168-.925.505-1.345a8.13 8.13 0 0 1-1.475-1.093c-.632.736-.99 1.555-.99 2.438 0 4.034 7.207 6.534 16.1 6.534 8.87.021 16.078-2.5 16.078-6.535Zm-3.351 1.534c-.906-.462-1.96-.861-3.16-1.197-1.37.378-2.909.672-4.553.861 2.318.294 4.341.778 5.9 1.408.76-.336 1.37-.693 1.813-1.072Zm-17.849-.357a31.902 31.902 0 0 1-4.467-.84c-1.18.336-2.255.735-3.16 1.197.42.379 1.01.715 1.748 1.05 1.539-.63 3.52-1.113 5.88-1.407Zm21.2-6.808c0-4.013-7.207-6.534-16.079-6.534C7.26.185.051 2.706.051 6.719c0 4.035 7.208 6.535 16.1 6.535 8.872.021 16.079-2.5 16.079-6.535Zm-1.94 0c0 2.732-5.836 4.812-14.139 4.812-8.302.021-14.14-2.06-14.14-4.812 0-2.731 5.838-4.811 14.14-4.811 7.86 0 14.14 2.08 14.14 4.811Zm-3.223 2.564c.758-.336 1.37-.694 1.812-1.072-2.95-1.513-7.544-2.353-12.728-2.353s-9.799.84-12.728 2.353c.422.378 1.012.715 1.75 1.05 2.507-1.05 6.363-1.68 10.978-1.68 4.404 0 8.324.651 10.916 1.702ZM1.042 15.628c-.632.736-.99 1.534-.99 2.438 0 4.034 7.207 6.534 16.1 6.534 8.892 0 16.099-2.521 16.099-6.534 0-.883-.359-1.702-.99-2.438-.422.4-.907.757-1.497 1.093.337.42.527.861.527 1.345 0 2.731-5.837 4.811-14.14 4.811-8.302 0-14.14-2.08-14.14-4.811 0-.463.17-.925.506-1.345a10.73 10.73 0 0 1-1.475-1.093Z" + ></path> + </symbol> <symbol viewBox="0 0 40 40" id="deepseek"> <path d="M35.6638 9.91965C35.3251 9.75432 35.1785 10.0703 34.9811 10.2316C34.9131 10.2836 34.8558 10.3516 34.7985 10.413C34.3025 10.9423 33.7238 11.289 32.9678 11.2476C31.8625 11.1863 30.9186 11.533 30.0839 12.3783C29.9066 11.3356 29.3173 10.7143 28.4213 10.3143C27.9519 10.1063 27.4773 9.89965 27.148 9.44766C26.9186 9.12633 26.856 8.76767 26.7413 8.41568C26.668 8.20235 26.5946 7.98502 26.3506 7.94902C26.084 7.90769 25.98 8.13035 25.876 8.31702C25.4587 9.07967 25.2973 9.91965 25.3133 10.7703C25.3493 12.6849 26.1573 14.2102 27.764 15.2942C27.9466 15.4182 27.9933 15.5435 27.9359 15.7249C27.8266 16.0982 27.696 16.4609 27.5813 16.8355C27.508 17.0742 27.3986 17.1248 27.1426 17.0222C26.2777 16.6504 25.4919 16.1164 24.828 15.4489C23.6854 14.3449 22.6534 13.1263 21.3654 12.1716C21.067 11.9511 20.7606 11.7416 20.4468 11.5436C19.1335 10.2676 20.6201 9.21967 20.9641 9.09567C21.3241 8.965 21.0881 8.51968 19.9254 8.52501C18.7628 8.53035 17.6988 8.91834 16.3428 9.43699C16.1413 9.51421 15.934 9.57529 15.7229 9.61966C14.4557 9.38091 13.1598 9.33506 11.8789 9.48366C9.36565 9.76365 7.35902 10.953 5.88305 12.9809C4.10975 15.4182 3.69243 18.1888 4.20308 21.0768C4.74041 24.122 6.29504 26.6433 8.683 28.6139C11.1603 30.6579 14.0122 31.6592 17.2668 31.4672C19.2428 31.3539 21.4441 31.0886 23.9254 28.9873C24.552 29.2993 25.208 29.4233 26.2986 29.5166C27.1386 29.5953 27.9466 29.4766 28.5719 29.3459C29.5519 29.1379 29.4839 28.23 29.1306 28.0646C26.2573 26.726 26.888 27.2713 26.3133 26.83C27.7746 25.102 29.9746 23.3074 30.8359 17.4928C30.9026 17.0302 30.8452 16.7395 30.8359 16.3662C30.8306 16.1395 30.8826 16.0502 31.1426 16.0249C31.8639 15.95 32.5637 15.7349 33.2025 15.3915C35.0638 14.3742 35.8158 12.7049 35.9931 10.7023C36.0198 10.3956 35.9878 10.081 35.6638 9.91965ZM19.4414 27.9433C16.6562 25.754 15.3055 25.0327 14.7482 25.0634C14.2256 25.0954 14.3202 25.6913 14.4349 26.0807C14.5549 26.4647 14.7109 26.7286 14.9295 27.066C15.0815 27.2886 15.1855 27.6206 14.7789 27.87C13.8816 28.4246 12.3229 27.6833 12.2496 27.6473C10.435 26.578 8.91632 25.1673 7.84834 23.2381C6.81637 21.3808 6.21638 19.3888 6.11771 17.2622C6.09105 16.7475 6.24171 16.5662 6.7537 16.4729C7.42583 16.3442 8.11451 16.3267 8.79233 16.4209C11.6349 16.8368 14.0536 18.1075 16.0828 20.1194C17.2402 21.2661 18.1161 22.6354 19.0188 23.974C19.9788 25.3953 21.0108 26.75 22.3254 27.8593C22.7894 28.2486 23.1587 28.5446 23.5134 28.7619C22.4441 28.8819 20.6601 28.9086 19.4414 27.9433ZM20.7748 19.3568C20.7745 19.2906 20.7904 19.2253 20.8211 19.1666C20.8517 19.1078 20.8962 19.0575 20.9507 19.0198C21.0052 18.9821 21.068 18.9583 21.1337 18.9503C21.1995 18.9424 21.2662 18.9505 21.3281 18.9741C21.407 19.0024 21.475 19.0546 21.5228 19.1235C21.5706 19.1923 21.5958 19.2743 21.5947 19.3581C21.5949 19.4123 21.5843 19.4659 21.5636 19.5159C21.5428 19.5659 21.5123 19.6113 21.4738 19.6494C21.4354 19.6875 21.3897 19.7176 21.3395 19.7378C21.2893 19.7581 21.2356 19.7682 21.1814 19.7675C21.1277 19.7676 21.0745 19.7571 21.0248 19.7365C20.9752 19.7158 20.9302 19.6855 20.8925 19.6473C20.8548 19.609 20.825 19.5636 20.805 19.5138C20.785 19.4639 20.7739 19.4105 20.7748 19.3568ZM24.9213 21.4848C24.6547 21.5928 24.3893 21.6861 24.1347 21.6981C23.7516 21.7114 23.3756 21.5918 23.0707 21.3594C22.7054 21.0528 22.4441 20.8821 22.3347 20.3488C22.297 20.0881 22.3042 19.823 22.3561 19.5648C22.4494 19.1288 22.3454 18.8488 22.0374 18.5955C21.7881 18.3875 21.4694 18.3302 21.1201 18.3302C21.0005 18.3232 20.8843 18.2875 20.7814 18.2262C20.6348 18.1542 20.5148 17.9728 20.6294 17.7488C20.6668 17.6768 20.8428 17.5008 20.8854 17.4688C21.3601 17.1995 21.9081 17.2875 22.4134 17.4902C22.8827 17.6822 23.2374 18.0342 23.748 18.5328C24.2694 19.1341 24.364 19.3008 24.6613 19.7515C24.896 20.1048 25.1093 20.4674 25.2547 20.8821C25.344 21.1421 25.2293 21.3541 24.9213 21.4848Z" @@ -730,6 +928,14 @@ fill="currentColor" ></path> </symbol> + <symbol viewBox="0 0 24 24" fill="currentColor" id="cloudferro-sherlock"> + <path + d="M12,24l-8.996,-8.996l8.996,-8.997l2.996,2.997l-5.999,6l2.996,2.997l6,-5.999l2.997,2.996l-8.99,8.996Z" + opacity="0.01" + ></path> + <path d="M9,15l6,-6l-3,-3l-9,9l-3,-3l12,-12l12,12l-3,3l-3,-3l-6,6l-3,-3Z"></path> + <path d="M0,12L12,0L24,12L12,24L0,12Z" fill="none" stroke="currentColor" stroke-width="0.2"></path> + </symbol> <symbol viewBox="0 0 24 24" fill="none" id="chutes"> <path shape-rendering="geometricPrecision" @@ -764,6 +970,12 @@ fill="currentColor" ></path> </symbol> + <symbol viewBox="0 0 463 419" fill="none" id="berget"> + <path + d="M208.739 17L255.261 17L446 403L398 403L313.5 255L261.5 176L233.163 96.1677L237.815 98.6522H226.185L230.837 96.1677L113 331L64.5 403L18 403L208.739 17Z" + fill="currentColor" + ></path> + </symbol> <symbol viewBox="0 0 24 24" fill="none" id="baseten"> <path d="M4.97934 6.78009H15.6237V10.26H8.59995C8.57096 10.2595 8.54214 10.2647 8.51516 10.2753C8.48819 10.286 8.4636 10.3019 8.44283 10.3221C8.42205 10.3423 8.40551 10.3665 8.39415 10.3932C8.38279 10.4199 8.37684 10.4485 8.37665 10.4775V13.5225C8.37665 13.6465 8.47815 13.74 8.59995 13.74H15.6237V17.22H12.2264C12.1974 17.2194 12.1685 17.2246 12.1416 17.2352C12.1146 17.2459 12.09 17.2618 12.0692 17.282C12.0485 17.3023 12.0319 17.3264 12.0206 17.3531C12.0092 17.3798 12.0032 17.4085 12.0031 17.4375V20.4824C12.0031 20.6064 12.1053 20.6999 12.2264 20.6999H15.4004C15.4295 20.701 15.4585 20.6962 15.4857 20.6857C15.5129 20.6752 15.5377 20.6593 15.5586 20.639C15.5795 20.6187 15.596 20.5943 15.6072 20.5674C15.6184 20.5405 15.624 20.5116 15.6237 20.4824V17.22H19.0268C19.0558 17.2205 19.0846 17.2154 19.1116 17.2047C19.1385 17.194 19.1631 17.1781 19.1839 17.1579C19.2047 17.1377 19.2212 17.1135 19.2326 17.0868C19.2439 17.0601 19.2499 17.0315 19.2501 17.0025V13.9575C19.2501 13.8335 19.1486 13.74 19.0268 13.74H15.6237V10.26H19.0268C19.0558 10.2606 19.0846 10.2554 19.1116 10.2448C19.1385 10.2341 19.1631 10.2182 19.1839 10.198C19.2047 10.1777 19.2212 10.1536 19.2326 10.1269C19.2439 10.1002 19.2499 10.0715 19.2501 10.0425V6.99758C19.2501 6.87361 19.1486 6.78009 19.0268 6.78009H15.6237V3.51762C15.6237 3.39365 15.5222 3.30012 15.4004 3.30012H4.97934C4.92022 3.29895 4.86302 3.32112 4.82014 3.36183C4.77725 3.40255 4.75214 3.45852 4.75024 3.51762V6.56259C4.75024 6.68656 4.85174 6.78009 4.97934 6.78009Z" @@ -878,5 +1090,32 @@ d="M34.2378 19.5597C34.2378 20.8568 33.1863 21.9083 31.8892 21.9083C30.5921 21.9083 29.5406 20.8568 29.5406 19.5597C29.5406 18.2626 30.5921 17.2111 31.8892 17.2111C33.1863 17.2111 34.2378 18.2626 34.2378 19.5597Z" ></path> </symbol> + <symbol style="display: block" viewBox="0 0 2048 2048" preserveAspectRatio="none" id="302ai"> + <path + transform="translate(0,0)" + fill="rgb(156,155,155)" + d="M 388.193 1682.23 C 380.878 1674.23 349.014 1650.79 338.487 1642.13 C 148.161 1485.91 28.1107 1260.14 5.01063 1015 C -18.4493 771.014 55.9168 527.694 211.767 338.509 C 367.861 148.455 593.42 28.6444 838.288 5.7197 C 1092.75 -18.7181 1345.95 63.524 1537.48 232.828 C 1567.76 259.726 1596.32 288.496 1623 318.968 C 1631.78 329.058 1640.32 339.36 1648.6 349.865 C 1654.15 356.824 1662.64 368.871 1669.4 374.06 C 1866.4 518.124 1998.49 734.204 2036.88 975.222 C 2041.98 1007.66 2045.11 1039.38 2046.62 1072.12 C 2046.85 1077.09 2047.16 1082.22 2048 1087.12 L 2048 1155.79 L 2047.85 1156.71 C 2045.71 1170.93 2045.27 1196.57 2043.86 1212.22 C 2040.62 1246.59 2035.38 1280.75 2028.17 1314.51 C 1981.27 1534.16 1856.1 1729.25 1675.99 1863.43 C 1479.61 2010.02 1232.99 2072.49 990.498 2037.07 C 801.767 2009.86 626.135 1924.74 487.842 1793.46 C 455.956 1763.37 418.158 1722.72 392.022 1687.5 C 390.729 1685.76 389.452 1684 388.193 1682.23 z" + ></path> + <path + transform="translate(0,0)" + fill="rgb(117,116,116)" + d="M 1669.4 374.06 C 1866.4 518.124 1998.49 734.204 2036.88 975.222 C 2041.98 1007.66 2045.11 1039.38 2046.62 1072.12 C 2046.85 1077.09 2047.16 1082.22 2048 1087.12 L 2048 1155.79 L 2047.85 1156.71 C 2045.71 1170.93 2045.27 1196.57 2043.86 1212.22 C 2040.62 1246.59 2035.38 1280.75 2028.17 1314.51 C 1981.27 1534.16 1856.1 1729.25 1675.99 1863.43 C 1479.61 2010.02 1232.99 2072.49 990.498 2037.07 C 801.767 2009.86 626.135 1924.74 487.842 1793.46 C 455.956 1763.37 418.158 1722.72 392.022 1687.5 C 390.729 1685.76 389.452 1684 388.193 1682.23 C 394.373 1684.07 421.092 1702.62 428.047 1707.15 C 439.611 1714.6 451.324 1721.83 463.177 1728.82 C 490.564 1744.99 528.003 1763.59 557.361 1776.32 C 782.899 1873.92 1037.96 1878.01 1266.51 1787.69 C 1495.36 1696.62 1678.57 1518.24 1775.72 1291.9 C 1877.79 1053.06 1875.1 782.375 1768.31 545.611 C 1753.03 511.993 1733.8 474.565 1714.15 443.177 C 1706.81 431.355 1699.2 419.704 1691.32 408.231 C 1685.67 400.055 1672.56 382.889 1669.4 374.06 z" + ></path> + <path + transform="translate(0,0)" + fill="rgb(254,254,254)" + d="M 907.581 300.401 C 923.66 299.084 947.483 300.532 962.897 302.556 C 1041.39 313.102 1112.41 354.577 1160.17 417.755 C 1202.42 473.452 1228.57 555 1218.78 624.854 C 1256.03 619.819 1285.79 618.643 1323.38 625.442 C 1401.3 639.582 1470.3 684.357 1514.95 749.754 C 1560.04 815.479 1576.85 896.56 1561.6 974.792 C 1546.59 1052.29 1501.28 1120.59 1435.71 1164.55 C 1366.19 1211.67 1287.89 1223.85 1206.7 1207.99 L 1208.16 1225.92 C 1213.72 1304.44 1187.72 1381.94 1135.93 1441.23 C 1080.14 1505.71 1008.69 1536.8 924.661 1542.84 C 910.37 1543.02 898.883 1543.12 884.551 1541.84 C 806.009 1534.5 733.606 1496.24 683.294 1435.48 C 630.495 1371.76 609.152 1293.49 617.004 1211.82 C 577.182 1218.28 543.704 1219.15 503.598 1211.31 C 425.862 1195.87 357.514 1150.02 313.752 1083.94 C 269.997 1017.95 254.398 937.224 270.419 859.682 C 286.452 782.387 332.522 714.62 398.502 671.28 C 468.674 625.191 546.96 613.555 628.149 630.32 C 625.459 583.013 627.036 545.389 643.173 499.662 C 684.204 383.394 785.737 308.984 907.581 300.401 z" + ></path> + <path + transform="translate(0,0)" + fill="rgb(156,155,155)" + d="M 907.659 407.406 C 928.022 404.422 959.425 408.947 978.901 414.989 C 1028.11 429.972 1069.15 464.261 1092.65 510.025 C 1116.27 555.792 1120.24 609.2 1103.65 657.957 C 1098.74 672.384 1090.33 686.336 1086.3 699.186 C 1082.14 712.53 1083.57 726.994 1090.26 739.265 C 1100.24 757.657 1118.84 768.259 1139.57 767.119 C 1155.78 766.227 1164.63 759.273 1178.02 751.678 C 1221.56 726.903 1273.23 720.668 1321.41 734.376 C 1370.6 748.209 1412.18 781.215 1436.82 825.985 C 1461.35 870.569 1467.02 923.112 1452.58 971.905 C 1438.06 1020.82 1404.54 1061.88 1359.51 1085.9 C 1280.31 1128.12 1181.39 1108.75 1124.87 1039.74 C 1113.7 1026.12 1105.83 1013.42 1087.4 1008.03 C 1041 993.798 1000.36 1044.75 1026.36 1086.49 C 1041.95 1111.53 1062.76 1127.17 1078.18 1153.03 C 1090.26 1175.57 1097.84 1197.66 1100.84 1223.2 C 1107.04 1273.73 1092.65 1324.64 1060.9 1364.44 C 1029.42 1404.28 983.238 1429.79 932.752 1435.23 C 882.189 1440.86 831.491 1425.87 792.121 1393.65 C 752.588 1361.54 727.605 1314.91 722.781 1264.21 C 718.894 1225.82 727.653 1167.83 758.478 1141.35 C 771.141 1130.47 781.921 1118.81 792.404 1105.84 C 869.373 1010.12 879.456 876.886 817.771 770.669 C 809.316 756.055 799.574 742.224 788.661 729.342 C 782.235 721.815 773.191 712.791 767.461 705.187 C 749.008 680.699 737.483 646.859 734.444 616.659 C 729.188 565.849 744.584 515.06 777.168 475.721 C 810.289 435.451 856.055 412.394 907.659 407.406 z" + ></path> + <path + transform="translate(0,0)" + fill="rgb(156,155,155)" + d="M 554.228 729.711 C 659.104 725.931 747.227 807.802 751.164 912.672 C 755.1 1017.54 673.362 1105.79 568.498 1109.88 C 463.411 1113.98 374.937 1032.03 370.992 926.942 C 367.047 821.849 449.129 733.498 554.228 729.711 z" + ></path> + </symbol> </defs> </svg> diff --git a/packages/ui/src/components/provider-icons/types.ts b/packages/ui/src/components/provider-icons/types.ts index 89fbc0625f..f9ddfdf0e9 100644 --- a/packages/ui/src/components/provider-icons/types.ts +++ b/packages/ui/src/components/provider-icons/types.ts @@ -10,6 +10,7 @@ export const iconNames = [ "xai", "wandb", "vultr", + "vivgrid", "vercel", "venice", "v0", @@ -17,32 +18,47 @@ export const iconNames = [ "togetherai", "synthetic", "submodel", + "stepfun", + "stackit", "siliconflow", "siliconflow-cn", "scaleway", "sap-ai-core", "requesty", + "qiniu-ai", + "qihang-ai", + "privatemode-ai", "poe", "perplexity", "ovhcloud", "openrouter", "opencode", + "opencode-go", "openai", "ollama-cloud", "nvidia", + "novita-ai", + "nova", "nebius", "nano-gpt", "morph", "moonshotai", "moonshotai-cn", "modelscope", + "moark", "mistral", "minimax", + "minimax-coding-plan", "minimax-cn", + "minimax-cn-coding-plan", + "meganova", "lucidquery", "lmstudio", "llama", + "kuae-cloud-coding-plan", "kimi-for-coding", + "kilo", + "jiekou", "io-net", "inference", "inception", @@ -53,19 +69,24 @@ export const iconNames = [ "google", "google-vertex", "google-vertex-anthropic", + "gitlab", "github-models", "github-copilot", "friendli", + "firmware", "fireworks-ai", "fastrouter", + "evroc", "deepseek", "deepinfra", "cortecs", "cohere", "cloudflare-workers-ai", "cloudflare-ai-gateway", + "cloudferro-sherlock", "chutes", "cerebras", + "berget", "baseten", "bailing", "azure", @@ -76,6 +97,7 @@ export const iconNames = [ "alibaba-cn", "aihubmix", "abacus", + "302ai", ] as const export type IconName = (typeof iconNames)[number] diff --git a/packages/ui/src/components/radio-group.css b/packages/ui/src/components/radio-group.css index 4faaa33f43..e9cc711846 100644 --- a/packages/ui/src/components/radio-group.css +++ b/packages/ui/src/components/radio-group.css @@ -48,9 +48,9 @@ transition: opacity 200ms ease-out, box-shadow 100ms ease-in-out, - width 200ms ease-out, - height 200ms ease-out, - transform 200ms ease-out; + width 200ms cubic-bezier(0.22, 1.2, 0.36, 1), + height 200ms cubic-bezier(0.22, 1.2, 0.36, 1), + transform 300ms cubic-bezier(0.22, 1.2, 0.36, 1); will-change: transform; z-index: 0; } diff --git a/packages/ui/src/components/radio-group.stories.tsx b/packages/ui/src/components/radio-group.stories.tsx new file mode 100644 index 0000000000..4900ead846 --- /dev/null +++ b/packages/ui/src/components/radio-group.stories.tsx @@ -0,0 +1,92 @@ +// @ts-nocheck +import * as mod from "./radio-group" +import { create } from "../storybook/scaffold" + +const docs = `### Overview +Segmented radio group for choosing a single option. + +Use for view toggles or mode selection. + +### API +- Required: \`options\`. +- Optional: \`current\`, \`defaultValue\`, \`value\`, \`label\`, \`onSelect\`. +- Optional layout: \`size\`, \`fill\`, \`pad\`. + +### Variants and states +- Size variants: small, medium. +- Optional fill and padding behavior. + +### Behavior +- Maps options to segmented items and manages selection. + +### Accessibility +- TODO: confirm role/aria attributes from Kobalte SegmentedControl. + +### Theming/tokens +- Uses \`data-component="radio-group"\` with size/pad data attributes. + +` + +const story = create({ + title: "UI/RadioGroup", + mod, + args: { + options: ["One", "Two", "Three"], + defaultValue: "One", + }, +}) + +export default { + title: "UI/RadioGroup", + id: "components-radio-group", + component: story.meta.component, + tags: ["autodocs"], + parameters: { + docs: { + description: { + component: docs, + }, + }, + }, + argTypes: { + size: { + control: "select", + options: ["small", "medium"], + }, + pad: { + control: "select", + options: ["none", "normal"], + }, + fill: { + control: "boolean", + }, + }, +} + +export const Basic = story.Basic + +export const Sizes = { + render: () => ( + <div style={{ display: "grid", gap: "12px" }}> + <mod.RadioGroup options={["One", "Two"]} defaultValue="One" size="small" /> + <mod.RadioGroup options={["One", "Two"]} defaultValue="One" size="medium" /> + </div> + ), +} + +export const Filled = { + args: { + fill: true, + pad: "none", + }, +} + +export const CustomLabels = { + render: () => ( + <mod.RadioGroup + options={["list", "grid"]} + defaultValue="list" + label={(value) => (value === "list" ? "List view" : "Grid view")} + /> + ), +} diff --git a/packages/ui/src/components/resize-handle.stories.tsx b/packages/ui/src/components/resize-handle.stories.tsx new file mode 100644 index 0000000000..474cf71e2d --- /dev/null +++ b/packages/ui/src/components/resize-handle.stories.tsx @@ -0,0 +1,156 @@ +// @ts-nocheck +import { createSignal } from "solid-js" +import * as mod from "./resize-handle" + +const docs = `### Overview +Drag handle for resizing panels or split views. + +Use alongside resizable panels and split layouts. + +### API +- Required: \`direction\`, \`size\`, \`min\`, \`max\`, \`onResize\`. +- Optional: \`edge\`, \`onCollapse\`, \`collapseThreshold\`. + +### Variants and states +- Horizontal and vertical directions. + +### Behavior +- Drag updates size and calls \`onResize\` with clamped values. + +### Accessibility +- TODO: provide keyboard resizing guidance if needed. + +### Theming/tokens +- Uses \`data-component="resize-handle"\` with direction/edge data attributes. + +` + +export default { + title: "UI/ResizeHandle", + id: "components-resize-handle", + component: mod.ResizeHandle, + tags: ["autodocs"], + parameters: { + docs: { + description: { + component: docs, + }, + }, + }, +} + +export const Basic = { + render: () => { + const [size, setSize] = createSignal(240) + return ( + <div style={{ display: "grid", gap: "8px" }}> + <div style={{ color: "var(--text-weak)", "font-size": "12px" }}>Size: {size()}px</div> + <div + style={{ + width: `${size()}px`, + height: "48px", + "background-color": "var(--background-stronger)", + "border-radius": "6px", + }} + /> + <mod.ResizeHandle + direction="horizontal" + size={size()} + min={120} + max={480} + onResize={setSize} + style="height:24px;border:1px dashed color-mix(in oklab, var(--text-base) 20%, transparent)" + /> + </div> + ) + }, +} + +export const Vertical = { + render: () => { + const [size, setSize] = createSignal(180) + return ( + <div style={{ display: "grid", gap: "8px", width: "220px" }}> + <div style={{ color: "var(--text-weak)", "font-size": "12px" }}>Size: {size()}px</div> + <div + style={{ + height: `${size()}px`, + "background-color": "var(--background-stronger)", + "border-radius": "6px", + }} + /> + <mod.ResizeHandle + direction="vertical" + size={size()} + min={120} + max={320} + onResize={setSize} + style="width:24px;border:1px dashed color-mix(in oklab, var(--text-base) 20%, transparent)" + /> + </div> + ) + }, +} + +export const Collapse = { + render: () => { + const [size, setSize] = createSignal(200) + const [collapsed, setCollapsed] = createSignal(false) + return ( + <div style={{ display: "grid", gap: "8px" }}> + <div style={{ color: "var(--text-weak)", "font-size": "12px" }}> + {collapsed() ? "Collapsed" : `Size: ${size()}px`} + </div> + <div + style={{ + width: `${collapsed() ? 0 : size()}px`, + height: "48px", + "background-color": "var(--background-stronger)", + "border-radius": "6px", + }} + /> + <mod.ResizeHandle + direction="horizontal" + size={size()} + min={80} + max={360} + collapseThreshold={100} + onResize={(next) => { + setCollapsed(false) + setSize(next) + }} + onCollapse={() => setCollapsed(true)} + style="height:24px;border:1px dashed color-mix(in oklab, var(--text-base) 20%, transparent)" + /> + </div> + ) + }, +} + +export const EdgeStart = { + render: () => { + const [size, setSize] = createSignal(240) + return ( + <div style={{ display: "grid", gap: "8px" }}> + <div style={{ color: "var(--text-weak)", "font-size": "12px" }}>Size: {size()}px</div> + <div + style={{ + width: `${size()}px`, + height: "48px", + "background-color": "var(--background-stronger)", + "border-radius": "6px", + }} + /> + <mod.ResizeHandle + direction="horizontal" + edge="start" + size={size()} + min={120} + max={480} + onResize={setSize} + style="height:24px;border:1px dashed color-mix(in oklab, var(--text-base) 20%, transparent)" + /> + </div> + ) + }, +} diff --git a/packages/ui/src/components/scroll-view.css b/packages/ui/src/components/scroll-view.css index f81ae29766..f6a49e241c 100644 --- a/packages/ui/src/components/scroll-view.css +++ b/packages/ui/src/components/scroll-view.css @@ -19,7 +19,7 @@ position: absolute; right: 0; top: 0; - width: 16px; + width: 12px; transition: opacity 200ms ease; cursor: default; user-select: none; @@ -29,10 +29,11 @@ .scroll-view__thumb::after { content: ""; position: absolute; - right: 4px; + left: 50%; + transform: translateX(-50%); top: 0; bottom: 0; - width: 6px; + width: 4px; border-radius: 9999px; background-color: var(--border-weak-base); backdrop-filter: blur(4px); diff --git a/packages/ui/src/components/scroll-view.test.ts b/packages/ui/src/components/scroll-view.test.ts new file mode 100644 index 0000000000..d28b51fea8 --- /dev/null +++ b/packages/ui/src/components/scroll-view.test.ts @@ -0,0 +1,19 @@ +import { describe, expect, test } from "bun:test" +import { scrollKey } from "./scroll-view" + +describe("scrollKey", () => { + test("maps plain navigation keys", () => { + expect(scrollKey({ key: "PageDown", altKey: false, ctrlKey: false, metaKey: false, shiftKey: false })).toBe( + "page-down", + ) + expect(scrollKey({ key: "ArrowUp", altKey: false, ctrlKey: false, metaKey: false, shiftKey: false })).toBe("up") + }) + + test("ignores modified keybinds", () => { + expect( + scrollKey({ key: "ArrowDown", altKey: false, ctrlKey: false, metaKey: true, shiftKey: false }), + ).toBeUndefined() + expect(scrollKey({ key: "PageUp", altKey: false, ctrlKey: true, metaKey: false, shiftKey: false })).toBeUndefined() + expect(scrollKey({ key: "End", altKey: false, ctrlKey: false, metaKey: false, shiftKey: true })).toBeUndefined() + }) +}) diff --git a/packages/ui/src/components/scroll-view.tsx b/packages/ui/src/components/scroll-view.tsx index acc54c8c3e..c3d878af63 100644 --- a/packages/ui/src/components/scroll-view.tsx +++ b/packages/ui/src/components/scroll-view.tsx @@ -1,11 +1,32 @@ import { createSignal, onCleanup, onMount, splitProps, type ComponentProps, Show, mergeProps } from "solid-js" +import { useI18n } from "../context/i18n" export interface ScrollViewProps extends ComponentProps<"div"> { viewportRef?: (el: HTMLDivElement) => void orientation?: "vertical" | "horizontal" // currently only vertical is fully implemented for thumb } +export const scrollKey = (event: Pick<KeyboardEvent, "key" | "altKey" | "ctrlKey" | "metaKey" | "shiftKey">) => { + if (event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) return + + switch (event.key) { + case "PageDown": + return "page-down" + case "PageUp": + return "page-up" + case "Home": + return "home" + case "End": + return "end" + case "ArrowUp": + return "up" + case "ArrowDown": + return "down" + } +} + export function ScrollView(props: ScrollViewProps) { + const i18n = useI18n() const merged = mergeProps({ orientation: "vertical" }, props) const [local, events, rest] = splitProps( merged, @@ -131,31 +152,34 @@ export function ScrollView(props: ScrollViewProps) { return } + const next = scrollKey(e) + if (!next) return + const scrollAmount = viewportRef.clientHeight * 0.8 const lineAmount = 40 - switch (e.key) { - case "PageDown": + switch (next) { + case "page-down": e.preventDefault() viewportRef.scrollBy({ top: scrollAmount, behavior: "smooth" }) break - case "PageUp": + case "page-up": e.preventDefault() viewportRef.scrollBy({ top: -scrollAmount, behavior: "smooth" }) break - case "Home": + case "home": e.preventDefault() viewportRef.scrollTo({ top: 0, behavior: "smooth" }) break - case "End": + case "end": e.preventDefault() viewportRef.scrollTo({ top: viewportRef.scrollHeight, behavior: "smooth" }) break - case "ArrowUp": + case "up": e.preventDefault() viewportRef.scrollBy({ top: -lineAmount, behavior: "smooth" }) break - case "ArrowDown": + case "down": e.preventDefault() viewportRef.scrollBy({ top: lineAmount, behavior: "smooth" }) break @@ -188,7 +212,7 @@ export function ScrollView(props: ScrollViewProps) { onClick={events.onClick as any} tabIndex={0} role="region" - aria-label="scrollable content" + aria-label={i18n.t("ui.scrollView.ariaLabel")} onKeyDown={(e) => { onKeyDown(e) if (typeof events.onKeyDown === "function") events.onKeyDown(e as any) diff --git a/packages/ui/src/components/select.stories.tsx b/packages/ui/src/components/select.stories.tsx new file mode 100644 index 0000000000..1ee00ab851 --- /dev/null +++ b/packages/ui/src/components/select.stories.tsx @@ -0,0 +1,113 @@ +// @ts-nocheck +import * as mod from "./select" +import { create } from "../storybook/scaffold" + +const docs = `### Overview +Select menu for choosing a single option with optional grouping. + +Use \`children\` to customize option rendering. + +### API +- Required: \`options\`. +- Optional: \`current\`, \`placeholder\`, \`value\`, \`label\`, \`groupBy\`. +- Accepts Button props for the trigger (\`variant\`, \`size\`). + +### Variants and states +- Trigger supports "settings" style via \`triggerVariant\`. + +### Behavior +- Uses Kobalte Select with optional item highlight callbacks. + +### Accessibility +- TODO: confirm keyboard navigation and aria attributes from Kobalte. + +### Theming/tokens +- Uses \`data-component="select"\` with slot attributes. + +` + +const story = create({ + title: "UI/Select", + mod, + args: { + options: ["One", "Two", "Three"], + current: "One", + placeholder: "Choose...", + variant: "secondary", + size: "normal", + }, +}) + +export default { + title: "UI/Select", + id: "components-select", + component: story.meta.component, + tags: ["autodocs"], + parameters: { + docs: { + description: { + component: docs, + }, + }, + }, + argTypes: { + triggerVariant: { + control: "select", + options: ["settings", undefined], + }, + }, +} + +export const Basic = story.Basic + +export const Grouped = { + render: () => { + const options = [ + { id: "alpha", label: "Alpha", group: "Group A" }, + { id: "bravo", label: "Bravo", group: "Group A" }, + { id: "delta", label: "Delta", group: "Group B" }, + ] + return ( + <mod.Select + options={options} + current={options[0]} + value={(item) => item.id} + label={(item) => item.label} + groupBy={(item) => item.group} + placeholder="Choose..." + variant="secondary" + /> + ) + }, +} + +export const SettingsTrigger = { + args: { + triggerVariant: "settings", + }, +} + +export const CustomRender = { + render: () => ( + <mod.Select + options={["Primary", "Secondary", "Ghost"]} + current="Primary" + placeholder="Choose..." + variant="secondary" + > + {(item) => <span style={{ "text-transform": "uppercase" }}>{item}</span>} + </mod.Select> + ), +} + +export const CustomTriggerStyle = { + args: { + triggerStyle: { "min-width": "180px", "justify-content": "space-between" }, + }, +} + +export const Disabled = { + args: { + disabled: true, + }, +} diff --git a/packages/ui/src/components/session-retry.tsx b/packages/ui/src/components/session-retry.tsx new file mode 100644 index 0000000000..ac0eb035d9 --- /dev/null +++ b/packages/ui/src/components/session-retry.tsx @@ -0,0 +1,74 @@ +import { createEffect, createMemo, createSignal, on, onCleanup, Show } from "solid-js" +import type { SessionStatus } from "@opencode-ai/sdk/v2/client" +import { useI18n } from "../context/i18n" +import { Card } from "./card" +import { Tooltip } from "./tooltip" +import { Spinner } from "./spinner" + +export function SessionRetry(props: { status: SessionStatus; show?: boolean }) { + const i18n = useI18n() + const retry = createMemo(() => { + if (props.status.type !== "retry") return + return props.status + }) + const [seconds, setSeconds] = createSignal(0) + createEffect( + on(retry, (current) => { + if (!current) return + const update = () => { + const next = retry()?.next + if (!next) return + setSeconds(Math.round((next - Date.now()) / 1000)) + } + update() + const timer = setInterval(update, 1000) + onCleanup(() => clearInterval(timer)) + }), + ) + const message = createMemo(() => { + const current = retry() + if (!current) return "" + if (current.message.includes("exceeded your current quota") && current.message.includes("gemini")) { + return i18n.t("ui.sessionTurn.retry.geminiHot") + } + if (current.message.length > 80) return current.message.slice(0, 80) + "..." + return current.message + }) + const truncated = createMemo(() => { + const current = retry() + if (!current) return false + return current.message.length > 80 + }) + const info = createMemo(() => { + const current = retry() + if (!current) return "" + const count = Math.max(0, seconds()) + const delay = count > 0 ? i18n.t("ui.sessionTurn.retry.inSeconds", { seconds: count }) : "" + const retrying = i18n.t("ui.sessionTurn.retry.retrying") + const line = [retrying, delay].filter(Boolean).join(" ") + if (!line) return i18n.t("ui.sessionTurn.retry.attempt", { attempt: current.attempt }) + return i18n.t("ui.sessionTurn.retry.attemptLine", { line, attempt: current.attempt }) + }) + + return ( + <Show when={retry() && (props.show ?? true)}> + <div data-slot="session-turn-retry"> + <Card variant="error" class="error-card"> + <div class="flex items-start gap-2"> + <Spinner class="size-4 mt-0.5" /> + <div class="min-w-0"> + <Show when={truncated()} fallback={<div data-slot="session-turn-retry-message">{message()}</div>}> + <Tooltip value={retry()?.message ?? ""} placement="top"> + <div data-slot="session-turn-retry-message" class="cursor-help truncate"> + {message()} + </div> + </Tooltip> + </Show> + <Show when={info()}>{(line) => <div data-slot="session-turn-retry-info">{line()}</div>}</Show> + </div> + </div> + </Card> + </div> + </Show> + ) +} diff --git a/packages/ui/src/components/session-review-search.test.ts b/packages/ui/src/components/session-review-search.test.ts new file mode 100644 index 0000000000..060df64071 --- /dev/null +++ b/packages/ui/src/components/session-review-search.test.ts @@ -0,0 +1,39 @@ +import { describe, expect, test } from "bun:test" +import { buildSessionSearchHits, stepSessionSearchIndex } from "./session-review-search" + +describe("session review search", () => { + test("builds hits with line, col, and side", () => { + const hits = buildSessionSearchHits({ + query: "alpha", + files: [ + { + file: "a.txt", + before: "alpha\nbeta alpha", + after: "ALPHA", + }, + ], + }) + + expect(hits).toEqual([ + { file: "a.txt", side: "deletions", line: 1, col: 1, len: 5 }, + { file: "a.txt", side: "deletions", line: 2, col: 6, len: 5 }, + { file: "a.txt", side: "additions", line: 1, col: 1, len: 5 }, + ]) + }) + + test("uses non-overlapping matches", () => { + const hits = buildSessionSearchHits({ + query: "aa", + files: [{ file: "a.txt", after: "aaaa" }], + }) + + expect(hits.map((hit) => hit.col)).toEqual([1, 3]) + }) + + test("wraps next and previous navigation", () => { + expect(stepSessionSearchIndex(5, 0, -1)).toBe(4) + expect(stepSessionSearchIndex(5, 4, 1)).toBe(0) + expect(stepSessionSearchIndex(5, 2, 1)).toBe(3) + expect(stepSessionSearchIndex(0, 0, 1)).toBe(0) + }) +}) diff --git a/packages/ui/src/components/session-review-search.ts b/packages/ui/src/components/session-review-search.ts new file mode 100644 index 0000000000..2cff0adc5a --- /dev/null +++ b/packages/ui/src/components/session-review-search.ts @@ -0,0 +1,59 @@ +export type SessionSearchHit = { + file: string + side: "additions" | "deletions" + line: number + col: number + len: number +} + +type SessionSearchFile = { + file: string + before?: string + after?: string +} + +function hitsForSide(args: { file: string; side: SessionSearchHit["side"]; text: string; needle: string }) { + return args.text.split("\n").flatMap((line, i) => { + if (!line) return [] + + const hay = line.toLowerCase() + let at = hay.indexOf(args.needle) + if (at < 0) return [] + + const out: SessionSearchHit[] = [] + while (at >= 0) { + out.push({ + file: args.file, + side: args.side, + line: i + 1, + col: at + 1, + len: args.needle.length, + }) + at = hay.indexOf(args.needle, at + args.needle.length) + } + + return out + }) +} + +export function buildSessionSearchHits(args: { query: string; files: SessionSearchFile[] }) { + const value = args.query.trim().toLowerCase() + if (!value) return [] + + return args.files.flatMap((file) => { + const out: SessionSearchHit[] = [] + if (typeof file.before === "string") { + out.push(...hitsForSide({ file: file.file, side: "deletions", text: file.before, needle: value })) + } + if (typeof file.after === "string") { + out.push(...hitsForSide({ file: file.file, side: "additions", text: file.after, needle: value })) + } + return out + }) +} + +export function stepSessionSearchIndex(total: number, current: number, dir: 1 | -1) { + if (total <= 0) return 0 + if (current < 0 || current >= total) return dir > 0 ? 0 : total - 1 + return (current + dir + total) % total +} diff --git a/packages/ui/src/components/session-review.css b/packages/ui/src/components/session-review.css index b9a2180cb8..014a70e740 100644 --- a/packages/ui/src/components/session-review.css +++ b/packages/ui/src/components/session-review.css @@ -3,22 +3,24 @@ flex-direction: column; gap: 0px; height: 100%; - overflow-y: auto; - scrollbar-width: none; - contain: strict; - &::-webkit-scrollbar { - display: none; + + [data-slot="session-review-scroll"] { + flex: 1 1 auto; + min-height: 0; + } + + .scroll-view__viewport { + display: flex; + flex-direction: column; } [data-slot="session-review-container"] { flex: 1 1 auto; - padding-right: 4px; + padding-right: 0; } [data-slot="session-review-header"] { - position: sticky; - top: 0; - z-index: 20; + z-index: 120; background-color: var(--background-stronger); height: 40px; padding-bottom: 8px; @@ -58,7 +60,7 @@ } [data-component="sticky-accordion-header"] { - --sticky-accordion-top: 40px; + --sticky-accordion-top: 0px; } [data-slot="session-review-accordion-item"][data-selected] @@ -195,50 +197,6 @@ color: var(--icon-diff-modified-base); } - [data-slot="session-review-file-container"] { - padding: 0; - } - - [data-slot="session-review-image-container"] { - padding: 12px; - display: flex; - justify-content: center; - background: var(--background-stronger); - } - - [data-slot="session-review-image"] { - max-width: 100%; - max-height: 60vh; - object-fit: contain; - border-radius: 8px; - border: 1px solid var(--border-weak-base); - background: var(--background-base); - } - - [data-slot="session-review-image-placeholder"] { - font-family: var(--font-family-sans); - font-size: var(--font-size-small); - color: var(--text-weak); - } - - [data-slot="session-review-audio-container"] { - padding: 12px; - display: flex; - justify-content: center; - background: var(--background-stronger); - } - - [data-slot="session-review-audio"] { - width: 100%; - max-width: 560px; - } - - [data-slot="session-review-audio-placeholder"] { - font-family: var(--font-family-sans); - font-size: var(--font-size-small); - color: var(--text-weak); - } - [data-slot="session-review-diff-wrapper"] { position: relative; overflow: hidden; diff --git a/packages/ui/src/components/session-review.stories.tsx b/packages/ui/src/components/session-review.stories.tsx new file mode 100644 index 0000000000..7ab1eb2038 --- /dev/null +++ b/packages/ui/src/components/session-review.stories.tsx @@ -0,0 +1,7 @@ +// @ts-nocheck +import * as mod from "./session-review" +import { create } from "../storybook/scaffold" + +const story = create({ title: "UI/SessionReview", mod }) +export default { title: "UI/SessionReview", id: "components-session-review", component: story.meta.component } +export const Basic = story.Basic diff --git a/packages/ui/src/components/session-review.tsx b/packages/ui/src/components/session-review.tsx index 7f737032e7..62c70e8647 100644 --- a/packages/ui/src/components/session-review.tsx +++ b/packages/ui/src/components/session-review.tsx @@ -1,23 +1,31 @@ import { Accordion } from "./accordion" import { Button } from "./button" +import { DropdownMenu } from "./dropdown-menu" import { RadioGroup } from "./radio-group" import { DiffChanges } from "./diff-changes" import { FileIcon } from "./file-icon" import { Icon } from "./icon" -import { LineComment, LineCommentEditor } from "./line-comment" +import { IconButton } from "./icon-button" import { StickyAccordionHeader } from "./sticky-accordion-header" import { Tooltip } from "./tooltip" import { ScrollView } from "./scroll-view" -import { useDiffComponent } from "../context/diff" +import { FileSearchBar } from "./file-search" +import type { FileSearchHandle } from "./file" +import { buildSessionSearchHits, stepSessionSearchIndex, type SessionSearchHit } from "./session-review-search" +import { useFileComponent } from "../context/file" import { useI18n } from "../context/i18n" import { getDirectory, getFilename } from "@opencode-ai/util/path" import { checksum } from "@opencode-ai/util/encode" -import { createEffect, createMemo, createSignal, For, Match, Show, Switch, type JSX } from "solid-js" +import { createEffect, createMemo, createSignal, For, Match, Show, Switch, untrack, type JSX } from "solid-js" +import { onCleanup } from "solid-js" import { createStore } from "solid-js/store" import { type FileContent, type FileDiff } from "@opencode-ai/sdk/v2" import { PreloadMultiFileDiffResult } from "@pierre/diffs/ssr" import { type SelectedLineRange } from "@pierre/diffs" import { Dynamic } from "solid-js/web" +import { mediaKindFromPath } from "../pierre/media" +import { cloneSelectedLineRange, previewSelectedLines } from "../pierre/selection-bridge" +import { createLineCommentController } from "./line-comment-annotations" const MAX_DIFF_CHANGED_LINES = 500 @@ -37,6 +45,22 @@ export type SessionReviewLineComment = { preview?: string } +export type SessionReviewCommentUpdate = SessionReviewLineComment & { + id: string +} + +export type SessionReviewCommentDelete = { + id: string + file: string +} + +export type SessionReviewCommentActions = { + moreLabel: string + editLabel: string + deleteLabel: string + saveLabel: string +} + export type SessionReviewFocus = { file: string; id: string } export interface SessionReviewProps { @@ -47,6 +71,9 @@ export interface SessionReviewProps { onDiffStyleChange?: (diffStyle: SessionReviewDiffStyle) => void onDiffRendered?: () => void onLineComment?: (comment: SessionReviewLineComment) => void + onLineCommentUpdate?: (comment: SessionReviewCommentUpdate) => void + onLineCommentDelete?: (comment: SessionReviewCommentDelete) => void + lineCommentActions?: SessionReviewCommentActions comments?: SessionReviewComment[] focusedComment?: SessionReviewFocus | null onFocusedCommentChange?: (focus: SessionReviewFocus | null) => void @@ -64,66 +91,35 @@ export interface SessionReviewProps { readFile?: (path: string) => Promise<FileContent | undefined> } -const imageExtensions = new Set(["png", "jpg", "jpeg", "gif", "webp", "avif", "bmp", "ico", "tif", "tiff", "heic"]) -const audioExtensions = new Set(["mp3", "wav", "ogg", "m4a", "aac", "flac", "opus"]) - -function normalizeMimeType(type: string | undefined): string | undefined { - if (!type) return - - const mime = type.split(";", 1)[0]?.trim().toLowerCase() - if (!mime) return - - if (mime === "audio/x-aac") return "audio/aac" - if (mime === "audio/x-m4a") return "audio/mp4" - - return mime -} - -function getExtension(file: string): string { - const idx = file.lastIndexOf(".") - if (idx === -1) return "" - return file.slice(idx + 1).toLowerCase() -} - -function isImageFile(file: string): boolean { - return imageExtensions.has(getExtension(file)) -} - -function isAudioFile(file: string): boolean { - return audioExtensions.has(getExtension(file)) -} - -function dataUrl(content: FileContent | undefined): string | undefined { - if (!content) return - if (content.encoding !== "base64") return - const mime = normalizeMimeType(content.mimeType) - if (!mime) return - if (!mime.startsWith("image/") && !mime.startsWith("audio/")) return - return `data:${mime};base64,${content.content}` -} - -function dataUrlFromValue(value: unknown): string | undefined { - if (typeof value === "string") { - if (value.startsWith("data:image/")) return value - if (value.startsWith("data:audio/x-aac;")) return value.replace("data:audio/x-aac;", "data:audio/aac;") - if (value.startsWith("data:audio/x-m4a;")) return value.replace("data:audio/x-m4a;", "data:audio/mp4;") - if (value.startsWith("data:audio/")) return value - return - } - if (!value || typeof value !== "object") return - - const content = (value as { content?: unknown }).content - const encoding = (value as { encoding?: unknown }).encoding - const mimeType = (value as { mimeType?: unknown }).mimeType - - if (typeof content !== "string") return - if (encoding !== "base64") return - if (typeof mimeType !== "string") return - const mime = normalizeMimeType(mimeType) - if (!mime) return - if (!mime.startsWith("image/") && !mime.startsWith("audio/")) return - - return `data:${mime};base64,${content}` +function ReviewCommentMenu(props: { + labels: SessionReviewCommentActions + onEdit: VoidFunction + onDelete: VoidFunction +}) { + return ( + <div onMouseDown={(event) => event.stopPropagation()} onClick={(event) => event.stopPropagation()}> + <DropdownMenu gutter={4} placement="bottom-end"> + <DropdownMenu.Trigger + as={IconButton} + icon="dot-grid" + variant="ghost" + size="small" + class="size-6 rounded-md" + aria-label={props.labels.moreLabel} + /> + <DropdownMenu.Portal> + <DropdownMenu.Content> + <DropdownMenu.Item onSelect={props.onEdit}> + <DropdownMenu.ItemLabel>{props.labels.editLabel}</DropdownMenu.ItemLabel> + </DropdownMenu.Item> + <DropdownMenu.Item onSelect={props.onDelete}> + <DropdownMenu.ItemLabel>{props.labels.deleteLabel}</DropdownMenu.ItemLabel> + </DropdownMenu.Item> + </DropdownMenu.Content> + </DropdownMenu.Portal> + </DropdownMenu> + </div> + ) } function diffId(file: string): string | undefined { @@ -137,62 +133,37 @@ type SessionReviewSelection = { range: SelectedLineRange } -function findSide(element: HTMLElement): "additions" | "deletions" | undefined { - const typed = element.closest("[data-line-type]") - if (typed instanceof HTMLElement) { - const type = typed.dataset.lineType - if (type === "change-deletion") return "deletions" - if (type === "change-addition" || type === "change-additions") return "additions" - } - - const code = element.closest("[data-code]") - if (!(code instanceof HTMLElement)) return - return code.hasAttribute("data-deletions") ? "deletions" : "additions" -} - -function findMarker(root: ShadowRoot, range: SelectedLineRange) { - const marker = (line: number, side?: "additions" | "deletions") => { - const nodes = Array.from(root.querySelectorAll(`[data-line="${line}"], [data-alt-line="${line}"]`)).filter( - (node): node is HTMLElement => node instanceof HTMLElement, - ) - if (nodes.length === 0) return - if (!side) return nodes[0] - const match = nodes.find((node) => findSide(node) === side) - return match ?? nodes[0] - } - - const a = marker(range.start, range.side) - const b = marker(range.end, range.endSide ?? range.side) - if (!a) return b - if (!b) return a - return a.getBoundingClientRect().top > b.getBoundingClientRect().top ? a : b -} - -function markerTop(wrapper: HTMLElement, marker: HTMLElement) { - const wrapperRect = wrapper.getBoundingClientRect() - const rect = marker.getBoundingClientRect() - return rect.top - wrapperRect.top + Math.max(0, (rect.height - 20) / 2) -} - export const SessionReview = (props: SessionReviewProps) => { let scroll: HTMLDivElement | undefined + let searchInput: HTMLInputElement | undefined let focusToken = 0 + let revealToken = 0 + let highlightedFile: string | undefined const i18n = useI18n() - const diffComponent = useDiffComponent() + const fileComponent = useFileComponent() const anchors = new Map<string, HTMLElement>() - const [store, setStore] = createStore({ - open: props.diffs.length > 10 ? [] : props.diffs.map((d) => d.file), + const searchHandles = new Map<string, FileSearchHandle>() + const readyFiles = new Set<string>() + const [store, setStore] = createStore<{ open: string[]; force: Record<string, boolean> }>({ + open: [], + force: {}, }) const [selection, setSelection] = createSignal<SessionReviewSelection | null>(null) const [commenting, setCommenting] = createSignal<SessionReviewSelection | null>(null) const [opened, setOpened] = createSignal<SessionReviewFocus | null>(null) + const [searchOpen, setSearchOpen] = createSignal(false) + const [searchQuery, setSearchQuery] = createSignal("") + const [searchActive, setSearchActive] = createSignal(0) + const [searchPos, setSearchPos] = createSignal({ top: 8, right: 8 }) const open = () => props.open ?? store.open const files = createMemo(() => props.diffs.map((d) => d.file)) const diffs = createMemo(() => new Map(props.diffs.map((d) => [d.file, d] as const))) const diffStyle = () => props.diffStyle ?? (props.split ? "split" : "unified") const hasDiffs = () => files().length > 0 + const searchValue = createMemo(() => searchQuery().trim()) + const searchExpanded = createMemo(() => searchValue().length > 0) const handleChange = (open: string[]) => { props.onOpenChange?.(open) @@ -205,13 +176,266 @@ export const SessionReview = (props: SessionReviewProps) => { handleChange(next) } + const clearViewerSearch = () => { + for (const handle of searchHandles.values()) handle.clear() + highlightedFile = undefined + } + + const openFileLabel = () => i18n.t("ui.sessionReview.openFile") + const selectionLabel = (range: SelectedLineRange) => { const start = Math.min(range.start, range.end) const end = Math.max(range.start, range.end) - if (start === end) return `line ${start}` - return `lines ${start}-${end}` + if (start === end) return i18n.t("ui.sessionReview.selection.line", { line: start }) + return i18n.t("ui.sessionReview.selection.lines", { start, end }) } + const focusSearch = () => { + if (!hasDiffs()) return + setSearchOpen(true) + requestAnimationFrame(() => { + searchInput?.focus() + searchInput?.select() + }) + } + + const closeSearch = () => { + revealToken++ + setSearchOpen(false) + setSearchQuery("") + setSearchActive(0) + clearViewerSearch() + } + + const positionSearchBar = () => { + if (typeof window === "undefined") return + if (!scroll) return + + const rect = scroll.getBoundingClientRect() + const title = parseFloat(getComputedStyle(scroll).getPropertyValue("--session-title-height")) + const header = Number.isNaN(title) ? 0 : title + setSearchPos({ + top: Math.round(rect.top) + header - 4, + right: Math.round(window.innerWidth - rect.right) + 8, + }) + } + + const searchHits = createMemo(() => + buildSessionSearchHits({ + query: searchQuery(), + files: props.diffs.flatMap((diff) => { + if (mediaKindFromPath(diff.file)) return [] + + return [ + { + file: diff.file, + before: typeof diff.before === "string" ? diff.before : undefined, + after: typeof diff.after === "string" ? diff.after : undefined, + }, + ] + }), + }), + ) + + const waitForViewer = (file: string, token: number) => + new Promise<FileSearchHandle | undefined>((resolve) => { + let attempt = 0 + + const tick = () => { + if (token !== revealToken) { + resolve(undefined) + return + } + + const handle = searchHandles.get(file) + if (handle && readyFiles.has(file)) { + resolve(handle) + return + } + + if (attempt >= 180) { + resolve(undefined) + return + } + + attempt++ + requestAnimationFrame(tick) + } + + tick() + }) + + const waitForFrames = (count: number, token: number) => + new Promise<boolean>((resolve) => { + const tick = (left: number) => { + if (token !== revealToken) { + resolve(false) + return + } + + if (left <= 0) { + resolve(true) + return + } + + requestAnimationFrame(() => tick(left - 1)) + } + + tick(count) + }) + + const revealSearchHit = async (token: number, hit: SessionSearchHit, query: string) => { + const diff = diffs().get(hit.file) + if (!diff) return + + if (!open().includes(hit.file)) { + handleChange([...open(), hit.file]) + } + + if (!mediaKindFromPath(hit.file) && diff.additions + diff.deletions > MAX_DIFF_CHANGED_LINES) { + setStore("force", hit.file, true) + } + + const handle = await waitForViewer(hit.file, token) + if (!handle || token !== revealToken) return + if (searchValue() !== query) return + if (!(await waitForFrames(2, token))) return + + if (highlightedFile && highlightedFile !== hit.file) { + searchHandles.get(highlightedFile)?.clear() + highlightedFile = undefined + } + + anchors.get(hit.file)?.scrollIntoView({ block: "nearest" }) + + let done = false + for (let i = 0; i < 4; i++) { + if (token !== revealToken) return + if (searchValue() !== query) return + + handle.setQuery(query) + if (handle.reveal(hit)) { + done = true + break + } + + const expanded = handle.expand(hit) + handle.refresh() + if (!(await waitForFrames(expanded ? 2 : 1, token))) return + } + + if (!done) return + + if (!(await waitForFrames(1, token))) return + handle.reveal(hit) + + highlightedFile = hit.file + } + + const navigateSearch = (dir: 1 | -1) => { + const total = searchHits().length + if (total <= 0) return + setSearchActive((value) => stepSessionSearchIndex(total, value, dir)) + } + + const inReview = (node: unknown, path?: unknown[]) => { + if (node === searchInput) return true + if (path?.some((item) => item === scroll || item === searchInput)) return true + if (path?.some((item) => item instanceof HTMLElement && item.dataset.component === "session-review")) { + return true + } + if (!(node instanceof Node)) return false + if (searchInput?.contains(node)) return true + if (node instanceof HTMLElement && node.closest("[data-component='session-review']")) return true + if (!scroll) return false + return scroll.contains(node) + } + + createEffect(() => { + if (typeof window === "undefined") return + + const onKeyDown = (event: KeyboardEvent) => { + const mod = event.metaKey || event.ctrlKey + if (!mod) return + + const key = event.key.toLowerCase() + if (key !== "f" && key !== "g") return + + if (key === "f") { + if (!hasDiffs()) return + event.preventDefault() + event.stopPropagation() + focusSearch() + return + } + + const path = typeof event.composedPath === "function" ? event.composedPath() : undefined + if (!inReview(event.target, path) && !inReview(document.activeElement, path)) return + if (!searchOpen()) return + event.preventDefault() + event.stopPropagation() + navigateSearch(event.shiftKey ? -1 : 1) + } + + window.addEventListener("keydown", onKeyDown, { capture: true }) + onCleanup(() => window.removeEventListener("keydown", onKeyDown, { capture: true })) + }) + + createEffect(() => { + diffStyle() + searchExpanded() + readyFiles.clear() + }) + + createEffect(() => { + if (!searchOpen()) return + if (!scroll) return + + const root = scroll + + requestAnimationFrame(positionSearchBar) + window.addEventListener("resize", positionSearchBar, { passive: true }) + const observer = typeof ResizeObserver === "undefined" ? undefined : new ResizeObserver(positionSearchBar) + observer?.observe(root) + + onCleanup(() => { + window.removeEventListener("resize", positionSearchBar) + observer?.disconnect() + }) + }) + + createEffect(() => { + const total = searchHits().length + if (total === 0) { + if (searchActive() !== 0) setSearchActive(0) + return + } + + if (searchActive() >= total) setSearchActive(total - 1) + }) + + createEffect(() => { + diffStyle() + const query = searchValue() + const hits = searchHits() + const token = ++revealToken + if (!query || hits.length === 0) { + clearViewerSearch() + return + } + + const hit = hits[Math.min(searchActive(), hits.length - 1)] + if (!hit) return + void revealSearchHit(token, hit, query) + }) + + onCleanup(() => { + revealToken++ + clearViewerSearch() + readyFiles.clear() + searchHandles.clear() + }) + const selectionSide = (range: SelectedLineRange) => range.endSide ?? range.side ?? "additions" const selectionPreview = (diff: FileDiff, range: SelectedLineRange) => { @@ -219,79 +443,120 @@ export const SessionReview = (props: SessionReviewProps) => { const contents = side === "deletions" ? diff.before : diff.after if (typeof contents !== "string" || contents.length === 0) return undefined - const start = Math.max(1, Math.min(range.start, range.end)) - const end = Math.max(range.start, range.end) - const lines = contents.split("\n").slice(start - 1, end) - if (lines.length === 0) return undefined - return lines.slice(0, 2).join("\n") + return previewSelectedLines(contents, range) } createEffect(() => { const focus = props.focusedComment if (!focus) return - focusToken++ - const token = focusToken + untrack(() => { + focusToken++ + const token = focusToken - setOpened(focus) + setOpened(focus) - const comment = (props.comments ?? []).find((c) => c.file === focus.file && c.id === focus.id) - if (comment) setSelection({ file: comment.file, range: comment.selection }) + const comment = (props.comments ?? []).find((c) => c.file === focus.file && c.id === focus.id) + if (comment) setSelection({ file: comment.file, range: cloneSelectedLineRange(comment.selection) }) - const current = open() - if (!current.includes(focus.file)) { - handleChange([...current, focus.file]) - } - - const scrollTo = (attempt: number) => { - if (token !== focusToken) return - - const root = scroll - if (!root) return - - const anchor = root.querySelector(`[data-comment-id="${focus.id}"]`) - const ready = - anchor instanceof HTMLElement && anchor.style.pointerEvents !== "none" && anchor.style.opacity !== "0" - - const target = ready ? anchor : anchors.get(focus.file) - if (!target) { - if (attempt >= 120) return - requestAnimationFrame(() => scrollTo(attempt + 1)) - return + const current = open() + if (!current.includes(focus.file)) { + handleChange([...current, focus.file]) } - const rootRect = root.getBoundingClientRect() - const targetRect = target.getBoundingClientRect() - const offset = targetRect.top - rootRect.top - const next = root.scrollTop + offset - rootRect.height / 2 + targetRect.height / 2 - root.scrollTop = Math.max(0, next) + const scrollTo = (attempt: number) => { + if (token !== focusToken) return - if (ready) return - if (attempt >= 120) return - requestAnimationFrame(() => scrollTo(attempt + 1)) - } + const root = scroll + if (!root) return - requestAnimationFrame(() => scrollTo(0)) + const wrapper = anchors.get(focus.file) + const anchor = wrapper?.querySelector(`[data-comment-id="${focus.id}"]`) + const ready = + anchor instanceof HTMLElement && anchor.style.pointerEvents !== "none" && anchor.style.opacity !== "0" - requestAnimationFrame(() => props.onFocusedCommentChange?.(null)) + const target = ready ? anchor : wrapper + if (!target) { + if (attempt >= 120) return + requestAnimationFrame(() => scrollTo(attempt + 1)) + return + } + + const rootRect = root.getBoundingClientRect() + const targetRect = target.getBoundingClientRect() + const offset = targetRect.top - rootRect.top + const next = root.scrollTop + offset - rootRect.height / 2 + targetRect.height / 2 + root.scrollTop = Math.max(0, next) + + if (ready) return + if (attempt >= 120) return + requestAnimationFrame(() => scrollTo(attempt + 1)) + } + + requestAnimationFrame(() => scrollTo(0)) + + requestAnimationFrame(() => props.onFocusedCommentChange?.(null)) + }) }) + const handleReviewKeyDown = (event: KeyboardEvent) => { + if (event.defaultPrevented) return + + const mod = event.metaKey || event.ctrlKey + const key = event.key.toLowerCase() + const target = event.target + if (mod && key === "f") { + event.preventDefault() + event.stopPropagation() + focusSearch() + return + } + + if (mod && key === "g") { + if (!searchOpen()) return + event.preventDefault() + event.stopPropagation() + navigateSearch(event.shiftKey ? -1 : 1) + } + } + + const handleSearchInputKeyDown = (event: KeyboardEvent) => { + const mod = event.metaKey || event.ctrlKey + const key = event.key.toLowerCase() + + if (mod && key === "g") { + event.preventDefault() + event.stopPropagation() + navigateSearch(event.shiftKey ? -1 : 1) + return + } + + if (mod && key === "f") { + event.preventDefault() + event.stopPropagation() + focusSearch() + return + } + + if (event.key === "Escape") { + event.preventDefault() + event.stopPropagation() + closeSearch() + return + } + + if (event.key !== "Enter") return + event.preventDefault() + event.stopPropagation() + navigateSearch(event.shiftKey ? -1 : 1) + } + return ( - <ScrollView - data-component="session-review" - viewportRef={(el) => { - scroll = el - props.scrollRef?.(el) - }} - onScroll={props.onScroll as any} - classList={{ - ...(props.classList ?? {}), - [props.classes?.root ?? ""]: !!props.classes?.root, - [props.class ?? ""]: !!props.class, - }} - > + <div data-component="session-review" class={props.class} classList={props.classList}> <div data-slot="session-review-header" class={props.classes?.header}> - <div data-slot="session-review-title">{props.title ?? i18n.t("ui.sessionReview.title")}</div> + <div data-slot="session-review-title"> + {props.title === undefined ? i18n.t("ui.sessionReview.title") : props.title} + </div> <div data-slot="session-review-actions"> <Show when={hasDiffs() && props.onDiffStyleChange}> <RadioGroup @@ -321,415 +586,319 @@ export const SessionReview = (props: SessionReviewProps) => { {props.actions} </div> </div> - <div data-slot="session-review-container" class={props.classes?.container}> - <Show when={hasDiffs()} fallback={props.empty}> - <Accordion multiple value={open()} onChange={handleChange}> - <For each={files()}> - {(file) => { - let wrapper: HTMLDivElement | undefined - const diff = createMemo(() => diffs().get(file)) - const item = () => diff()! - - const expanded = createMemo(() => open().includes(file)) - const [force, setForce] = createSignal(false) - - const comments = createMemo(() => (props.comments ?? []).filter((c) => c.file === file)) - const commentedLines = createMemo(() => comments().map((c) => c.selection)) - - const beforeText = () => (typeof item().before === "string" ? item().before : "") - const afterText = () => (typeof item().after === "string" ? item().after : "") - const changedLines = () => item().additions + item().deletions - - const tooLarge = createMemo(() => { - if (!expanded()) return false - if (force()) return false - if (isImageFile(file)) return false - return changedLines() > MAX_DIFF_CHANGED_LINES - }) - - const isAdded = () => item().status === "added" || (beforeText().length === 0 && afterText().length > 0) - const isDeleted = () => - item().status === "deleted" || (afterText().length === 0 && beforeText().length > 0) - const isImage = () => isImageFile(file) - const isAudio = () => isAudioFile(file) - - const diffImageSrc = createMemo(() => dataUrlFromValue(item().after) ?? dataUrlFromValue(item().before)) - const [imageSrc, setImageSrc] = createSignal<string | undefined>(diffImageSrc()) - const [imageStatus, setImageStatus] = createSignal<"idle" | "loading" | "error">("idle") - - const diffAudioSrc = createMemo(() => dataUrlFromValue(item().after) ?? dataUrlFromValue(item().before)) - const [audioSrc, setAudioSrc] = createSignal<string | undefined>(diffAudioSrc()) - const [audioStatus, setAudioStatus] = createSignal<"idle" | "loading" | "error">("idle") - const [audioMime, setAudioMime] = createSignal<string | undefined>(undefined) - - const selectedLines = createMemo(() => { - const current = selection() - if (!current || current.file !== file) return null - return current.range - }) - - const draftRange = createMemo(() => { - const current = commenting() - if (!current || current.file !== file) return null - return current.range - }) - - const [draft, setDraft] = createSignal("") - const [positions, setPositions] = createSignal<Record<string, number>>({}) - const [draftTop, setDraftTop] = createSignal<number | undefined>(undefined) - - const getRoot = () => { - const el = wrapper - if (!el) return - - const host = el.querySelector("diffs-container") - if (!(host instanceof HTMLElement)) return - return host.shadowRoot ?? undefined - } - - const updateAnchors = () => { - const el = wrapper - if (!el) return - - const root = getRoot() - if (!root) return - - const next: Record<string, number> = {} - for (const item of comments()) { - const marker = findMarker(root, item.selection) - if (!marker) continue - next[item.id] = markerTop(el, marker) - } - setPositions(next) - - const range = draftRange() - if (!range) { - setDraftTop(undefined) - return - } - - const marker = findMarker(root, range) - if (!marker) { - setDraftTop(undefined) - return - } - - setDraftTop(markerTop(el, marker)) - } - - const scheduleAnchors = () => { - requestAnimationFrame(updateAnchors) - } - - createEffect(() => { - if (!isImage()) return - const src = diffImageSrc() - setImageSrc(src) - setImageStatus("idle") - }) - - createEffect(() => { - if (!isAudio()) return - const src = diffAudioSrc() - setAudioSrc(src) - setAudioStatus("idle") - setAudioMime(undefined) - }) - - createEffect(() => { - comments() - scheduleAnchors() - }) - - createEffect(() => { - const range = draftRange() - if (!range) return - setDraft("") - scheduleAnchors() - }) - - createEffect(() => { - if (!open().includes(file)) return - if (!isImage()) return - if (imageSrc()) return - if (imageStatus() !== "idle") return - if (isDeleted()) return - - const reader = props.readFile - if (!reader) return - - setImageStatus("loading") - reader(file) - .then((result) => { - const src = dataUrl(result) - if (!src) { - setImageStatus("error") - return - } - setImageSrc(src) - setImageStatus("idle") - }) - .catch(() => { - setImageStatus("error") - }) - }) - - createEffect(() => { - if (!open().includes(file)) return - if (!isAudio()) return - if (audioSrc()) return - if (audioStatus() !== "idle") return - - const reader = props.readFile - if (!reader) return - - setAudioStatus("loading") - reader(file) - .then((result) => { - const src = dataUrl(result) - if (!src) { - setAudioStatus("error") - return - } - setAudioMime(normalizeMimeType(result?.mimeType)) - setAudioSrc(src) - setAudioStatus("idle") - }) - .catch(() => { - setAudioStatus("error") - }) - }) - - const handleLineSelected = (range: SelectedLineRange | null) => { - if (!props.onLineComment) return - - if (!range) { - setSelection(null) - return - } - - setSelection({ file, range }) - } - - const handleLineSelectionEnd = (range: SelectedLineRange | null) => { - if (!props.onLineComment) return - - if (!range) { - setCommenting(null) - return - } - - setSelection({ file, range }) - setCommenting({ file, range }) - } - - const openComment = (comment: SessionReviewComment) => { - setOpened({ file: comment.file, id: comment.id }) - setSelection({ file: comment.file, range: comment.selection }) - } - - const isCommentOpen = (comment: SessionReviewComment) => { - const current = opened() - if (!current) return false - return current.file === comment.file && current.id === comment.id - } - - return ( - <Accordion.Item - value={file} - id={diffId(file)} - data-file={file} - data-slot="session-review-accordion-item" - data-selected={props.focusedFile === file ? "" : undefined} - > - <StickyAccordionHeader> - <Accordion.Trigger> - <div data-slot="session-review-trigger-content"> - <div data-slot="session-review-file-info"> - <FileIcon node={{ path: file, type: "file" }} /> - <div data-slot="session-review-file-name-container"> - <Show when={file.includes("/")}> - <span data-slot="session-review-directory">{`\u202A${getDirectory(file)}\u202C`}</span> - </Show> - <span data-slot="session-review-filename">{getFilename(file)}</span> - <Show when={props.onViewFile}> - <Tooltip value="Open file" placement="top" gutter={4}> - <button - data-slot="session-review-view-button" - type="button" - aria-label="Open file" - onClick={(e) => { - e.stopPropagation() - props.onViewFile?.(file) - }} - > - <Icon name="open-file" size="small" /> - </button> - </Tooltip> - </Show> - </div> - </div> - <div data-slot="session-review-trigger-actions"> - <Switch> - <Match when={isAdded()}> - <div data-slot="session-review-change-group" data-type="added"> - <span data-slot="session-review-change" data-type="added"> - {i18n.t("ui.sessionReview.change.added")} - </span> - <DiffChanges changes={item()} /> - </div> - </Match> - <Match when={isDeleted()}> - <span data-slot="session-review-change" data-type="removed"> - {i18n.t("ui.sessionReview.change.removed")} - </span> - </Match> - <Match when={isImage()}> - <span data-slot="session-review-change" data-type="modified"> - {i18n.t("ui.sessionReview.change.modified")} - </span> - </Match> - <Match when={true}> - <DiffChanges changes={item()} /> - </Match> - </Switch> - <span data-slot="session-review-diff-chevron"> - <Icon name="chevron-down" size="small" /> - </span> - </div> - </div> - </Accordion.Trigger> - </StickyAccordionHeader> - <Accordion.Content data-slot="session-review-accordion-content"> - <div - data-slot="session-review-diff-wrapper" - ref={(el) => { - wrapper = el - anchors.set(file, el) - scheduleAnchors() - }} - > - <Show when={expanded()}> - <Switch> - <Match when={isImage() && imageSrc()}> - <div data-slot="session-review-image-container"> - <img data-slot="session-review-image" src={imageSrc()} alt={file} /> - </div> - </Match> - <Match when={isImage() && isDeleted()}> - <div data-slot="session-review-image-container" data-removed> - <span data-slot="session-review-image-placeholder"> - {i18n.t("ui.sessionReview.change.removed")} - </span> - </div> - </Match> - <Match when={isImage() && !imageSrc()}> - <div data-slot="session-review-image-container"> - <span data-slot="session-review-image-placeholder"> - {imageStatus() === "loading" - ? i18n.t("ui.sessionReview.image.loading") - : i18n.t("ui.sessionReview.image.placeholder")} - </span> - </div> - </Match> - <Match when={!isImage() && tooLarge()}> - <div data-slot="session-review-large-diff"> - <div data-slot="session-review-large-diff-title"> - {i18n.t("ui.sessionReview.largeDiff.title")} - </div> - <div data-slot="session-review-large-diff-meta"> - {i18n.t("ui.sessionReview.largeDiff.meta", { - limit: MAX_DIFF_CHANGED_LINES.toLocaleString(), - current: changedLines().toLocaleString(), - })} - </div> - <div data-slot="session-review-large-diff-actions"> - <Button size="normal" variant="secondary" onClick={() => setForce(true)}> - {i18n.t("ui.sessionReview.largeDiff.renderAnyway")} - </Button> - </div> - </div> - </Match> - <Match when={!isImage()}> - <Dynamic - component={diffComponent} - preloadedDiff={item().preloaded} - diffStyle={diffStyle()} - onRendered={() => { - props.onDiffRendered?.() - scheduleAnchors() - }} - enableLineSelection={props.onLineComment != null} - onLineSelected={handleLineSelected} - onLineSelectionEnd={handleLineSelectionEnd} - selectedLines={selectedLines()} - commentedLines={commentedLines()} - before={{ - name: file, - contents: typeof item().before === "string" ? item().before : "", - }} - after={{ - name: file, - contents: typeof item().after === "string" ? item().after : "", - }} - /> - </Match> - </Switch> - - <For each={comments()}> - {(comment) => ( - <LineComment - id={comment.id} - top={positions()[comment.id]} - onMouseEnter={() => setSelection({ file: comment.file, range: comment.selection })} - onClick={() => { - if (isCommentOpen(comment)) { - setOpened(null) - return - } - - openComment(comment) - }} - open={isCommentOpen(comment)} - comment={comment.comment} - selection={selectionLabel(comment.selection)} - /> - )} - </For> - - <Show when={draftRange()}> - {(range) => ( - <Show when={draftTop() !== undefined}> - <LineCommentEditor - top={draftTop()} - value={draft()} - selection={selectionLabel(range())} - onInput={setDraft} - onCancel={() => setCommenting(null)} - onSubmit={(comment) => { - props.onLineComment?.({ - file, - selection: range(), - comment, - preview: selectionPreview(item(), range()), - }) - setCommenting(null) - }} - /> - </Show> - )} - </Show> - </Show> - </div> - </Accordion.Content> - </Accordion.Item> - ) - }} - </For> - </Accordion> + <ScrollView + data-slot="session-review-scroll" + viewportRef={(el) => { + scroll = el + props.scrollRef?.(el) + }} + onScroll={props.onScroll as any} + onKeyDown={handleReviewKeyDown} + classList={{ + [props.classes?.root ?? ""]: !!props.classes?.root, + }} + > + <Show when={searchOpen()}> + <FileSearchBar + pos={searchPos} + query={searchQuery} + index={() => (searchHits().length ? Math.min(searchActive(), searchHits().length - 1) : 0)} + count={() => searchHits().length} + setInput={(el) => { + searchInput = el + }} + onInput={(value) => { + setSearchQuery(value) + setSearchActive(0) + }} + onKeyDown={(event) => handleSearchInputKeyDown(event)} + onClose={closeSearch} + onPrev={() => navigateSearch(-1)} + onNext={() => navigateSearch(1)} + /> </Show> - </div> - </ScrollView> + + <div data-slot="session-review-container" class={props.classes?.container}> + <Show when={hasDiffs()} fallback={props.empty}> + <div class="pb-6"> + <Accordion multiple value={open()} onChange={handleChange}> + <For each={files()}> + {(file) => { + let wrapper: HTMLDivElement | undefined + + const diff = createMemo(() => diffs().get(file)) + const item = () => diff()! + + const expanded = createMemo(() => open().includes(file)) + const force = () => !!store.force[file] + + const comments = createMemo(() => (props.comments ?? []).filter((c) => c.file === file)) + const commentedLines = createMemo(() => comments().map((c) => c.selection)) + + const beforeText = () => (typeof item().before === "string" ? item().before : "") + const afterText = () => (typeof item().after === "string" ? item().after : "") + const changedLines = () => item().additions + item().deletions + const mediaKind = createMemo(() => mediaKindFromPath(file)) + + const tooLarge = createMemo(() => { + if (!expanded()) return false + if (force()) return false + if (mediaKind()) return false + return changedLines() > MAX_DIFF_CHANGED_LINES + }) + + const isAdded = () => + item().status === "added" || (beforeText().length === 0 && afterText().length > 0) + const isDeleted = () => + item().status === "deleted" || (afterText().length === 0 && beforeText().length > 0) + + const selectedLines = createMemo(() => { + const current = selection() + if (!current || current.file !== file) return null + return current.range + }) + + const draftRange = createMemo(() => { + const current = commenting() + if (!current || current.file !== file) return null + return current.range + }) + + const commentsUi = createLineCommentController<SessionReviewComment>({ + comments, + label: i18n.t("ui.lineComment.submit"), + draftKey: () => file, + state: { + opened: () => { + const current = opened() + if (!current || current.file !== file) return null + return current.id + }, + setOpened: (id) => setOpened(id ? { file, id } : null), + selected: selectedLines, + setSelected: (range) => setSelection(range ? { file, range } : null), + commenting: draftRange, + setCommenting: (range) => setCommenting(range ? { file, range } : null), + }, + getSide: selectionSide, + clearSelectionOnSelectionEndNull: false, + onSubmit: ({ comment, selection }) => { + props.onLineComment?.({ + file, + selection, + comment, + preview: selectionPreview(item(), selection), + }) + }, + onUpdate: ({ id, comment, selection }) => { + props.onLineCommentUpdate?.({ + id, + file, + selection, + comment, + preview: selectionPreview(item(), selection), + }) + }, + onDelete: (comment) => { + props.onLineCommentDelete?.({ + id: comment.id, + file, + }) + }, + editSubmitLabel: props.lineCommentActions?.saveLabel, + renderCommentActions: props.lineCommentActions + ? (comment, controls) => ( + <ReviewCommentMenu + labels={props.lineCommentActions!} + onEdit={controls.edit} + onDelete={controls.remove} + /> + ) + : undefined, + }) + + onCleanup(() => { + anchors.delete(file) + readyFiles.delete(file) + searchHandles.delete(file) + if (highlightedFile === file) highlightedFile = undefined + }) + + const handleLineSelected = (range: SelectedLineRange | null) => { + if (!props.onLineComment) return + commentsUi.onLineSelected(range) + } + + const handleLineSelectionEnd = (range: SelectedLineRange | null) => { + if (!props.onLineComment) return + commentsUi.onLineSelectionEnd(range) + } + + return ( + <Accordion.Item + value={file} + id={diffId(file)} + data-file={file} + data-slot="session-review-accordion-item" + data-selected={props.focusedFile === file ? "" : undefined} + > + <StickyAccordionHeader> + <Accordion.Trigger> + <div data-slot="session-review-trigger-content"> + <div data-slot="session-review-file-info"> + <FileIcon node={{ path: file, type: "file" }} /> + <div data-slot="session-review-file-name-container"> + <Show when={file.includes("/")}> + <span data-slot="session-review-directory">{`\u202A${getDirectory(file)}\u202C`}</span> + </Show> + <span data-slot="session-review-filename">{getFilename(file)}</span> + <Show when={props.onViewFile}> + <Tooltip value={openFileLabel()} placement="top" gutter={4}> + <button + data-slot="session-review-view-button" + type="button" + aria-label={openFileLabel()} + onClick={(e) => { + e.stopPropagation() + props.onViewFile?.(file) + }} + > + <Icon name="open-file" size="small" /> + </button> + </Tooltip> + </Show> + </div> + </div> + <div data-slot="session-review-trigger-actions"> + <Switch> + <Match when={isAdded()}> + <div data-slot="session-review-change-group" data-type="added"> + <span data-slot="session-review-change" data-type="added"> + {i18n.t("ui.sessionReview.change.added")} + </span> + <DiffChanges changes={item()} /> + </div> + </Match> + <Match when={isDeleted()}> + <span data-slot="session-review-change" data-type="removed"> + {i18n.t("ui.sessionReview.change.removed")} + </span> + </Match> + <Match when={!!mediaKind()}> + <span data-slot="session-review-change" data-type="modified"> + {i18n.t("ui.sessionReview.change.modified")} + </span> + </Match> + <Match when={true}> + <DiffChanges changes={item()} /> + </Match> + </Switch> + <span data-slot="session-review-diff-chevron"> + <Icon name="chevron-down" size="small" /> + </span> + </div> + </div> + </Accordion.Trigger> + </StickyAccordionHeader> + <Accordion.Content data-slot="session-review-accordion-content"> + <div + data-slot="session-review-diff-wrapper" + ref={(el) => { + wrapper = el + anchors.set(file, el) + }} + > + <Show when={expanded()}> + <Switch> + <Match when={tooLarge()}> + <div data-slot="session-review-large-diff"> + <div data-slot="session-review-large-diff-title"> + {i18n.t("ui.sessionReview.largeDiff.title")} + </div> + <div data-slot="session-review-large-diff-meta"> + {i18n.t("ui.sessionReview.largeDiff.meta", { + limit: MAX_DIFF_CHANGED_LINES.toLocaleString(), + current: changedLines().toLocaleString(), + })} + </div> + <div data-slot="session-review-large-diff-actions"> + <Button + size="normal" + variant="secondary" + onClick={() => setStore("force", file, true)} + > + {i18n.t("ui.sessionReview.largeDiff.renderAnyway")} + </Button> + </div> + </div> + </Match> + <Match when={true}> + <Dynamic + component={fileComponent} + mode="diff" + preloadedDiff={item().preloaded} + diffStyle={diffStyle()} + expansionLineCount={searchExpanded() ? Number.MAX_SAFE_INTEGER : 20} + onRendered={() => { + readyFiles.add(file) + props.onDiffRendered?.() + }} + enableLineSelection={props.onLineComment != null} + enableHoverUtility={props.onLineComment != null} + onLineSelected={handleLineSelected} + onLineSelectionEnd={handleLineSelectionEnd} + onLineNumberSelectionEnd={commentsUi.onLineNumberSelectionEnd} + annotations={commentsUi.annotations()} + renderAnnotation={commentsUi.renderAnnotation} + renderHoverUtility={props.onLineComment ? commentsUi.renderHoverUtility : undefined} + selectedLines={selectedLines()} + commentedLines={commentedLines()} + search={{ + shortcuts: "disabled", + showBar: false, + disableVirtualization: searchExpanded(), + register: (handle: FileSearchHandle | null) => { + if (!handle) { + searchHandles.delete(file) + readyFiles.delete(file) + if (highlightedFile === file) highlightedFile = undefined + return + } + + searchHandles.set(file, handle) + }, + }} + before={{ + name: file, + contents: typeof item().before === "string" ? item().before : "", + }} + after={{ + name: file, + contents: typeof item().after === "string" ? item().after : "", + }} + media={{ + mode: "auto", + path: file, + before: item().before, + after: item().after, + readFile: props.readFile, + }} + /> + </Match> + </Switch> + </Show> + </div> + </Accordion.Content> + </Accordion.Item> + ) + }} + </For> + </Accordion> + </div> + </Show> + </div> + </ScrollView> + </div> ) } diff --git a/packages/ui/src/components/session-turn.css b/packages/ui/src/components/session-turn.css index 9639e6635a..eea9a13e4f 100644 --- a/packages/ui/src/components/session-turn.css +++ b/packages/ui/src/components/session-turn.css @@ -37,6 +37,12 @@ max-width: 100%; } + [data-slot="session-turn-compaction"] { + width: 100%; + min-width: 0; + align-self: stretch; + } + [data-slot="session-turn-thinking"] { display: flex; align-items: center; @@ -47,23 +53,20 @@ font-family: var(--font-family-sans); font-size: var(--font-size-base); font-weight: var(--font-weight-medium); - line-height: var(--line-height-large); + line-height: 20px; min-height: 20px; [data-component="spinner"] { width: 16px; height: 16px; } + } - [data-slot="session-turn-thinking-heading"] { - flex: 1 1 auto; - min-width: 0; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - color: var(--text-weaker); - font-weight: var(--font-weight-regular); - } + [data-component="text-reveal"].session-turn-thinking-heading { + flex: 1 1 auto; + min-width: 0; + color: var(--text-weaker); + font-weight: var(--font-weight-regular); } .error-card { @@ -130,6 +133,7 @@ [data-slot="session-turn-diffs-count"] { color: var(--text-base); font-family: var(--font-family-sans); + font-variant-numeric: tabular-nums; font-size: var(--font-size-base); font-weight: var(--font-weight-regular); line-height: var(--line-height-x-large); @@ -168,10 +172,8 @@ [data-slot="session-turn-diff-path"] { display: flex; + flex-grow: 1; min-width: 0; - align-items: baseline; - overflow: hidden; - white-space: nowrap; font-family: var(--font-family-sans); font-size: var(--font-size-small); @@ -179,24 +181,16 @@ } [data-slot="session-turn-diff-directory"] { - flex: 1 1 auto; - color: var(--text-weak); - min-width: 0; + color: var(--text-base); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; direction: rtl; - unicode-bidi: plaintext; text-align: left; } [data-slot="session-turn-diff-filename"] { flex-shrink: 0; - max-width: 100%; - min-width: 0; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; color: var(--text-strong); font-weight: var(--font-weight-medium); } diff --git a/packages/ui/src/components/session-turn.stories.tsx b/packages/ui/src/components/session-turn.stories.tsx new file mode 100644 index 0000000000..927402c8db --- /dev/null +++ b/packages/ui/src/components/session-turn.stories.tsx @@ -0,0 +1,7 @@ +// @ts-nocheck +import * as mod from "./session-turn" +import { create } from "../storybook/scaffold" + +const story = create({ title: "UI/SessionTurn", mod }) +export default { title: "UI/SessionTurn", id: "components-session-turn", component: story.meta.component } +export const Basic = story.Basic diff --git a/packages/ui/src/components/session-turn.tsx b/packages/ui/src/components/session-turn.tsx index 33e72fb1e7..3323a9fc66 100644 --- a/packages/ui/src/components/session-turn.tsx +++ b/packages/ui/src/components/session-turn.tsx @@ -1,12 +1,13 @@ import { AssistantMessage, type FileDiff, Message as MessageType, Part as PartType } from "@opencode-ai/sdk/v2/client" +import type { SessionStatus } from "@opencode-ai/sdk/v2" import { useData } from "../context" -import { useDiffComponent } from "../context/diff" +import { useFileComponent } from "../context/file" import { Binary } from "@opencode-ai/util/binary" import { getDirectory, getFilename } from "@opencode-ai/util/path" import { createEffect, createMemo, createSignal, For, on, ParentProps, Show } from "solid-js" import { Dynamic } from "solid-js/web" -import { AssistantParts, Message, PART_MAPPING } from "./message-part" +import { AssistantParts, Message, Part, PART_MAPPING } from "./message-part" import { Card } from "./card" import { Accordion } from "./accordion" import { StickyAccordionHeader } from "./sticky-accordion-header" @@ -14,6 +15,8 @@ import { Collapsible } from "./collapsible" import { DiffChanges } from "./diff-changes" import { Icon } from "./icon" import { TextShimmer } from "./text-shimmer" +import { SessionRetry } from "./session-retry" +import { TextReveal } from "./text-reveal" import { createAutoScroll } from "../hooks" import { useI18n } from "../context/i18n" @@ -91,7 +94,7 @@ function partState(part: PartType, showReasoningSummaries: boolean) { } if (part.type === "text") return part.text?.trim() ? ("visible" as const) : undefined if (part.type === "reasoning") { - if (showReasoningSummaries) return "visible" as const + if (showReasoningSummaries && part.text?.trim()) return "visible" as const return } if (PART_MAPPING[part.type]) return "visible" as const @@ -138,8 +141,12 @@ export function SessionTurn( props: ParentProps<{ sessionID: string messageID: string - lastUserMessageID?: string showReasoningSummaries?: boolean + shellToolDefaultOpen?: boolean + editToolDefaultOpen?: boolean + active?: boolean + queued?: boolean + status?: SessionStatus onUserInteracted?: () => void classes?: { root?: string @@ -150,7 +157,7 @@ export function SessionTurn( ) { const data = useData() const i18n = useI18n() - const diffComponent = useDiffComponent() + const fileComponent = useFileComponent() const emptyMessages: MessageType[] = [] const emptyParts: PartType[] = [] @@ -184,18 +191,41 @@ export function SessionTurn( return msg }) - const lastUserMessageID = createMemo(() => { - if (props.lastUserMessageID) return props.lastUserMessageID - + const pending = createMemo(() => { + if (typeof props.active === "boolean" && typeof props.queued === "boolean") return const messages = allMessages() ?? emptyMessages - for (let i = messages.length - 1; i >= 0; i--) { - const msg = messages[i] - if (msg?.role === "user") return msg.id - } - return undefined + return messages.findLast( + (item): item is AssistantMessage => item.role === "assistant" && typeof item.time.completed !== "number", + ) }) - const isLastUserMessage = createMemo(() => props.messageID === lastUserMessageID()) + const pendingUser = createMemo(() => { + const item = pending() + if (!item?.parentID) return + const messages = allMessages() ?? emptyMessages + const result = Binary.search(messages, item.parentID, (m) => m.id) + const msg = result.found ? messages[result.index] : messages.find((m) => m.id === item.parentID) + if (!msg || msg.role !== "user") return + return msg + }) + + const active = createMemo(() => { + if (typeof props.active === "boolean") return props.active + const msg = message() + const parent = pendingUser() + if (!msg || !parent) return false + return parent.id === msg.id + }) + + const queued = createMemo(() => { + if (typeof props.queued === "boolean") return props.queued + const id = message()?.id + if (!id) return false + if (!pendingUser()) return false + const item = pending() + if (!item) return false + return id > item.id + }) const parts = createMemo(() => { const msg = message() @@ -203,6 +233,8 @@ export function SessionTurn( return list(data.store.part?.[msg.id], emptyParts) }) + const compaction = createMemo(() => parts().find((part) => part.type === "compaction")) + const diffs = createMemo(() => { const files = message()?.summary?.diffs if (!files?.length) return emptyDiffs @@ -281,8 +313,12 @@ export function SessionTurn( return unwrap(String(msg)) }) - const status = createMemo(() => data.store.session_status[props.sessionID] ?? idle) - const working = createMemo(() => status().type !== "idle" && isLastUserMessage()) + const status = createMemo(() => { + if (props.status !== undefined) return props.status + if (typeof props.active === "boolean" && !props.active) return idle + return data.store.session_status[props.sessionID] ?? idle + }) + const working = createMemo(() => status().type !== "idle" && active()) const showReasoningSummaries = createMemo(() => props.showReasoningSummaries ?? true) const assistantCopyPartID = createMemo(() => { @@ -330,8 +366,9 @@ export function SessionTurn( ) const showThinking = createMemo(() => { if (!working() || !!error()) return false + if (queued()) return false + if (status().type === "retry") return false if (showReasoningSummaries()) return assistantVisible() === 0 - if (assistantTailVisible() === "text") return false return true }) @@ -351,141 +388,149 @@ export function SessionTurn( > <div onClick={autoScroll.handleInteraction}> <Show when={message()}> - {(msg) => ( - <div - ref={autoScroll.contentRef} - data-message={msg().id} - data-slot="session-turn-message-container" - class={props.classes?.container} - > - <div data-slot="session-turn-message-content" aria-live="off"> - <Message message={msg()} parts={parts()} interrupted={interrupted()} /> + <div + ref={autoScroll.contentRef} + data-message={message()!.id} + data-slot="session-turn-message-container" + class={props.classes?.container} + > + <div data-slot="session-turn-message-content" aria-live="off"> + <Message message={message()!} parts={parts()} interrupted={interrupted()} queued={queued()} /> + </div> + <Show when={compaction()}> + <div data-slot="session-turn-compaction"> + <Part part={compaction()!} message={message()!} hideDetails /> </div> - <Show when={assistantMessages().length > 0}> - <div data-slot="session-turn-assistant-content" aria-hidden={working()}> - <AssistantParts - messages={assistantMessages()} - showAssistantCopyPartID={assistantCopyPartID()} - turnDurationMs={turnDurationMs()} - working={working()} - showReasoningSummaries={showReasoningSummaries()} + </Show> + <Show when={assistantMessages().length > 0}> + <div data-slot="session-turn-assistant-content" aria-hidden={working()}> + <AssistantParts + messages={assistantMessages()} + showAssistantCopyPartID={assistantCopyPartID()} + turnDurationMs={turnDurationMs()} + working={working()} + showReasoningSummaries={showReasoningSummaries()} + shellToolDefaultOpen={props.shellToolDefaultOpen} + editToolDefaultOpen={props.editToolDefaultOpen} + /> + </div> + </Show> + <Show when={showThinking()}> + <div data-slot="session-turn-thinking"> + <TextShimmer text={i18n.t("ui.sessionTurn.status.thinking")} /> + <Show when={!showReasoningSummaries()}> + <TextReveal + text={reasoningHeading()} + class="session-turn-thinking-heading" + travel={25} + duration={700} /> - </div> - </Show> - <Show when={showThinking()}> - <div data-slot="session-turn-thinking"> - <TextShimmer text={i18n.t("ui.sessionTurn.status.thinking")} /> - <Show when={!showReasoningSummaries() && reasoningHeading()}> - {(text) => <span data-slot="session-turn-thinking-heading">{text()}</span>} - </Show> - </div> - </Show> - <Show when={edited() > 0 && !working()}> - <div data-slot="session-turn-diffs"> - <Collapsible open={open()} onOpenChange={setOpen} variant="ghost"> - <Collapsible.Trigger> - <div data-component="session-turn-diffs-trigger"> - <div data-slot="session-turn-diffs-title"> - <span data-slot="session-turn-diffs-label"> - {i18n.t("ui.sessionReview.change.modified")} - </span> - <span data-slot="session-turn-diffs-count"> - {edited()} {i18n.t(edited() === 1 ? "ui.common.file.one" : "ui.common.file.other")} - </span> - <div data-slot="session-turn-diffs-meta"> - <DiffChanges changes={diffs()} variant="bars" /> - <Collapsible.Arrow /> - </div> + </Show> + </div> + </Show> + <SessionRetry status={status()} show={active()} /> + <Show when={edited() > 0 && !working()}> + <div data-slot="session-turn-diffs"> + <Collapsible open={open()} onOpenChange={setOpen} variant="ghost"> + <Collapsible.Trigger> + <div data-component="session-turn-diffs-trigger"> + <div data-slot="session-turn-diffs-title"> + <span data-slot="session-turn-diffs-label">{i18n.t("ui.sessionReview.change.modified")}</span> + <span data-slot="session-turn-diffs-count"> + {edited()} {i18n.t(edited() === 1 ? "ui.common.file.one" : "ui.common.file.other")} + </span> + <div data-slot="session-turn-diffs-meta"> + <DiffChanges changes={diffs()} variant="bars" /> + <Collapsible.Arrow /> </div> </div> - </Collapsible.Trigger> - <Collapsible.Content> - <Show when={open()}> - <div data-component="session-turn-diffs-content"> - <Accordion - multiple - style={{ "--sticky-accordion-offset": "40px" }} - value={expanded()} - onChange={(value) => setExpanded(Array.isArray(value) ? value : value ? [value] : [])} - > - <For each={diffs()}> - {(diff) => { - const active = createMemo(() => expanded().includes(diff.file)) - const [visible, setVisible] = createSignal(false) + </div> + </Collapsible.Trigger> + <Collapsible.Content> + <Show when={open()}> + <div data-component="session-turn-diffs-content"> + <Accordion + multiple + style={{ "--sticky-accordion-offset": "40px" }} + value={expanded()} + onChange={(value) => setExpanded(Array.isArray(value) ? value : value ? [value] : [])} + > + <For each={diffs()}> + {(diff) => { + const active = createMemo(() => expanded().includes(diff.file)) + const [visible, setVisible] = createSignal(false) - createEffect( - on( - active, - (value) => { - if (!value) { - setVisible(false) - return - } + createEffect( + on( + active, + (value) => { + if (!value) { + setVisible(false) + return + } - requestAnimationFrame(() => { - if (!active()) return - setVisible(true) - }) - }, - { defer: true }, - ), - ) + requestAnimationFrame(() => { + if (!active()) return + setVisible(true) + }) + }, + { defer: true }, + ), + ) - return ( - <Accordion.Item value={diff.file}> - <StickyAccordionHeader> - <Accordion.Trigger> - <div data-slot="session-turn-diff-trigger"> - <span data-slot="session-turn-diff-path"> - <Show when={diff.file.includes("/")}> - <span data-slot="session-turn-diff-directory"> - {`\u202A${getDirectory(diff.file)}\u202C`} - </span> - </Show> - <span data-slot="session-turn-diff-filename"> - {getFilename(diff.file)} + return ( + <Accordion.Item value={diff.file}> + <StickyAccordionHeader> + <Accordion.Trigger> + <div data-slot="session-turn-diff-trigger"> + <span data-slot="session-turn-diff-path"> + <Show when={diff.file.includes("/")}> + <span data-slot="session-turn-diff-directory"> + {`\u202A${getDirectory(diff.file)}\u202C`} </span> + </Show> + <span data-slot="session-turn-diff-filename">{getFilename(diff.file)}</span> + </span> + <div data-slot="session-turn-diff-meta"> + <span data-slot="session-turn-diff-changes"> + <DiffChanges changes={diff} /> + </span> + <span data-slot="session-turn-diff-chevron"> + <Icon name="chevron-down" size="small" /> </span> - <div data-slot="session-turn-diff-meta"> - <span data-slot="session-turn-diff-changes"> - <DiffChanges changes={diff} /> - </span> - <span data-slot="session-turn-diff-chevron"> - <Icon name="chevron-down" size="small" /> - </span> - </div> </div> - </Accordion.Trigger> - </StickyAccordionHeader> - <Accordion.Content> - <Show when={visible()}> - <div data-slot="session-turn-diff-view" data-scrollable> - <Dynamic - component={diffComponent} - before={{ name: diff.file, contents: diff.before }} - after={{ name: diff.file, contents: diff.after }} - /> - </div> - </Show> - </Accordion.Content> - </Accordion.Item> - ) - }} - </For> - </Accordion> - </div> - </Show> - </Collapsible.Content> - </Collapsible> - </div> - </Show> - <Show when={error()}> - <Card variant="error" class="error-card"> - {errorText()} - </Card> - </Show> - </div> - )} + </div> + </Accordion.Trigger> + </StickyAccordionHeader> + <Accordion.Content> + <Show when={visible()}> + <div data-slot="session-turn-diff-view" data-scrollable> + <Dynamic + component={fileComponent} + mode="diff" + before={{ name: diff.file, contents: diff.before }} + after={{ name: diff.file, contents: diff.after }} + /> + </div> + </Show> + </Accordion.Content> + </Accordion.Item> + ) + }} + </For> + </Accordion> + </div> + </Show> + </Collapsible.Content> + </Collapsible> + </div> + </Show> + <Show when={error()}> + <Card variant="error" class="error-card"> + {errorText()} + </Card> + </Show> + </div> </Show> {props.children} </div> diff --git a/packages/ui/src/components/shell-submessage-motion.stories.tsx b/packages/ui/src/components/shell-submessage-motion.stories.tsx new file mode 100644 index 0000000000..1f53b6e4de --- /dev/null +++ b/packages/ui/src/components/shell-submessage-motion.stories.tsx @@ -0,0 +1,329 @@ +// @ts-nocheck +import { createEffect, createSignal, onCleanup } from "solid-js" +import { BasicTool } from "./basic-tool" +import { animate } from "motion" + +export default { + title: "UI/Shell Submessage Motion", + id: "components-shell-submessage-motion", + tags: ["autodocs"], + parameters: { + docs: { + description: { + component: `### Overview +Interactive playground for animating the Shell tool subtitle ("submessage") in the timeline trigger row. + +### Production component path +- Trigger layout: \`packages/ui/src/components/basic-tool.tsx\` +- Bash tool subtitle source: \`packages/ui/src/components/message-part.tsx\` (tool: \`bash\`, \`trigger.subtitle\`) + +### What this playground tunes +- Width reveal (spring-driven pixel width via \`useSpring\`) +- Opacity fade +- Blur settle`, + }, + }, + }, +} + +const btn = (accent?: boolean) => + ({ + padding: "6px 14px", + "border-radius": "6px", + border: "1px solid var(--color-divider, #333)", + background: accent ? "var(--color-accent, #58f)" : "var(--color-fill-element, #222)", + color: "var(--color-text, #eee)", + cursor: "pointer", + "font-size": "13px", + }) as const + +const sliderLabel = { + "font-size": "11px", + "font-family": "monospace", + color: "var(--color-text-weak, #666)", + "min-width": "84px", + "flex-shrink": "0", + "text-align": "right", +} + +const sliderValue = { + "font-family": "monospace", + "font-size": "11px", + color: "var(--color-text-weak, #aaa)", + "min-width": "76px", +} + +const shellCss = ` +[data-component="shell-submessage-scene"] [data-component="tool-trigger"] [data-slot="basic-tool-tool-info-main"] { + align-items: baseline; +} + +[data-component="shell-submessage"] { + min-width: 0; + max-width: 100%; + display: inline-flex; + align-items: baseline; + vertical-align: baseline; +} + +[data-component="shell-submessage"] [data-slot="shell-submessage-width"] { + min-width: 0; + max-width: 100%; + display: inline-flex; + align-items: baseline; + overflow: hidden; +} + +[data-component="shell-submessage"] [data-slot="shell-submessage-value"] { + display: inline-block; + vertical-align: baseline; + min-width: 0; + line-height: inherit; + white-space: nowrap; + opacity: 0; + filter: blur(var(--shell-sub-blur, 2px)); + transition-property: opacity, filter; + transition-duration: var(--shell-sub-fade-ms, 320ms); + transition-timing-function: var(--shell-sub-fade-ease, cubic-bezier(0.22, 1, 0.36, 1)); +} + +[data-component="shell-submessage"][data-visible] [data-slot="shell-submessage-value"] { + opacity: 1; + filter: blur(0px); +} +` + +const ease = { + smooth: "cubic-bezier(0.16, 1, 0.3, 1)", + snappy: "cubic-bezier(0.22, 1, 0.36, 1)", + standard: "cubic-bezier(0.2, 0.8, 0.2, 1)", + linear: "linear", +} + +function SpringSubmessage(props: { text: string; visible: boolean; visualDuration: number; bounce: number }) { + let ref: HTMLSpanElement | undefined + let widthRef: HTMLSpanElement | undefined + + createEffect(() => { + if (!widthRef) return + if (props.visible) { + requestAnimationFrame(() => { + ref?.setAttribute("data-visible", "") + animate( + widthRef!, + { width: "auto" }, + { type: "spring", visualDuration: props.visualDuration, bounce: props.bounce }, + ) + }) + } else { + ref?.removeAttribute("data-visible") + animate( + widthRef, + { width: "0px" }, + { type: "spring", visualDuration: props.visualDuration, bounce: props.bounce }, + ) + } + }) + + return ( + <span ref={ref} data-component="shell-submessage"> + <span ref={widthRef} data-slot="shell-submessage-width" style={{ width: "0px" }}> + <span data-slot="basic-tool-tool-subtitle"> + <span data-slot="shell-submessage-value">{props.text || "\u00A0"}</span> + </span> + </span> + </span> + ) +} + +export const Playground = { + render: () => { + const [text, setText] = createSignal("Prints five topic blocks between timed commands") + const [show, setShow] = createSignal(true) + const [visualDuration, setVisualDuration] = createSignal(0.35) + const [bounce, setBounce] = createSignal(0) + const [fadeMs, setFadeMs] = createSignal(320) + const [blur, setBlur] = createSignal(2) + const [fadeEase, setFadeEase] = createSignal<keyof typeof ease>("snappy") + const [auto, setAuto] = createSignal(false) + let replayTimer + let autoTimer + + const replay = () => { + setShow(false) + if (replayTimer) clearTimeout(replayTimer) + replayTimer = setTimeout(() => { + setShow(true) + }, 50) + } + + const stopAuto = () => { + if (autoTimer) clearInterval(autoTimer) + autoTimer = undefined + setAuto(false) + } + + const toggleAuto = () => { + if (auto()) { + stopAuto() + return + } + setAuto(true) + autoTimer = setInterval(replay, 2200) + } + + onCleanup(() => { + if (replayTimer) clearTimeout(replayTimer) + if (autoTimer) clearInterval(autoTimer) + }) + + return ( + <div + data-component="shell-submessage-scene" + style={{ + display: "grid", + gap: "20px", + padding: "20px", + "max-width": "860px", + "--shell-sub-fade-ms": `${fadeMs()}ms`, + "--shell-sub-blur": `${blur()}px`, + "--shell-sub-fade-ease": ease[fadeEase()], + }} + > + <style>{shellCss}</style> + + <BasicTool + icon="console" + defaultOpen + trigger={ + <div data-slot="basic-tool-tool-info-structured"> + <div data-slot="basic-tool-tool-info-main"> + <span data-slot="basic-tool-tool-title">Shell</span> + <SpringSubmessage text={text()} visible={show()} visualDuration={visualDuration()} bounce={bounce()} /> + </div> + </div> + } + > + <div + style={{ + "border-radius": "8px", + border: "1px solid var(--color-divider, #333)", + background: "var(--color-fill-secondary, #161616)", + padding: "14px 16px", + "font-family": "ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace", + "font-size": "18px", + color: "var(--color-text, #eee)", + "white-space": "pre-wrap", + }} + > + {"$ cat <<'TOPIC1'"} + </div> + </BasicTool> + + <div style={{ display: "flex", gap: "8px", "flex-wrap": "wrap" }}> + <button onClick={replay} style={btn()}> + Replay entry + </button> + <button onClick={() => setShow((v) => !v)} style={btn(show())}> + {show() ? "Hide subtitle" : "Show subtitle"} + </button> + <button onClick={toggleAuto} style={btn(auto())}> + {auto() ? "Stop auto replay" : "Auto replay"} + </button> + </div> + + <div + style={{ + display: "grid", + gap: "10px", + "border-top": "1px solid var(--color-divider, #333)", + "padding-top": "14px", + }} + > + <div style={{ display: "flex", "align-items": "center", gap: "12px" }}> + <span style={sliderLabel}>subtitle</span> + <input + value={text()} + onInput={(e) => setText(e.currentTarget.value)} + style={{ + width: "420px", + "max-width": "100%", + padding: "6px 8px", + "border-radius": "6px", + border: "1px solid var(--color-divider, #333)", + background: "var(--color-fill-element, #222)", + color: "var(--color-text, #eee)", + }} + /> + </div> + + <div style={{ display: "flex", "align-items": "center", gap: "12px" }}> + <span style={sliderLabel}>visualDuration</span> + <input + type="range" + min={0.05} + max={1.5} + step={0.01} + value={visualDuration()} + onInput={(e) => setVisualDuration(Number(e.currentTarget.value))} + /> + <span style={sliderValue}>{visualDuration().toFixed(2)}s</span> + </div> + + <div style={{ display: "flex", "align-items": "center", gap: "12px" }}> + <span style={sliderLabel}>bounce</span> + <input + type="range" + min={0} + max={0.5} + step={0.01} + value={bounce()} + onInput={(e) => setBounce(Number(e.currentTarget.value))} + /> + <span style={sliderValue}>{bounce().toFixed(2)}</span> + </div> + + <div style={{ display: "flex", "align-items": "center", gap: "12px" }}> + <span style={sliderLabel}>fade ease</span> + <button + onClick={() => + setFadeEase((v) => + v === "snappy" ? "smooth" : v === "smooth" ? "standard" : v === "standard" ? "linear" : "snappy", + ) + } + style={btn()} + > + {fadeEase()} + </button> + </div> + + <div style={{ display: "flex", "align-items": "center", gap: "12px" }}> + <span style={sliderLabel}>fade</span> + <input + type="range" + min={0} + max={1400} + step={10} + value={fadeMs()} + onInput={(e) => setFadeMs(Number(e.currentTarget.value))} + /> + <span style={sliderValue}>{fadeMs()}ms</span> + </div> + + <div style={{ display: "flex", "align-items": "center", gap: "12px" }}> + <span style={sliderLabel}>blur</span> + <input + type="range" + min={0} + max={14} + step={0.5} + value={blur()} + onInput={(e) => setBlur(Number(e.currentTarget.value))} + /> + <span style={sliderValue}>{blur()}px</span> + </div> + </div> + </div> + ) + }, +} diff --git a/packages/ui/src/components/shell-submessage.css b/packages/ui/src/components/shell-submessage.css new file mode 100644 index 0000000000..f72ba3fc75 --- /dev/null +++ b/packages/ui/src/components/shell-submessage.css @@ -0,0 +1,23 @@ +[data-component="shell-submessage"] { + min-width: 0; + max-width: 100%; + display: inline-flex; + align-items: baseline; + vertical-align: baseline; +} + +[data-component="shell-submessage"] [data-slot="shell-submessage-width"] { + min-width: 0; + max-width: 100%; + display: inline-flex; + align-items: baseline; + overflow: hidden; +} + +[data-component="shell-submessage"] [data-slot="shell-submessage-value"] { + display: inline-block; + vertical-align: baseline; + min-width: 0; + line-height: inherit; + white-space: nowrap; +} diff --git a/packages/ui/src/components/spinner.stories.tsx b/packages/ui/src/components/spinner.stories.tsx new file mode 100644 index 0000000000..be6106d148 --- /dev/null +++ b/packages/ui/src/components/spinner.stories.tsx @@ -0,0 +1,53 @@ +// @ts-nocheck +import * as mod from "./spinner" +import { create } from "../storybook/scaffold" + +const docs = `### Overview +Animated loading indicator for inline or page-level loading states. + +Use with \`Button\` or in empty states. + +### API +- Accepts standard SVG props (class, style). + +### Variants and states +- Single default animation style. + +### Behavior +- Animation is CSS-driven via data attributes. + +### Accessibility +- Use alongside text or aria-live regions to convey loading state. + +### Theming/tokens +- Uses \`data-component="spinner"\` for styling hooks. + +` + +const story = create({ title: "UI/Spinner", mod }) + +export default { + title: "UI/Spinner", + id: "components-spinner", + component: story.meta.component, + tags: ["autodocs"], + parameters: { + docs: { + description: { + component: docs, + }, + }, + }, +} + +export const Basic = story.Basic + +export const Sizes = { + render: () => ( + <div style={{ display: "flex", gap: "16px", "align-items": "center" }}> + <mod.Spinner style={{ width: "12px", height: "12px" }} /> + <mod.Spinner style={{ width: "20px", height: "20px" }} /> + <mod.Spinner style={{ width: "28px", height: "28px" }} /> + </div> + ), +} diff --git a/packages/ui/src/components/spinner.tsx b/packages/ui/src/components/spinner.tsx index cc4149d174..3d029d9765 100644 --- a/packages/ui/src/components/spinner.tsx +++ b/packages/ui/src/components/spinner.tsx @@ -41,6 +41,7 @@ export function Spinner(props: { animation: square.corner ? undefined : `${square.outer ? "pulse-opacity-dim" : "pulse-opacity"} ${square.duration}s ease-in-out infinite`, + "animation-fill-mode": square.corner ? undefined : "both", "animation-delay": square.corner ? undefined : `${square.delay}s`, }} /> diff --git a/packages/ui/src/components/sticky-accordion-header.stories.tsx b/packages/ui/src/components/sticky-accordion-header.stories.tsx new file mode 100644 index 0000000000..3f03356267 --- /dev/null +++ b/packages/ui/src/components/sticky-accordion-header.stories.tsx @@ -0,0 +1,54 @@ +// @ts-nocheck +import { Accordion } from "./accordion" +import * as mod from "./sticky-accordion-header" + +const docs = `### Overview +Sticky accordion header wrapper for persistent section labels. + +Use only inside \`Accordion.Item\` with \`Accordion.Trigger\`. + +### API +- Accepts standard header props and children. + +### Variants and states +- Inherits accordion states. + +### Behavior +- Renders inside an Accordion item header. + +### Accessibility +- TODO: confirm semantics from Accordion.Header usage. + +### Theming/tokens +- Uses \`data-component="sticky-accordion-header"\`. + +` + +export default { + title: "UI/StickyAccordionHeader", + id: "components-sticky-accordion-header", + component: mod.StickyAccordionHeader, + tags: ["autodocs"], + parameters: { + docs: { + description: { + component: docs, + }, + }, + }, +} + +export const Basic = { + render: () => ( + <Accordion value="first"> + <Accordion.Item value="first"> + <mod.StickyAccordionHeader> + <Accordion.Trigger>Sticky header</Accordion.Trigger> + </mod.StickyAccordionHeader> + <Accordion.Content> + <div style={{ color: "var(--text-weak)", padding: "8px 0" }}>Accordion content.</div> + </Accordion.Content> + </Accordion.Item> + </Accordion> + ), +} diff --git a/packages/ui/src/components/switch.stories.tsx b/packages/ui/src/components/switch.stories.tsx new file mode 100644 index 0000000000..540e91e365 --- /dev/null +++ b/packages/ui/src/components/switch.stories.tsx @@ -0,0 +1,68 @@ +// @ts-nocheck +import * as mod from "./switch" +import { create } from "../storybook/scaffold" + +const docs = `### Overview +Toggle control for binary settings. + +Use in settings panels or forms. + +### API +- Uses Kobalte Switch props (\`checked\`, \`defaultChecked\`, \`onChange\`). +- Optional: \`hideLabel\`, \`description\`. +- Children render as the label. + +### Variants and states +- Checked/unchecked, disabled states. + +### Behavior +- Controlled or uncontrolled usage via Kobalte props. + +### Accessibility +- TODO: confirm aria attributes from Kobalte. + +### Theming/tokens +- Uses \`data-component="switch"\` and slot attributes. + +` + +const story = create({ + title: "UI/Switch", + mod, + args: { defaultChecked: true, children: "Enable notifications" }, +}) + +export default { + title: "UI/Switch", + id: "components-switch", + component: story.meta.component, + tags: ["autodocs"], + parameters: { + docs: { + description: { + component: docs, + }, + }, + }, +} + +export const Basic = story.Basic + +export const States = { + render: () => ( + <div style={{ display: "grid", gap: "12px" }}> + <mod.Switch defaultChecked>Enabled</mod.Switch> + <mod.Switch>Disabled</mod.Switch> + <mod.Switch disabled>Disabled switch</mod.Switch> + <mod.Switch description="Optional description">With description</mod.Switch> + </div> + ), +} + +export const HiddenLabel = { + args: { + children: "Hidden label", + hideLabel: true, + defaultChecked: true, + }, +} diff --git a/packages/ui/src/components/tabs.css b/packages/ui/src/components/tabs.css index 03df9cd84e..036533c10f 100644 --- a/packages/ui/src/components/tabs.css +++ b/packages/ui/src/components/tabs.css @@ -1,4 +1,9 @@ [data-component="tabs"] { + --tabs-bar-height: 48px; + --tabs-compact-pill-height: 24px; + --tabs-compact-pill-radius: 6px; + --tabs-compact-pill-padding-x: 4px; + width: 100%; height: 100%; display: flex; @@ -93,17 +98,6 @@ outline: none; box-shadow: none; } - &:has([data-hidden]) { - [data-slot="tabs-trigger-close-button"] { - opacity: 0; - } - - &:hover { - [data-slot="tabs-trigger-close-button"] { - opacity: 1; - } - } - } &:has([data-selected]) { color: var(--text-strong); background-color: transparent; @@ -112,6 +106,7 @@ opacity: 1; } } + &:hover:not(:disabled):not([data-selected]) { color: var(--text-strong); } @@ -140,6 +135,138 @@ } } + #review-panel &[data-variant="normal"][data-orientation="horizontal"] { + background-color: var(--background-stronger); + + [data-slot="tabs-list"] { + height: var(--tabs-bar-height); + padding-left: 12px; + padding-right: 0; + --tabs-review-gap: 16px; + --tabs-review-fade: 16px; + gap: var(--tabs-review-gap); + background-color: var(--background-stronger); + border-bottom: 1px solid var(--border-weaker-base); + + &::after { + display: none; + } + + > .sticky { + border-bottom: none; + background-color: var(--background-stronger); + + &::before { + content: ""; + position: absolute; + top: 0; + bottom: 0; + left: calc(var(--tabs-review-fade) * -1); + width: var(--tabs-review-fade); + pointer-events: none; + background: linear-gradient(90deg, transparent, var(--background-stronger)); + } + } + } + + [data-slot="tabs-trigger-wrapper"] { + height: var(--tabs-compact-pill-height); + margin-block: 0; + max-width: 320px; + padding-inline: var(--tabs-compact-pill-padding-x); + box-sizing: border-box; + border: 1px solid transparent; + border-radius: var(--tabs-compact-pill-radius); + background-color: transparent; + gap: 8px; + color: var(--text-weak); + transition: + color 120ms ease, + background-color 120ms ease, + border-color 120ms ease; + + &::after { + content: ""; + position: absolute; + left: 0; + right: 0; + bottom: calc((var(--tabs-compact-pill-height) - var(--tabs-bar-height)) / 2); + height: 1px; + background-color: var(--text-strong); + opacity: 0; + transform: scaleX(0.75); + transform-origin: center; + transition: + opacity 120ms ease, + transform 120ms ease; + } + + &[data-value="review"] { + padding-left: 8px; + padding-right: 8px; + } + + [data-slot="tabs-trigger"] { + height: 100%; + padding: 0 !important; + } + + &:has([data-slot="tabs-trigger-close-button"]) { + padding-right: 5px; + [data-slot="tabs-trigger"] { + padding-right: 0 !important; + } + } + + &:has([data-selected]) { + color: var(--text-strong); + background-color: var(--surface-base-active); + border-color: var(--border-weak-base); + + &::after { + opacity: 1; + transform: scaleX(1); + } + } + + &:hover:not(:disabled):not(:has([data-selected])) { + color: var(--text-base); + background-color: var(--surface-base-hover); + } + + /* + File tabs: use monochrome icon by default. + Full-color icon is shown on hover/selected. + */ + [data-slot="tabs-trigger"] { + .tab-fileicon-color, + .tab-fileicon-mono { + pointer-events: none; + } + + .tab-fileicon-color { + display: none; + } + + .tab-fileicon-mono { + display: block; + color: currentColor; + } + + &[data-selected], + &:hover { + .tab-fileicon-color { + display: block; + } + + .tab-fileicon-mono { + display: none; + } + } + } + } + } + &[data-variant="alt"] { [data-slot="tabs-list"] { padding-left: 24px; @@ -279,12 +406,20 @@ gap: 8px; align-items: center; background-color: var(--background-stronger); + box-sizing: border-box; + border-bottom: 1px solid var(--border-weak-base); } [data-slot="tabs-trigger-wrapper"] { - height: 24px; - border-radius: 6px; + height: var(--tabs-compact-pill-height); + border-radius: var(--tabs-compact-pill-radius); color: var(--text-weak); + box-sizing: border-box; + border: 1px solid transparent; + transition: + color 120ms ease, + background-color 120ms ease, + border-color 120ms ease; &:not(:has([data-selected])):hover:not(:disabled) { color: var(--text-base); @@ -292,6 +427,7 @@ &:has([data-selected]) { color: var(--text-strong); + border-color: var(--border-weak-base); } } } @@ -459,3 +595,41 @@ } } } + +[data-component="tabs-drag-preview"] { + position: relative; + display: flex; + align-items: center; + height: var(--tabs-bar-height, 48px); + max-width: 320px; + padding-inline: var(--tabs-compact-pill-padding-x, 4px); + overflow: hidden; + color: var(--text-strong); + opacity: 0.6; +} + +[data-component="tabs-drag-preview"]::before { + content: ""; + position: absolute; + left: 0; + right: 0; + top: calc((var(--tabs-bar-height, 48px) - var(--tabs-compact-pill-height, 24px)) / 2); + height: var(--tabs-compact-pill-height, 24px); + border: 1px solid var(--border-weak-base); + border-radius: var(--tabs-compact-pill-radius, 6px); + background-color: var(--surface-base-active); +} + +[data-component="tabs-drag-preview"]::after { + content: ""; + position: absolute; + left: 0; + right: 0; + bottom: 0; + height: 1px; + background-color: var(--text-strong); +} + +[data-component="tabs-drag-preview"] > * { + position: relative; +} diff --git a/packages/ui/src/components/tabs.stories.tsx b/packages/ui/src/components/tabs.stories.tsx new file mode 100644 index 0000000000..8e09764dcc --- /dev/null +++ b/packages/ui/src/components/tabs.stories.tsx @@ -0,0 +1,179 @@ +// @ts-nocheck +import { IconButton } from "./icon-button" +import { createSignal } from "solid-js" +import * as mod from "./tabs" + +const docs = `### Overview +Tabbed navigation for switching between related panels. + +Compose \`Tabs.List\` + \`Tabs.Trigger\` + \`Tabs.Content\`. + +### API +- Root accepts Kobalte Tabs props (\`value\`, \`defaultValue\`, \`onChange\`). +- \`variant\` sets visual style: normal, alt, pill, settings. +- \`orientation\` supports horizontal or vertical layouts. +- Trigger supports \`closeButton\`, \`hideCloseButton\`, and \`onMiddleClick\`. + +### Variants and states +- Normal, alt, pill, settings variants. +- Horizontal and vertical orientations. + +### Behavior +- Uses Kobalte Tabs for roving focus and selection management. + +### Accessibility +- TODO: confirm keyboard interactions from Kobalte Tabs. + +### Theming/tokens +- Uses \`data-component="tabs"\` with variant/orientation data attributes. + +` + +export default { + title: "UI/Tabs", + id: "components-tabs", + component: mod.Tabs, + tags: ["autodocs"], + parameters: { + docs: { + description: { + component: docs, + }, + }, + }, + argTypes: { + variant: { + control: "select", + options: ["normal", "alt", "pill", "settings"], + }, + orientation: { + control: "select", + options: ["horizontal", "vertical"], + }, + }, +} + +export const Basic = { + args: { + variant: "normal", + orientation: "horizontal", + defaultValue: "overview", + }, + render: (props) => ( + <mod.Tabs {...props}> + <mod.Tabs.List> + <mod.Tabs.Trigger value="overview">Overview</mod.Tabs.Trigger> + <mod.Tabs.Trigger value="details">Details</mod.Tabs.Trigger> + <mod.Tabs.Trigger value="activity">Activity</mod.Tabs.Trigger> + </mod.Tabs.List> + <mod.Tabs.Content value="overview">Overview content</mod.Tabs.Content> + <mod.Tabs.Content value="details">Details content</mod.Tabs.Content> + <mod.Tabs.Content value="activity">Activity content</mod.Tabs.Content> + </mod.Tabs> + ), +} + +export const Settings = { + args: { + variant: "settings", + orientation: "horizontal", + defaultValue: "general", + }, + render: (props) => ( + <mod.Tabs {...props}> + <mod.Tabs.List> + <mod.Tabs.Trigger value="general">General</mod.Tabs.Trigger> + <mod.Tabs.Trigger value="appearance">Appearance</mod.Tabs.Trigger> + </mod.Tabs.List> + <mod.Tabs.Content value="general">General settings</mod.Tabs.Content> + <mod.Tabs.Content value="appearance">Appearance settings</mod.Tabs.Content> + </mod.Tabs> + ), +} + +export const Alt = { + args: { + variant: "alt", + orientation: "horizontal", + defaultValue: "first", + }, + render: (props) => ( + <mod.Tabs {...props}> + <mod.Tabs.List> + <mod.Tabs.Trigger value="first">First</mod.Tabs.Trigger> + <mod.Tabs.Trigger value="second">Second</mod.Tabs.Trigger> + </mod.Tabs.List> + <mod.Tabs.Content value="first">Alt content</mod.Tabs.Content> + <mod.Tabs.Content value="second">Alt content 2</mod.Tabs.Content> + </mod.Tabs> + ), +} + +export const Vertical = { + args: { + variant: "pill", + orientation: "vertical", + defaultValue: "alpha", + }, + render: (props) => ( + <mod.Tabs {...props}> + <mod.Tabs.List> + <mod.Tabs.Trigger value="alpha">Alpha</mod.Tabs.Trigger> + <mod.Tabs.Trigger value="beta">Beta</mod.Tabs.Trigger> + </mod.Tabs.List> + <mod.Tabs.Content value="alpha">Alpha content</mod.Tabs.Content> + <mod.Tabs.Content value="beta">Beta content</mod.Tabs.Content> + </mod.Tabs> + ), +} + +export const Closable = { + args: { + variant: "normal", + orientation: "horizontal", + defaultValue: "tab-1", + }, + render: (props) => ( + <mod.Tabs {...props}> + <mod.Tabs.List> + <mod.Tabs.Trigger + value="tab-1" + closeButton={<IconButton icon="close" size="small" variant="ghost" aria-label="Close tab" />} + > + Tab 1 + </mod.Tabs.Trigger> + <mod.Tabs.Trigger value="tab-2">Tab 2</mod.Tabs.Trigger> + </mod.Tabs.List> + <mod.Tabs.Content value="tab-1">Closable content</mod.Tabs.Content> + <mod.Tabs.Content value="tab-2">Standard content</mod.Tabs.Content> + </mod.Tabs> + ), +} + +export const MiddleClick = { + args: { + variant: "normal", + orientation: "horizontal", + defaultValue: "tab-1", + }, + render: (props) => { + const [message, setMessage] = createSignal("Middle click a tab") + return ( + <div style={{ display: "grid", gap: "8px" }}> + <div style={{ "font-size": "12px", color: "var(--text-weak)" }}>{message()}</div> + <mod.Tabs {...props}> + <mod.Tabs.List> + <mod.Tabs.Trigger value="tab-1" onMiddleClick={() => setMessage("Middle clicked tab-1")}> + Tab 1 + </mod.Tabs.Trigger> + <mod.Tabs.Trigger value="tab-2" onMiddleClick={() => setMessage("Middle clicked tab-2")}> + Tab 2 + </mod.Tabs.Trigger> + </mod.Tabs.List> + <mod.Tabs.Content value="tab-1">Tab 1 content</mod.Tabs.Content> + <mod.Tabs.Content value="tab-2">Tab 2 content</mod.Tabs.Content> + </mod.Tabs> + </div> + ) + }, +} diff --git a/packages/ui/src/components/tabs.tsx b/packages/ui/src/components/tabs.tsx index 4836a0864c..396504dd72 100644 --- a/packages/ui/src/components/tabs.tsx +++ b/packages/ui/src/components/tabs.tsx @@ -61,10 +61,16 @@ function TabsTrigger(props: ParentProps<TabsTriggerProps>) { return ( <div data-slot="tabs-trigger-wrapper" + data-value={props.value} classList={{ ...(split.classList ?? {}), [split.class ?? ""]: !!split.class, }} + onMouseDown={(e) => { + if (e.button === 1 && split.onMiddleClick) { + e.preventDefault() + } + }} onAuxClick={(e) => { if (e.button === 1 && split.onMiddleClick) { e.preventDefault() @@ -75,6 +81,7 @@ function TabsTrigger(props: ParentProps<TabsTriggerProps>) { <Kobalte.Trigger {...rest} data-slot="tabs-trigger" + data-value={props.value} classList={{ [split.classes?.button ?? ""]: split.classes?.button }} > {split.children} diff --git a/packages/ui/src/components/tag.stories.tsx b/packages/ui/src/components/tag.stories.tsx new file mode 100644 index 0000000000..73ae880ba1 --- /dev/null +++ b/packages/ui/src/components/tag.stories.tsx @@ -0,0 +1,58 @@ +// @ts-nocheck +import * as mod from "./tag" +import { create } from "../storybook/scaffold" + +const docs = `### Overview +Small label tag for metadata and status chips. + +Use alongside headings or lists for quick metadata. + +### API +- Optional: \`size\` (normal | large). +- Accepts standard span props. + +### Variants and states +- Size variants only. + +### Behavior +- Inline element; size controls padding and font size via CSS. + +### Accessibility +- Ensure text conveys meaning; avoid color-only distinction. + +### Theming/tokens +- Uses \`data-component="tag"\` with size data attributes. + +` + +const story = create({ title: "UI/Tag", mod, args: { children: "Tag" } }) +export default { + title: "UI/Tag", + id: "components-tag", + component: story.meta.component, + tags: ["autodocs"], + parameters: { + docs: { + description: { + component: docs, + }, + }, + }, + argTypes: { + size: { + control: "select", + options: ["normal", "large"], + }, + }, +} + +export const Basic = story.Basic + +export const Sizes = { + render: () => ( + <div style={{ display: "flex", gap: "8px", "align-items": "center" }}> + <mod.Tag size="normal">Normal</mod.Tag> + <mod.Tag size="large">Large</mod.Tag> + </div> + ), +} diff --git a/packages/ui/src/components/text-field.stories.tsx b/packages/ui/src/components/text-field.stories.tsx new file mode 100644 index 0000000000..73f9006607 --- /dev/null +++ b/packages/ui/src/components/text-field.stories.tsx @@ -0,0 +1,111 @@ +// @ts-nocheck +import * as mod from "./text-field" +import { create } from "../storybook/scaffold" + +const docs = `### Overview +Text input with label, description, and optional copy-to-clipboard action. + +Pair with \`Tooltip\` and \`IconButton\` for copy affordance (built in). + +### API +- Supports Kobalte TextField props: \`value\`, \`defaultValue\`, \`onChange\`, \`disabled\`, \`readOnly\`. +- Optional: \`label\`, \`description\`, \`error\`, \`variant\`, \`copyable\`, \`multiline\`. + +### Variants and states +- Normal and ghost variants. +- Supports multiline textarea. + +### Behavior +- When \`copyable\` is true, clicking copies the current value. + +### Accessibility +- Label is hidden when \`hideLabel\` is true (sr-only). + +### Theming/tokens +- Uses \`data-component="input"\` with slot attributes for styling. + +` + +const story = create({ + title: "UI/TextField", + mod, + args: { + label: "Label", + placeholder: "Type here...", + defaultValue: "Hello", + }, +}) + +export default { + title: "UI/TextField", + id: "components-text-field", + component: story.meta.component, + tags: ["autodocs"], + parameters: { + docs: { + description: { + component: docs, + }, + }, + }, +} + +export const Basic = story.Basic + +export const Variants = { + render: () => ( + <div style={{ display: "grid", gap: "12px", width: "320px" }}> + <mod.TextField label="Normal" placeholder="Type here..." defaultValue="Value" /> + <mod.TextField label="Ghost" variant="ghost" placeholder="Type here..." defaultValue="Value" /> + </div> + ), +} + +export const Multiline = { + args: { + label: "Description", + multiline: true, + defaultValue: "Line one\nLine two", + }, +} + +export const Copyable = { + args: { + label: "Invite link", + defaultValue: "https://example.com/invite/abc", + copyable: true, + copyKind: "link", + }, +} + +export const Error = { + args: { + label: "Email", + defaultValue: "invalid@", + error: "Enter a valid email address", + }, +} + +export const Disabled = { + args: { + label: "Disabled", + defaultValue: "Readonly", + disabled: true, + }, +} + +export const ReadOnly = { + args: { + label: "Read only", + defaultValue: "Read only value", + readOnly: true, + }, +} + +export const HiddenLabel = { + args: { + label: "Hidden label", + hideLabel: true, + placeholder: "Hidden label", + }, +} diff --git a/packages/ui/src/components/text-reveal.css b/packages/ui/src/components/text-reveal.css new file mode 100644 index 0000000000..f799962f09 --- /dev/null +++ b/packages/ui/src/components/text-reveal.css @@ -0,0 +1,150 @@ +/* + * TextReveal — mask-position wipe animation + * + * Instead of sliding text through a fixed mask (odometer style), + * the mask itself sweeps across each span to reveal/hide text. + * + * Direction: top-to-bottom. New text drops in from above, old text exits downward. + * + * Entering: gradient reveals top-to-bottom (top of text appears first). + * gradient(to bottom, white 33%, transparent 33%+edge) + * pos 0 100% = transparent covers element = hidden + * pos 0 0% = white covers element = visible + * + * Leaving: gradient hides top-to-bottom (top of text disappears first). + * gradient(to top, white 33%, transparent 33%+edge) + * pos 0 100% = white covers element = visible + * pos 0 0% = transparent covers element = hidden + * + * Both transition from 0 100% (swap) → 0 0% (settled). + */ + +[data-component="text-reveal"] { + --_edge: var(--text-reveal-edge, 17%); + --_dur: var(--text-reveal-duration, 450ms); + --_spring: var(--text-reveal-spring, cubic-bezier(0.34, 1.08, 0.64, 1)); + --_spring-soft: var(--text-reveal-spring-soft, cubic-bezier(0.34, 1, 0.64, 1)); + --_travel: var(--text-reveal-travel, 0px); + + display: inline-flex; + align-items: center; + min-width: 0; + overflow: visible; + + [data-slot="text-reveal-track"] { + display: grid; + min-height: 20px; + line-height: 20px; + justify-items: start; + align-items: center; + overflow: visible; + transition: width var(--_dur) var(--_spring-soft); + } + + [data-slot="text-reveal-entering"], + [data-slot="text-reveal-leaving"] { + grid-area: 1 / 1; + line-height: 20px; + white-space: nowrap; + justify-self: start; + text-align: start; + mask-size: 100% 300%; + -webkit-mask-size: 100% 300%; + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + transition-duration: var(--_dur); + transition-timing-function: var(--_spring); + } + + /* ── entering: reveal top-to-bottom ── + * Gradient(to top): white at bottom, transparent at top of mask. + * Settled pos 0 100% = white covers element = visible + * Swap pos 0 0% = transparent covers = hidden + * Slides from above: translateY(-travel) → translateY(0) + */ + [data-slot="text-reveal-entering"] { + mask-image: linear-gradient(to top, white 33%, transparent calc(33% + var(--_edge))); + -webkit-mask-image: linear-gradient(to top, white 33%, transparent calc(33% + var(--_edge))); + mask-position: 0 100%; + -webkit-mask-position: 0 100%; + transition-property: + mask-position, + -webkit-mask-position, + transform; + transform: translateY(0); + } + + /* ── leaving: hide top-to-bottom + slide downward ── + * Gradient(to bottom): white at top, transparent at bottom of mask. + * Swap pos 0 0% = white covers element = visible + * Settled pos 0 100% = transparent covers = hidden + * Slides down: translateY(0) → translateY(travel) + */ + [data-slot="text-reveal-leaving"] { + mask-image: linear-gradient(to bottom, white 33%, transparent calc(33% + var(--_edge))); + -webkit-mask-image: linear-gradient(to bottom, white 33%, transparent calc(33% + var(--_edge))); + mask-position: 0 100%; + -webkit-mask-position: 0 100%; + transition-property: + mask-position, + -webkit-mask-position, + transform; + transform: translateY(var(--_travel)); + } + + /* ── swapping: instant reset ── + * Snap entering to hidden (above), leaving to visible (center). + */ + &[data-swapping="true"] [data-slot="text-reveal-entering"] { + mask-position: 0 0%; + -webkit-mask-position: 0 0%; + transform: translateY(calc(var(--_travel) * -1)); + transition-duration: 0ms !important; + } + + &[data-swapping="true"] [data-slot="text-reveal-leaving"] { + mask-position: 0 0%; + -webkit-mask-position: 0 0%; + transform: translateY(0); + transition-duration: 0ms !important; + } + + /* ── not ready: kill all transitions ── */ + &[data-ready="false"] [data-slot="text-reveal-track"] { + transition-duration: 0ms !important; + } + + &[data-ready="false"] [data-slot="text-reveal-entering"], + &[data-ready="false"] [data-slot="text-reveal-leaving"] { + transition-duration: 0ms !important; + } + + &[data-truncate="true"] { + width: 100%; + } + + &[data-truncate="true"] [data-slot="text-reveal-track"] { + width: 100%; + min-width: 0; + overflow: hidden; + } + + &[data-truncate="true"] [data-slot="text-reveal-entering"], + &[data-truncate="true"] [data-slot="text-reveal-leaving"] { + min-width: 0; + width: 100%; + overflow: hidden; + text-overflow: ellipsis; + } +} + +@media (prefers-reduced-motion: reduce) { + [data-component="text-reveal"] [data-slot="text-reveal-track"] { + transition-duration: 0ms !important; + } + + [data-component="text-reveal"] [data-slot="text-reveal-entering"], + [data-component="text-reveal"] [data-slot="text-reveal-leaving"] { + transition-duration: 0ms !important; + } +} diff --git a/packages/ui/src/components/text-reveal.stories.tsx b/packages/ui/src/components/text-reveal.stories.tsx new file mode 100644 index 0000000000..df514ca38d --- /dev/null +++ b/packages/ui/src/components/text-reveal.stories.tsx @@ -0,0 +1,310 @@ +// @ts-nocheck +import { createSignal, onCleanup } from "solid-js" +import { TextReveal } from "./text-reveal" + +export default { + title: "UI/TextReveal", + id: "components-text-reveal", + tags: ["autodocs"], + parameters: { + docs: { + description: { + component: `### Overview +Playground for the TextReveal text transition component. + +**Hybrid** — mask wipe + vertical slide: gradient sweeps AND text moves downward. + +**Wipe only** — pure mask wipe: gradient sweeps top-to-bottom, text stays in place.`, + }, + }, + }, +} + +const TEXTS = [ + "Refactor ToolStatusTitle DOM measurement", + "Remove inline measure nodes", + "Run typechecks and report changes", + "Verify reduced-motion behavior", + "Review diff for animation edge cases", + "Check keyboard semantics", + undefined, + "Planning key generation details", + "Analyzing error handling", + "Considering edge cases", +] + +const btn = (accent?: boolean) => + ({ + padding: "5px 12px", + "border-radius": "6px", + border: accent ? "1px solid var(--color-accent, #58f)" : "1px solid var(--color-divider, #333)", + background: accent ? "var(--color-accent, #58f)" : "var(--color-fill-element, #222)", + color: "var(--color-text, #eee)", + cursor: "pointer", + "font-size": "12px", + }) as const + +const sliderLabel = { + width: "90px", + "font-size": "12px", + color: "var(--color-text-secondary, #a3a3a3)", + "flex-shrink": "0", +} as const + +const cardStyle = { + padding: "20px 24px", + "border-radius": "10px", + border: "1px solid var(--color-divider, #333)", + background: "var(--color-fill-element, #1a1a1a)", + display: "grid", + gap: "12px", +} as const + +const cardLabel = { + "font-size": "11px", + "font-family": "monospace", + color: "var(--color-text-weak, #666)", +} as const + +const previewRow = { + display: "flex", + "align-items": "center", + gap: "8px", + "font-size": "14px", + "font-weight": "500", + "line-height": "20px", + color: "var(--text-weak, #aaa)", + "min-height": "20px", + overflow: "visible", +} as const + +const headingSlot = { + "min-width": "0", + overflow: "visible", + color: "var(--text-weaker, #888)", + "font-weight": "400", +} as const + +export const Playground = { + render: () => { + const [index, setIndex] = createSignal(0) + const [cycling, setCycling] = createSignal(false) + const [growOnly, setGrowOnly] = createSignal(true) + + const [duration, setDuration] = createSignal(600) + const [bounce, setBounce] = createSignal(1.0) + const [bounceSoft, setBounceSoft] = createSignal(1.0) + + const [hybridTravel, setHybridTravel] = createSignal(25) + const [hybridEdge, setHybridEdge] = createSignal(17) + + const [edge, setEdge] = createSignal(17) + const [revealTravel, setRevealTravel] = createSignal(0) + + let timer: number | undefined + const text = () => TEXTS[index()] + const next = () => setIndex((i) => (i + 1) % TEXTS.length) + const prev = () => setIndex((i) => (i - 1 + TEXTS.length) % TEXTS.length) + + const toggleCycle = () => { + if (cycling()) { + if (timer) clearTimeout(timer) + timer = undefined + setCycling(false) + return + } + setCycling(true) + const tick = () => { + next() + timer = window.setTimeout(tick, 700 + Math.floor(Math.random() * 600)) + } + timer = window.setTimeout(tick, 700 + Math.floor(Math.random() * 600)) + } + + onCleanup(() => { + if (timer) clearTimeout(timer) + }) + + const spring = () => `cubic-bezier(0.34, ${bounce()}, 0.64, 1)` + const springSoft = () => `cubic-bezier(0.34, ${bounceSoft()}, 0.64, 1)` + + return ( + <div style={{ display: "grid", gap: "24px", padding: "20px", "max-width": "700px" }}> + <div style={{ display: "grid", gap: "16px" }}> + <div style={cardStyle}> + <span style={cardLabel}>text-reveal (mask wipe + slide)</span> + <div style={previewRow}> + <span>Thinking</span> + <span style={headingSlot}> + <TextReveal + class="text-14-regular" + text={text()} + duration={duration()} + edge={hybridEdge()} + travel={hybridTravel()} + spring={spring()} + springSoft={springSoft()} + growOnly={growOnly()} + /> + </span> + </div> + </div> + + <div style={cardStyle}> + <span style={cardLabel}>text-reveal (mask wipe only)</span> + <div style={previewRow}> + <span>Thinking</span> + <span style={headingSlot}> + <TextReveal + class="text-14-regular" + text={text()} + duration={duration()} + edge={edge()} + travel={revealTravel()} + spring={spring()} + springSoft={springSoft()} + growOnly={growOnly()} + /> + </span> + </div> + </div> + </div> + + <div style={{ display: "flex", gap: "6px", "flex-wrap": "wrap" }}> + {TEXTS.map((t, i) => ( + <button onClick={() => setIndex(i)} style={btn(index() === i)}> + {t ?? "(none)"} + </button> + ))} + </div> + + <div style={{ display: "flex", gap: "8px", "flex-wrap": "wrap" }}> + <button onClick={prev} style={btn()}> + Prev + </button> + <button onClick={next} style={btn()}> + Next + </button> + <button onClick={toggleCycle} style={btn(cycling())}> + {cycling() ? "Stop cycle" : "Auto cycle"} + </button> + <button onClick={() => setGrowOnly((v) => !v)} style={btn(growOnly())}> + {growOnly() ? "growOnly: on" : "growOnly: off"} + </button> + </div> + + <div style={{ display: "grid", gap: "8px", "max-width": "480px" }}> + <div style={{ "font-size": "11px", color: "var(--color-text-weak, #666)" }}>Hybrid (wipe + slide)</div> + + <label style={{ display: "flex", "align-items": "center", gap: "12px" }}> + <span style={sliderLabel}>edge</span> + <input + type="range" + min="1" + max="40" + step="1" + value={hybridEdge()} + onInput={(e) => setHybridEdge(e.currentTarget.valueAsNumber)} + style={{ flex: 1 }} + /> + <span style={{ width: "60px", "text-align": "right", "font-size": "12px" }}>{hybridEdge()}%</span> + </label> + + <label style={{ display: "flex", "align-items": "center", gap: "12px" }}> + <span style={sliderLabel}>travel</span> + <input + type="range" + min="0" + max="40" + step="1" + value={hybridTravel()} + onInput={(e) => setHybridTravel(e.currentTarget.valueAsNumber)} + style={{ flex: 1 }} + /> + <span style={{ width: "60px", "text-align": "right", "font-size": "12px" }}>{hybridTravel()}px</span> + </label> + + <div style={{ "font-size": "11px", color: "var(--color-text-weak, #666)", "margin-top": "8px" }}>Shared</div> + + <label style={{ display: "flex", "align-items": "center", gap: "12px" }}> + <span style={sliderLabel}>duration</span> + <input + type="range" + min="100" + max="1400" + step="10" + value={duration()} + onInput={(e) => setDuration(e.currentTarget.valueAsNumber)} + style={{ flex: 1 }} + /> + <span style={{ width: "60px", "text-align": "right", "font-size": "12px" }}>{duration()}ms</span> + </label> + + <label style={{ display: "flex", "align-items": "center", gap: "12px" }}> + <span style={sliderLabel}>bounce</span> + <input + type="range" + min="1" + max="2" + step="0.01" + value={bounce()} + onInput={(e) => setBounce(e.currentTarget.valueAsNumber)} + style={{ flex: 1 }} + /> + <span style={{ width: "60px", "text-align": "right", "font-size": "12px" }}>{bounce().toFixed(2)}</span> + </label> + + <label style={{ display: "flex", "align-items": "center", gap: "12px" }}> + <span style={sliderLabel}>bounce soft</span> + <input + type="range" + min="1" + max="1.5" + step="0.01" + value={bounceSoft()} + onInput={(e) => setBounceSoft(e.currentTarget.valueAsNumber)} + style={{ flex: 1 }} + /> + <span style={{ width: "60px", "text-align": "right", "font-size": "12px" }}>{bounceSoft().toFixed(2)}</span> + </label> + + <div style={{ "font-size": "11px", color: "var(--color-text-weak, #666)", "margin-top": "8px" }}> + Wipe only + </div> + + <label style={{ display: "flex", "align-items": "center", gap: "12px" }}> + <span style={sliderLabel}>edge</span> + <input + type="range" + min="1" + max="40" + step="1" + value={edge()} + onInput={(e) => setEdge(e.currentTarget.valueAsNumber)} + style={{ flex: 1 }} + /> + <span style={{ width: "60px", "text-align": "right", "font-size": "12px" }}>{edge()}%</span> + </label> + + <label style={{ display: "flex", "align-items": "center", gap: "12px" }}> + <span style={sliderLabel}>travel</span> + <input + type="range" + min="0" + max="16" + step="1" + value={revealTravel()} + onInput={(e) => setRevealTravel(e.currentTarget.valueAsNumber)} + style={{ flex: 1 }} + /> + <span style={{ width: "60px", "text-align": "right", "font-size": "12px" }}>{revealTravel()}px</span> + </label> + </div> + + <div style={{ "font-size": "11px", color: "var(--color-text-weak, #888)", "font-family": "monospace" }}> + text: {text() ?? "(none)"} · growOnly: {growOnly() ? "on" : "off"} + </div> + </div> + ) + }, +} diff --git a/packages/ui/src/components/text-reveal.tsx b/packages/ui/src/components/text-reveal.tsx new file mode 100644 index 0000000000..c4fe1302f0 --- /dev/null +++ b/packages/ui/src/components/text-reveal.tsx @@ -0,0 +1,135 @@ +import { createEffect, createSignal, on, onCleanup, onMount } from "solid-js" + +const px = (value: number | string | undefined, fallback: number) => { + if (typeof value === "number") return `${value}px` + if (typeof value === "string") return value + return `${fallback}px` +} + +const ms = (value: number | string | undefined, fallback: number) => { + if (typeof value === "number") return `${value}ms` + if (typeof value === "string") return value + return `${fallback}ms` +} + +const pct = (value: number | undefined, fallback: number) => { + const v = value ?? fallback + return `${v}%` +} + +export function TextReveal(props: { + text?: string + class?: string + duration?: number | string + /** Gradient edge softness as a percentage of the mask (0 = hard wipe, 17 = soft). */ + edge?: number + /** Optional small vertical travel for entering text (px). Default 0. */ + travel?: number | string + spring?: string + springSoft?: string + growOnly?: boolean + truncate?: boolean +}) { + const [cur, setCur] = createSignal(props.text) + const [old, setOld] = createSignal<string | undefined>() + const [width, setWidth] = createSignal("auto") + const [ready, setReady] = createSignal(false) + const [swapping, setSwapping] = createSignal(false) + let inRef: HTMLSpanElement | undefined + let outRef: HTMLSpanElement | undefined + let rootRef: HTMLSpanElement | undefined + let frame: number | undefined + + const win = () => inRef?.scrollWidth ?? 0 + const wout = () => outRef?.scrollWidth ?? 0 + + const widen = (next: number) => { + if (next <= 0) return + if (props.growOnly ?? true) { + const prev = Number.parseFloat(width()) + if (Number.isFinite(prev) && next <= prev) return + } + setWidth(`${next}px`) + } + + createEffect( + on( + () => props.text, + (next, prev) => { + if (next === prev) return + if (typeof next === "string" && typeof prev === "string" && next.startsWith(prev)) { + setCur(next) + widen(win()) + return + } + setSwapping(true) + setOld(prev) + setCur(next) + + if (typeof requestAnimationFrame !== "function") { + widen(Math.max(win(), wout())) + rootRef?.offsetHeight + setSwapping(false) + return + } + if (frame !== undefined && typeof cancelAnimationFrame === "function") cancelAnimationFrame(frame) + frame = requestAnimationFrame(() => { + widen(Math.max(win(), wout())) + rootRef?.offsetHeight + setSwapping(false) + frame = undefined + }) + }, + ), + ) + + onMount(() => { + widen(win()) + const fonts = typeof document !== "undefined" ? document.fonts : undefined + if (typeof requestAnimationFrame !== "function") { + setReady(true) + return + } + if (!fonts) { + requestAnimationFrame(() => setReady(true)) + return + } + fonts.ready.finally(() => { + widen(win()) + requestAnimationFrame(() => setReady(true)) + }) + }) + + onCleanup(() => { + if (frame === undefined || typeof cancelAnimationFrame !== "function") return + cancelAnimationFrame(frame) + }) + + return ( + <span + ref={rootRef} + data-component="text-reveal" + data-ready={ready() ? "true" : "false"} + data-swapping={swapping() ? "true" : "false"} + data-truncate={props.truncate ? "true" : "false"} + class={props.class} + aria-label={props.text ?? ""} + style={{ + "--text-reveal-duration": ms(props.duration, 450), + "--text-reveal-edge": pct(props.edge, 17), + "--text-reveal-travel": px(props.travel, 0), + "--text-reveal-spring": props.spring ?? "cubic-bezier(0.34, 1.08, 0.64, 1)", + "--text-reveal-spring-soft": props.springSoft ?? "cubic-bezier(0.34, 1, 0.64, 1)", + }} + > + <span data-slot="text-reveal-track" style={{ width: props.truncate ? "100%" : width() }}> + <span data-slot="text-reveal-entering" ref={inRef}> + {cur() ?? "\u00A0"} + </span> + <span data-slot="text-reveal-leaving" ref={outRef}> + {old() ?? "\u00A0"} + </span> + </span> + </span> + ) +} diff --git a/packages/ui/src/components/text-shimmer.css b/packages/ui/src/components/text-shimmer.css index 929a2d8516..f042dd2d86 100644 --- a/packages/ui/src/components/text-shimmer.css +++ b/packages/ui/src/components/text-shimmer.css @@ -1,43 +1,119 @@ [data-component="text-shimmer"] { --text-shimmer-step: 45ms; --text-shimmer-duration: 1200ms; + --text-shimmer-swap: 220ms; + --text-shimmer-index: 0; + --text-shimmer-angle: 90deg; + --text-shimmer-spread: 5.2ch; + --text-shimmer-size: 360%; + --text-shimmer-base-color: var(--text-weak); + --text-shimmer-peak-color: var(--text-strong); + --text-shimmer-sweep: linear-gradient( + var(--text-shimmer-angle), + transparent calc(50% - var(--text-shimmer-spread)), + var(--text-shimmer-peak-color) 50%, + transparent calc(50% + var(--text-shimmer-spread)) + ); + --text-shimmer-base: linear-gradient(var(--text-shimmer-base-color), var(--text-shimmer-base-color)); + + display: inline-flex; + align-items: baseline; + font: inherit; + letter-spacing: inherit; + line-height: inherit; } [data-component="text-shimmer"] [data-slot="text-shimmer-char"] { + display: inline-grid; white-space: pre; - color: inherit; + font: inherit; + letter-spacing: inherit; + line-height: inherit; } -[data-component="text-shimmer"][data-active="true"] [data-slot="text-shimmer-char"] { - animation-name: text-shimmer-char; +[data-component="text-shimmer"] [data-slot="text-shimmer-char-base"], +[data-component="text-shimmer"] [data-slot="text-shimmer-char-shimmer"] { + grid-area: 1 / 1; + white-space: pre; + transition: opacity var(--text-shimmer-swap) ease-out; + font: inherit; + letter-spacing: inherit; + line-height: inherit; +} + +[data-component="text-shimmer"] [data-slot="text-shimmer-char-base"] { + color: inherit; + opacity: 1; +} + +[data-component="text-shimmer"] [data-slot="text-shimmer-char-shimmer"] { + color: var(--text-weaker); + opacity: 0; +} + +[data-component="text-shimmer"][data-active="true"] [data-slot="text-shimmer-char-shimmer"] { + opacity: 1; +} + +[data-component="text-shimmer"] [data-slot="text-shimmer-char-shimmer"][data-run="true"] { + animation-name: text-shimmer-sweep; animation-duration: var(--text-shimmer-duration); animation-iteration-count: infinite; - animation-timing-function: ease-in-out; - animation-delay: calc(var(--text-shimmer-step) * var(--text-shimmer-index)); + animation-timing-function: linear; + animation-fill-mode: both; + animation-delay: calc(var(--text-shimmer-step) * var(--text-shimmer-index) * -1); + will-change: background-position; } -@keyframes text-shimmer-char { - 0%, +@keyframes text-shimmer-sweep { + 0% { + background-position: + 100% 0, + 0 0; + } + 100% { - color: var(--text-weaker); + background-position: + 0% 0, + 0 0; + } +} + +@supports ((-webkit-background-clip: text) or (background-clip: text)) { + [data-component="text-shimmer"] [data-slot="text-shimmer-char-shimmer"] { + color: transparent; + -webkit-text-fill-color: transparent; + background-image: var(--text-shimmer-sweep), var(--text-shimmer-base); + background-size: + var(--text-shimmer-size) 100%, + 100% 100%; + background-position: + 100% 0, + 0 0; + background-repeat: no-repeat; + -webkit-background-clip: text; + background-clip: text; } - 30% { - color: var(--text-weak); - } - - 55% { - color: var(--text-base); - } - - 75% { - color: var(--text-strong); + [data-component="text-shimmer"][data-active="true"] [data-slot="text-shimmer-char-base"] { + opacity: 0; } } @media (prefers-reduced-motion: reduce) { - [data-component="text-shimmer"] [data-slot="text-shimmer-char"] { + [data-component="text-shimmer"] [data-slot="text-shimmer-char-base"], + [data-component="text-shimmer"] [data-slot="text-shimmer-char-shimmer"] { + transition-duration: 0ms; + } + + [data-component="text-shimmer"] [data-slot="text-shimmer-char-shimmer"] { animation: none !important; color: inherit; + -webkit-text-fill-color: currentColor; + background-image: none; + } + + [data-component="text-shimmer"] [data-slot="text-shimmer-char-base"] { + opacity: 1 !important; } } diff --git a/packages/ui/src/components/text-shimmer.stories.tsx b/packages/ui/src/components/text-shimmer.stories.tsx new file mode 100644 index 0000000000..a88a7158b1 --- /dev/null +++ b/packages/ui/src/components/text-shimmer.stories.tsx @@ -0,0 +1,92 @@ +// @ts-nocheck +import * as mod from "./text-shimmer" +import { useArgs } from "storybook/preview-api" +import { create } from "../storybook/scaffold" + +const docs = `### Overview +Animated shimmer effect for loading text placeholders. + +Use for pending states inside buttons or list rows. + +### API +- Required: \`text\` string. +- Optional: \`as\`, \`active\`, \`offset\`, \`class\`. + +### Variants and states +- Active/inactive state via \`active\`. + +### Behavior +- Uses a moving gradient sweep clipped to text. +- \`offset\` lets multiple shimmers run out-of-phase. + +### Accessibility +- Uses \`aria-label\` with the full text. + +### Theming/tokens +- Uses \`data-component="text-shimmer"\` and CSS custom properties for timing. + +` + +const defaults = { + text: "Loading...", + active: true, + class: "text-14-medium text-text-strong", + offset: 0, +} as const + +const story = create({ title: "UI/TextShimmer", mod, args: defaults }) + +export default { + title: "UI/TextShimmer", + id: "components-text-shimmer", + component: story.meta.component, + tags: ["autodocs"], + args: defaults, + argTypes: { + text: { control: "text" }, + class: { control: "text" }, + active: { control: "boolean" }, + offset: { control: { type: "range", min: 0, max: 80, step: 1 } }, + }, + parameters: { + docs: { + description: { + component: docs, + }, + }, + }, +} + +export const Basic = { + args: defaults, + render: (args) => { + const [, updateArgs] = useArgs() + const reset = () => updateArgs(defaults) + return ( + <div style={{ display: "grid", gap: "12px", "justify-items": "start" }}> + <mod.TextShimmer {...args} /> + <button + onClick={reset} + style={{ + padding: "4px 10px", + "font-size": "12px", + "border-radius": "6px", + border: "1px solid var(--color-divider, #333)", + background: "var(--color-fill-element, #222)", + color: "var(--color-text, #eee)", + cursor: "pointer", + }} + > + Reset controls + </button> + </div> + ) + }, +} + +export const Inactive = { + args: { + text: "Static text", + active: false, + }, +} diff --git a/packages/ui/src/components/text-shimmer.tsx b/packages/ui/src/components/text-shimmer.tsx index 6ee4ef4020..3ab077d92d 100644 --- a/packages/ui/src/components/text-shimmer.tsx +++ b/packages/ui/src/components/text-shimmer.tsx @@ -1,4 +1,4 @@ -import { For, createMemo, type ValidComponent } from "solid-js" +import { createEffect, createMemo, createSignal, onCleanup, type ValidComponent } from "solid-js" import { Dynamic } from "solid-js/web" export const TextShimmer = <T extends ValidComponent = "span">(props: { @@ -6,31 +6,57 @@ export const TextShimmer = <T extends ValidComponent = "span">(props: { class?: string as?: T active?: boolean - stepMs?: number - durationMs?: number + offset?: number }) => { - const chars = createMemo(() => Array.from(props.text)) - const active = () => props.active ?? true + const text = createMemo(() => props.text ?? "") + const active = createMemo(() => props.active ?? true) + const offset = createMemo(() => props.offset ?? 0) + const [run, setRun] = createSignal(active()) + const swap = 220 + let timer: ReturnType<typeof setTimeout> | undefined + + createEffect(() => { + if (timer) { + clearTimeout(timer) + timer = undefined + } + + if (active()) { + setRun(true) + return + } + + timer = setTimeout(() => { + timer = undefined + setRun(false) + }, swap) + }) + + onCleanup(() => { + if (!timer) return + clearTimeout(timer) + }) return ( <Dynamic - component={props.as || "span"} + component={props.as ?? "span"} data-component="text-shimmer" - data-active={active()} + data-active={active() ? "true" : "false"} class={props.class} - aria-label={props.text} + aria-label={text()} style={{ - "--text-shimmer-step": `${props.stepMs ?? 45}ms`, - "--text-shimmer-duration": `${props.durationMs ?? 1200}ms`, + "--text-shimmer-swap": `${swap}ms`, + "--text-shimmer-index": `${offset()}`, }} > - <For each={chars()}> - {(char, index) => ( - <span data-slot="text-shimmer-char" aria-hidden="true" style={{ "--text-shimmer-index": `${index()}` }}> - {char} - </span> - )} - </For> + <span data-slot="text-shimmer-char"> + <span data-slot="text-shimmer-char-base" aria-hidden="true"> + {text()} + </span> + <span data-slot="text-shimmer-char-shimmer" data-run={run() ? "true" : "false"} aria-hidden="true"> + {text()} + </span> + </span> </Dynamic> ) } diff --git a/packages/ui/src/components/text-strikethrough.css b/packages/ui/src/components/text-strikethrough.css new file mode 100644 index 0000000000..1be8054683 --- /dev/null +++ b/packages/ui/src/components/text-strikethrough.css @@ -0,0 +1,27 @@ +/* + * TextStrikethrough — spring-animated strikethrough line + * + * Draws a line-through from left to right using clip-path on a + * transparent-text overlay that carries the text-decoration. + * Grid stacking (grid-area: 1/1) layers the overlay on the base text. + * + * Key trick: -webkit-text-fill-color hides the glyph paint while + * keeping `color` (and therefore `currentColor` / text-decoration-color) + * set to the real inherited text color. + */ + +[data-component="text-strikethrough"] { + display: grid; +} + +[data-slot="text-strikethrough-line"] { + -webkit-text-fill-color: transparent; + text-decoration-line: line-through; + pointer-events: none; +} + +@media (prefers-reduced-motion: reduce) { + [data-slot="text-strikethrough-line"] { + clip-path: none !important; + } +} diff --git a/packages/ui/src/components/text-strikethrough.stories.tsx b/packages/ui/src/components/text-strikethrough.stories.tsx new file mode 100644 index 0000000000..b07e745534 --- /dev/null +++ b/packages/ui/src/components/text-strikethrough.stories.tsx @@ -0,0 +1,279 @@ +// @ts-nocheck +import { createEffect, createSignal, onCleanup, onMount } from "solid-js" +import { useSpring } from "./motion-spring" +import { TextStrikethrough } from "./text-strikethrough" + +const TEXT_SHORT = "Remove inline measure nodes" +const TEXT_MED = "Remove inline measure nodes and keep width morph behavior intact" +const TEXT_LONG = + "Refactor ToolStatusTitle DOM measurement to offscreen global measurer (unconstrained by timeline layout)" + +const btn = (active?: boolean) => + ({ + padding: "8px 18px", + "border-radius": "6px", + border: "1px solid var(--color-divider, #444)", + background: active ? "var(--color-accent, #58f)" : "var(--color-fill-element, #222)", + color: "var(--color-text, #eee)", + cursor: "pointer", + "font-size": "14px", + "font-weight": "500", + }) as const + +const heading = { + "font-size": "11px", + "font-weight": "600", + "text-transform": "uppercase" as const, + "letter-spacing": "0.05em", + color: "var(--text-weak, #888)", + "margin-bottom": "4px", +} + +const card = { + padding: "16px 20px", + "border-radius": "10px", + border: "1px solid var(--border-weak-base, #333)", + background: "var(--surface-base, #1a1a1a)", +} + +/* ─── Variant A: scaleX pseudo-line at 50% ─── */ +function VariantA(props: { active: boolean; text: string }) { + const progress = useSpring( + () => (props.active ? 1 : 0), + () => ({ visualDuration: 0.35, bounce: 0 }), + ) + return ( + <span + style={{ + position: "relative", + display: "block", + color: props.active ? "var(--text-weak, #888)" : "var(--text-strong, #eee)", + transition: "color 220ms ease", + }} + > + {props.text} + <span + style={{ + position: "absolute", + left: "0", + right: "0", + top: "50%", + height: "1.5px", + background: "currentColor", + "transform-origin": "left center", + transform: `scaleX(${progress()})`, + "pointer-events": "none", + }} + /> + </span> + ) +} + +/* ─── Variant D: background-image line ─── */ +function VariantD(props: { active: boolean; text: string }) { + const progress = useSpring( + () => (props.active ? 1 : 0), + () => ({ visualDuration: 0.35, bounce: 0 }), + ) + return ( + <span + style={{ + display: "block", + color: props.active ? "var(--text-weak, #888)" : "var(--text-strong, #eee)", + transition: "color 220ms ease", + "background-image": "linear-gradient(currentColor, currentColor)", + "background-repeat": "no-repeat", + "background-size": `${progress() * 100}% 1.5px`, + "background-position": "left center", + }} + > + {props.text} + </span> + ) +} + +/* ─── Variant E: grid stacking + clip-path (container %) ─── */ +function VariantE(props: { active: boolean; text: string }) { + const progress = useSpring( + () => (props.active ? 1 : 0), + () => ({ visualDuration: 0.35, bounce: 0 }), + ) + return ( + <span + style={{ + display: "grid", + color: props.active ? "var(--text-weak, #888)" : "var(--text-strong, #eee)", + transition: "color 220ms ease", + }} + > + <span style={{ "grid-area": "1 / 1" }}>{props.text}</span> + <span + aria-hidden="true" + style={{ + "grid-area": "1 / 1", + "text-decoration": "line-through", + "pointer-events": "none", + "clip-path": `inset(0 ${(1 - progress()) * 100}% 0 0)`, + }} + > + {props.text} + </span> + </span> + ) +} + +/* ─── Variant F: grid stacking + clip-path mapped to text width ─── */ +function VariantF(props: { active: boolean; text: string }) { + const progress = useSpring( + () => (props.active ? 1 : 0), + () => ({ visualDuration: 0.35, bounce: 0 }), + ) + let baseRef: HTMLSpanElement | undefined + let containerRef: HTMLSpanElement | undefined + const [textWidth, setTextWidth] = createSignal(0) + const [containerWidth, setContainerWidth] = createSignal(0) + + const measure = () => { + if (baseRef) setTextWidth(baseRef.scrollWidth) + if (containerRef) setContainerWidth(containerRef.offsetWidth) + } + + onMount(measure) + createEffect(() => { + const el = containerRef + if (!el) return + const observer = new ResizeObserver(measure) + observer.observe(el) + onCleanup(() => observer.disconnect()) + }) + + const clipRight = () => { + const cw = containerWidth() + const tw = textWidth() + if (cw <= 0 || tw <= 0) return `${(1 - progress()) * 100}%` + const revealed = progress() * tw + const remaining = Math.max(0, cw - revealed) + return `${remaining}px` + } + + return ( + <span + ref={containerRef} + style={{ + display: "grid", + color: props.active ? "var(--text-weak, #888)" : "var(--text-strong, #eee)", + transition: "color 220ms ease", + }} + > + <span ref={baseRef} style={{ "grid-area": "1 / 1" }}> + {props.text} + </span> + <span + aria-hidden="true" + style={{ + "grid-area": "1 / 1", + "text-decoration": "line-through", + "pointer-events": "none", + "clip-path": `inset(0 ${clipRight()} 0 0)`, + }} + > + {props.text} + </span> + </span> + ) +} + +export default { + title: "UI/Text Strikethrough", + id: "components-text-strikethrough", + tags: ["autodocs"], + parameters: { + docs: { + description: { + component: `### Animated Strikethrough Variants + +- **A** — scaleX line at 50% (single line only) +- **D** — background-image line (single line only) +- **E** — grid stacking + clip-path (container %) +- **F** — grid stacking + clip-path mapped to text width (the real component)`, + }, + }, + }, +} + +export const Playground = { + render: () => { + const [active, setActive] = createSignal(false) + const toggle = () => setActive((v) => !v) + + return ( + <div style={{ display: "grid", gap: "24px", padding: "24px", "max-width": "700px" }}> + <button onClick={toggle} style={btn(active())}> + {active() ? "Undo strikethrough" : "Strike through all"} + </button> + + <div style={card}> + <div style={heading}>F — grid stacking + clip mapped to text width (THE COMPONENT)</div> + <TextStrikethrough + active={active()} + text={TEXT_SHORT} + style={{ + color: active() ? "var(--text-weak, #888)" : "var(--text-strong, #eee)", + transition: "color 220ms ease", + }} + /> + <div style={{ "margin-top": "12px" }} /> + <TextStrikethrough + active={active()} + text={TEXT_MED} + style={{ + color: active() ? "var(--text-weak, #888)" : "var(--text-strong, #eee)", + transition: "color 220ms ease", + }} + /> + <div style={{ "margin-top": "12px" }} /> + <TextStrikethrough + active={active()} + text={TEXT_LONG} + style={{ + color: active() ? "var(--text-weak, #888)" : "var(--text-strong, #eee)", + transition: "color 220ms ease", + }} + /> + </div> + + <div style={card}> + <div style={heading}>F (inline) — same but just inline variants</div> + <VariantF active={active()} text={TEXT_SHORT} /> + <div style={{ "margin-top": "12px" }} /> + <VariantF active={active()} text={TEXT_MED} /> + <div style={{ "margin-top": "12px" }} /> + <VariantF active={active()} text={TEXT_LONG} /> + </div> + + <div style={card}> + <div style={heading}>E — grid stacking + clip-path (container %)</div> + <VariantE active={active()} text={TEXT_SHORT} /> + <div style={{ "margin-top": "12px" }} /> + <VariantE active={active()} text={TEXT_MED} /> + <div style={{ "margin-top": "12px" }} /> + <VariantE active={active()} text={TEXT_LONG} /> + </div> + + <div style={card}> + <div style={heading}>A — scaleX line at 50%</div> + <VariantA active={active()} text={TEXT_SHORT} /> + <div style={{ "margin-top": "12px" }} /> + <VariantA active={active()} text={TEXT_LONG} /> + </div> + + <div style={card}> + <div style={heading}>D — background-image line</div> + <VariantD active={active()} text={TEXT_SHORT} /> + <div style={{ "margin-top": "12px" }} /> + <VariantD active={active()} text={TEXT_LONG} /> + </div> + </div> + ) + }, +} diff --git a/packages/ui/src/components/text-strikethrough.tsx b/packages/ui/src/components/text-strikethrough.tsx new file mode 100644 index 0000000000..211e7d44c0 --- /dev/null +++ b/packages/ui/src/components/text-strikethrough.tsx @@ -0,0 +1,85 @@ +import type { JSX } from "solid-js" +import { createEffect, createSignal, onCleanup, onMount } from "solid-js" +import { useSpring } from "./motion-spring" + +export function TextStrikethrough(props: { + /** Whether the strikethrough is active (line drawn across). */ + active: boolean + /** The text to display. Rendered twice internally (base + decoration overlay). */ + text: string + /** Spring visual duration in seconds. Default 0.35. */ + visualDuration?: number + class?: string + style?: JSX.CSSProperties +}) { + const progress = useSpring( + () => (props.active ? 1 : 0), + () => ({ visualDuration: props.visualDuration ?? 0.35, bounce: 0 }), + ) + + let baseRef: HTMLSpanElement | undefined + let containerRef: HTMLSpanElement | undefined + const [textWidth, setTextWidth] = createSignal(0) + const [containerWidth, setContainerWidth] = createSignal(0) + + const measure = () => { + if (baseRef) setTextWidth(baseRef.scrollWidth) + if (containerRef) setContainerWidth(containerRef.offsetWidth) + } + + onMount(measure) + + createEffect(() => { + const el = containerRef + if (!el) return + const observer = new ResizeObserver(measure) + observer.observe(el) + onCleanup(() => observer.disconnect()) + }) + + // Revealed pixels from left = progress * textWidth + const revealedPx = () => { + const tw = textWidth() + return tw > 0 ? progress() * tw : 0 + } + + // Overlay clip: hide everything to the right of revealed area + const overlayClip = () => { + const cw = containerWidth() + const tw = textWidth() + if (cw <= 0 || tw <= 0) return `inset(0 ${(1 - progress()) * 100}% 0 0)` + const remaining = Math.max(0, cw - revealedPx()) + return `inset(0 ${remaining}px 0 0)` + } + + // Base clip: hide everything to the left of revealed area (complementary) + const baseClip = () => { + const px = revealedPx() + if (px <= 0.5) return "none" + return `inset(0 0 0 ${px}px)` + } + + return ( + <span + data-component="text-strikethrough" + class={props.class} + style={{ display: "grid", ...props.style }} + ref={containerRef} + > + <span ref={baseRef} style={{ "grid-area": "1 / 1", "clip-path": baseClip() }}> + {props.text} + </span> + <span + aria-hidden="true" + style={{ + "grid-area": "1 / 1", + "text-decoration": "line-through", + "pointer-events": "none", + "clip-path": overlayClip(), + }} + > + {props.text} + </span> + </span> + ) +} diff --git a/packages/ui/src/components/thinking-heading.stories.tsx b/packages/ui/src/components/thinking-heading.stories.tsx new file mode 100644 index 0000000000..90eb7ee319 --- /dev/null +++ b/packages/ui/src/components/thinking-heading.stories.tsx @@ -0,0 +1,837 @@ +// @ts-nocheck +import { createSignal, createEffect, on, onMount, onCleanup } from "solid-js" +import { TextShimmer } from "./text-shimmer" +import { TextReveal } from "./text-reveal" + +export default { + title: "UI/ThinkingHeading", + id: "components-thinking-heading", + tags: ["autodocs"], + parameters: { + docs: { + description: { + component: `### Overview +Playground for animating the secondary heading beside "Thinking". + +Uses TextReveal for the production heading animation with tunable +duration, travel, bounce, and fade controls.`, + }, + }, + }, +} + +const HEADINGS = [ + "Planning key generation details", + "Analyzing error handling", + undefined, + "Reviewing authentication flow", + "Considering edge cases", + "Evaluating performance", + "Structuring the response", + "Checking type safety", + "Designing the API surface", + "Mapping dependencies", + "Outlining test strategy", +] + +// --------------------------------------------------------------------------- +// CSS +// +// Custom properties driven by sliders: +// --h-duration transition duration (e.g. "600ms") +// --h-duration-raw unitless number for calc (e.g. "600") +// --h-blur blur radius (e.g. "4px") +// --h-travel vertical travel distance (e.g. "18px") +// --h-spring full cubic-bezier for movement (set from bounce slider) +// --h-spring-soft softer version for width transitions +// --h-mask-size fade depth at top/bottom of odometer mask +// --h-mask-pad base padding-block on odometer track +// --h-mask-height extra vertical mask area per side +// --h-mask-bg background color for fade overlays +// --------------------------------------------------------------------------- + +const STYLES = ` +/* ── shared base ────────────────────────────────────────────────── */ +[data-variant] { + display: inline-flex; + align-items: center; +} + +[data-variant] [data-slot="track"] { + display: grid; + overflow: visible; + min-height: 20px; + justify-items: start; + align-items: center; + transition: width var(--h-duration, 600ms) var(--h-spring-soft, cubic-bezier(0.34, 1.1, 0.64, 1)); +} + +[data-variant] [data-slot="entering"], +[data-variant] [data-slot="leaving"] { + grid-area: 1 / 1; + line-height: 20px; + white-space: nowrap; + justify-self: start; +} + +/* kill transitions before fonts are ready */ +[data-variant][data-ready="false"] [data-slot="track"], +[data-variant][data-ready="false"] [data-slot="entering"], +[data-variant][data-ready="false"] [data-slot="leaving"] { + transition-duration: 0ms !important; +} + + +/* ── 1. spring-up ───────────────────────────────────────────────── * + * New text rises from below, old text exits upward. */ + +[data-variant="spring-up"] [data-slot="entering"], +[data-variant="spring-up"] [data-slot="leaving"] { + transition-property: transform, opacity, filter; + transition-duration: + var(--h-duration, 600ms), + calc(var(--h-duration-raw, 600) * 0.6 * 1ms), + calc(var(--h-duration-raw, 600) * 0.5 * 1ms); + transition-timing-function: var(--h-spring), ease-out, ease-out; +} +[data-variant="spring-up"] [data-slot="entering"] { + transform: translateY(0); + opacity: 1; + filter: blur(0); +} +[data-variant="spring-up"] [data-slot="leaving"] { + transform: translateY(calc(var(--h-travel, 18px) * -1)); + opacity: 0; + filter: blur(var(--h-blur, 0px)); +} +[data-variant="spring-up"][data-swapping="true"] [data-slot="entering"] { + transform: translateY(var(--h-travel, 18px)); + opacity: 0; + filter: blur(var(--h-blur, 0px)); + transition-duration: 0ms !important; +} +[data-variant="spring-up"][data-swapping="true"] [data-slot="leaving"] { + transform: translateY(0); + opacity: 1; + filter: blur(0); + transition-duration: 0ms !important; +} + + +/* ── 2. spring-down ─────────────────────────────────────────────── * + * New text drops from above, old text exits downward. */ + +[data-variant="spring-down"] [data-slot="entering"], +[data-variant="spring-down"] [data-slot="leaving"] { + transition-property: transform, opacity, filter; + transition-duration: + var(--h-duration, 600ms), + calc(var(--h-duration-raw, 600) * 0.6 * 1ms), + calc(var(--h-duration-raw, 600) * 0.5 * 1ms); + transition-timing-function: var(--h-spring), ease-out, ease-out; +} +[data-variant="spring-down"] [data-slot="entering"] { + transform: translateY(0); + opacity: 1; + filter: blur(0); +} +[data-variant="spring-down"] [data-slot="leaving"] { + transform: translateY(var(--h-travel, 18px)); + opacity: 0; + filter: blur(var(--h-blur, 0px)); +} +[data-variant="spring-down"][data-swapping="true"] [data-slot="entering"] { + transform: translateY(calc(var(--h-travel, 18px) * -1)); + opacity: 0; + filter: blur(var(--h-blur, 0px)); + transition-duration: 0ms !important; +} +[data-variant="spring-down"][data-swapping="true"] [data-slot="leaving"] { + transform: translateY(0); + opacity: 1; + filter: blur(0); + transition-duration: 0ms !important; +} + + +/* ── 3. spring-pop ──────────────────────────────────────────────── * + * Scale + slight vertical shift + blur. Playful, bouncy. */ + +[data-variant="spring-pop"] [data-slot="entering"], +[data-variant="spring-pop"] [data-slot="leaving"] { + transition-property: transform, opacity, filter; + transition-duration: + var(--h-duration, 600ms), + calc(var(--h-duration-raw, 600) * 0.55 * 1ms), + calc(var(--h-duration-raw, 600) * 0.55 * 1ms); + transition-timing-function: var(--h-spring), ease-out, ease-out; + transform-origin: left center; +} +[data-variant="spring-pop"] [data-slot="entering"] { + transform: translateY(0) scale(1); + opacity: 1; + filter: blur(0); +} +[data-variant="spring-pop"] [data-slot="leaving"] { + transform: translateY(calc(var(--h-travel, 18px) * -0.35)) scale(0.92); + opacity: 0; + filter: blur(var(--h-blur, 3px)); +} +[data-variant="spring-pop"][data-swapping="true"] [data-slot="entering"] { + transform: translateY(calc(var(--h-travel, 18px) * 0.35)) scale(0.92); + opacity: 0; + filter: blur(var(--h-blur, 3px)); + transition-duration: 0ms !important; +} +[data-variant="spring-pop"][data-swapping="true"] [data-slot="leaving"] { + transform: translateY(0) scale(1); + opacity: 1; + filter: blur(0); + transition-duration: 0ms !important; +} + + +/* ── 4. spring-blur ─────────────────────────────────────────────── * + * Pure crossfade with heavy blur. No vertical movement. * + * Width still animates with spring. */ + +[data-variant="spring-blur"] [data-slot="entering"], +[data-variant="spring-blur"] [data-slot="leaving"] { + transition-property: opacity, filter; + transition-duration: + calc(var(--h-duration-raw, 600) * 0.75 * 1ms), + var(--h-duration, 600ms); + transition-timing-function: ease-out, var(--h-spring-soft); +} +[data-variant="spring-blur"] [data-slot="entering"] { + opacity: 1; + filter: blur(0); +} +[data-variant="spring-blur"] [data-slot="leaving"] { + opacity: 0; + filter: blur(calc(var(--h-blur, 4px) * 2)); +} +[data-variant="spring-blur"][data-swapping="true"] [data-slot="entering"] { + opacity: 0; + filter: blur(calc(var(--h-blur, 4px) * 2)); + transition-duration: 0ms !important; +} +[data-variant="spring-blur"][data-swapping="true"] [data-slot="leaving"] { + opacity: 1; + filter: blur(0); + transition-duration: 0ms !important; +} + + +/* ── 5. odometer ──────────────────────────────────────────────── * + * Both texts scroll vertically through a clipped track. * + * * + * overflow:hidden clips at the padding-box edge. * + * mask-image fades to transparent at that same edge. * + * Result: content is invisible at the clip boundary → no hard * + * edge ever visible. Padding + mask height extend the clip area * + * so text has room to travel through the gradient fade zone. * + * * + * Uses transparent→white which works in both alpha & luminance * + * mask modes (transparent=hidden, white=visible in both). */ + +[data-variant="odometer"] [data-slot="track"] { + --h-mask-stop: min(var(--h-mask-size, 20px), calc(50% - 0.5px)); + --h-odo-shift: calc( + 100% + var(--h-travel, 18px) + var(--h-mask-height, 0px) + max(calc(var(--h-mask-pad, 28px) - 28px), 0px) + ); + position: relative; + align-items: stretch; + overflow: hidden; + padding-block: calc(var(--h-mask-pad, 28px) + var(--h-mask-height, 0px)); + margin-block: calc((var(--h-mask-pad, 28px) + var(--h-mask-height, 0px)) * -1); + -webkit-mask-image: linear-gradient( + to bottom, + transparent 0px, + white var(--h-mask-stop), + white calc(100% - var(--h-mask-stop)), + transparent 100% + ); + mask-image: linear-gradient( + to bottom, + transparent 0px, + white var(--h-mask-stop), + white calc(100% - var(--h-mask-stop)), + transparent 100% + ); + transition: width var(--h-duration, 600ms) var(--h-spring-soft, cubic-bezier(0.34, 1.1, 0.64, 1)); +} + +/* on swap, jump width instantly to the max of both texts */ +[data-variant="odometer"][data-swapping="true"] [data-slot="track"] { + transition-duration: 0ms !important; +} + +[data-variant="odometer"] [data-slot="entering"], +[data-variant="odometer"] [data-slot="leaving"] { + transition-property: transform; + transition-duration: var(--h-duration, 600ms); + transition-timing-function: var(--h-spring); + opacity: 1; +} +/* settled: entering in view, leaving pushed below */ +[data-variant="odometer"] [data-slot="entering"] { + transform: translateY(0); +} +[data-variant="odometer"] [data-slot="leaving"] { + transform: translateY(var(--h-odo-shift)); +} +/* swapping: snap entering above, leaving in-place */ +[data-variant="odometer"][data-swapping="true"] [data-slot="entering"] { + transform: translateY(calc(var(--h-odo-shift) * -1)); + transition-duration: 0ms !important; +} +[data-variant="odometer"][data-swapping="true"] [data-slot="leaving"] { + transform: translateY(0); + transition-duration: 0ms !important; +} + +/* ── odometer + blur ──────────────────────────────────────────── * + * Optional: adds opacity + blur transitions on top of the * + * positional odometer movement. */ + +[data-variant="odometer"][data-odo-blur="true"] [data-slot="entering"], +[data-variant="odometer"][data-odo-blur="true"] [data-slot="leaving"] { + transition-property: transform, opacity, filter; + transition-duration: + var(--h-duration, 600ms), + calc(var(--h-duration-raw, 600) * 0.6 * 1ms), + calc(var(--h-duration-raw, 600) * 0.5 * 1ms); +} +[data-variant="odometer"][data-odo-blur="true"] [data-slot="entering"] { + opacity: 1; + filter: blur(0); +} +[data-variant="odometer"][data-odo-blur="true"] [data-slot="leaving"] { + opacity: 0; + filter: blur(var(--h-blur, 4px)); +} +[data-variant="odometer"][data-odo-blur="true"][data-swapping="true"] [data-slot="entering"] { + opacity: 0; + filter: blur(var(--h-blur, 4px)); +} +[data-variant="odometer"][data-odo-blur="true"][data-swapping="true"] [data-slot="leaving"] { + opacity: 1; + filter: blur(0); +} + +/* ── debug: show fade zones ───────────────────────────────────── */ +[data-variant="odometer"][data-debug="true"] [data-slot="track"] { + outline: 1px dashed rgba(255, 0, 0, 0.6); +} +[data-variant="odometer"][data-debug="true"] [data-slot="track"]::before, +[data-variant="odometer"][data-debug="true"] [data-slot="track"]::after { + content: ""; + position: absolute; + left: 0; + right: 0; + height: var(--h-mask-stop); + pointer-events: none; +} +[data-variant="odometer"][data-debug="true"] [data-slot="track"]::before { + top: 0; + background: linear-gradient(to bottom, rgba(255, 0, 0, 0.3), transparent); +} +[data-variant="odometer"][data-debug="true"] [data-slot="track"]::after { + bottom: 0; + background: linear-gradient(to top, rgba(255, 0, 0, 0.3), transparent); +} + + +/* ── slider styling ─────────────────────────────────────────────── */ +input[type="range"].heading-slider { + -webkit-appearance: none; + appearance: none; + width: 140px; + height: 4px; + border-radius: 2px; + background: var(--color-divider, #444); + outline: none; +} +input[type="range"].heading-slider::-webkit-slider-thumb { + -webkit-appearance: none; + appearance: none; + width: 14px; + height: 14px; + border-radius: 50%; + background: var(--color-accent, #58f); + cursor: pointer; + border: none; +} +` + +// --------------------------------------------------------------------------- +// Animated heading component +// +// Width is measured via scrollWidth (NOT Range.getBoundingClientRect) because +// getBoundingClientRect includes CSS transforms — so scale(0.92) during the +// swap phase would measure 92% of the real width and permanently clip text. +// scrollWidth returns the layout/intrinsic width, unaffected by transforms. +// --------------------------------------------------------------------------- + +function AnimatedHeading(props) { + const [current, setCurrent] = createSignal(props.text) + const [leaving, setLeaving] = createSignal(undefined) + const [width, setWidth] = createSignal("auto") + const [ready, setReady] = createSignal(false) + const [swapping, setSwapping] = createSignal(false) + let enterRef + let leaveRef + let containerRef + let frame + + const measureEnter = () => enterRef?.scrollWidth ?? 0 + const measureLeave = () => leaveRef?.scrollWidth ?? 0 + const widen = (px) => { + if (px <= 0) return + const w = Number.parseFloat(width()) + if (Number.isFinite(w) && px <= w) return + setWidth(`${px}px`) + } + + const measure = () => { + if (!current()) { + setWidth("0px") + return + } + const px = measureEnter() + if (px > 0) setWidth(`${px}px`) + } + + createEffect( + on( + () => props.text, + (next, prev) => { + if (next === prev) return + setSwapping(true) + setLeaving(prev) + setCurrent(next) + + if (frame) cancelAnimationFrame(frame) + frame = requestAnimationFrame(() => { + // For odometer keep width as a grow-only max so heading never shrinks. + if (props.variant === "odometer") { + const enterW = measureEnter() + const leaveW = measureLeave() + widen(Math.max(enterW, leaveW)) + containerRef?.offsetHeight // reflow with max width + swap positions + setSwapping(false) + } else { + containerRef?.offsetHeight + setSwapping(false) + measure() + } + frame = undefined + }) + }, + ), + ) + + onMount(() => { + measure() + document.fonts?.ready.finally(() => { + measure() + requestAnimationFrame(() => setReady(true)) + }) + }) + + onCleanup(() => { + if (frame) cancelAnimationFrame(frame) + }) + + return ( + <span + ref={containerRef} + data-variant={props.variant} + data-ready={ready()} + data-swapping={swapping()} + data-debug={props.debug ? "true" : undefined} + data-odo-blur={props.odoBlur ? "true" : undefined} + > + <span data-slot="track" style={{ width: width() }}> + <span data-slot="entering" ref={enterRef}> + {current() ?? "\u00A0"} + </span> + <span data-slot="leaving" ref={leaveRef}> + {leaving() ?? "\u00A0"} + </span> + </span> + </span> + ) +} + +// --------------------------------------------------------------------------- +// Button / layout styles +// --------------------------------------------------------------------------- + +const btn = (accent) => ({ + padding: "6px 14px", + "border-radius": "6px", + border: "1px solid var(--color-divider, #333)", + background: accent ? "var(--color-danger-fill, #c33)" : "var(--color-fill-element, #222)", + color: "var(--color-text, #eee)", + cursor: "pointer", + "font-size": "13px", +}) + +const smallBtn = (active) => ({ + padding: "4px 12px", + "border-radius": "6px", + border: active ? "1px solid var(--color-accent, #58f)" : "1px solid var(--color-divider, #333)", + background: active ? "var(--color-accent, #58f)" : "var(--color-fill-element, #222)", + color: "var(--color-text, #eee)", + cursor: "pointer", + "font-size": "12px", +}) + +const sliderLabel = { + "font-size": "11px", + "font-family": "monospace", + color: "var(--color-text-weak, #666)", + "min-width": "70px", + "flex-shrink": "0", + "text-align": "right", +} + +const sliderValue = { + "font-family": "monospace", + "font-size": "11px", + color: "var(--color-text-weak, #aaa)", + "min-width": "60px", +} + +const cardLabel = { + "font-size": "11px", + "font-family": "monospace", + color: "var(--color-text-weak, #666)", +} + +const thinkingRow = { + display: "flex", + "align-items": "center", + gap: "8px", + "min-width": "0", + "font-size": "14px", + "font-weight": "500", + "line-height": "20px", + "min-height": "20px", + color: "var(--text-weak, #aaa)", +} + +const headingSlot = { + "min-width": "0", + overflow: "visible", + "white-space": "nowrap", + color: "var(--text-weaker, #888)", + "font-weight": "400", +} + +const cardStyle = { + padding: "16px 20px", + "border-radius": "10px", + border: "1px solid var(--color-divider, #333)", + background: "var(--h-mask-bg, #1a1a1a)", + display: "grid", + gap: "8px", +} + +// --------------------------------------------------------------------------- +// Variants +// --------------------------------------------------------------------------- + +const VARIANTS: { key: string; label: string }[] = [] + +// --------------------------------------------------------------------------- +// Story +// --------------------------------------------------------------------------- + +export const Playground = { + render: () => { + const [heading, setHeading] = createSignal(HEADINGS[0]) + const [headingIndex, setHeadingIndex] = createSignal(0) + const [active, setActive] = createSignal(true) + const [cycling, setCycling] = createSignal(false) + let cycleTimer + + // tunable params + const [duration, setDuration] = createSignal(550) + const [blur, setBlur] = createSignal(2) + const [travel, setTravel] = createSignal(4) + const [bounce, setBounce] = createSignal(1.35) + const [maskSize, setMaskSize] = createSignal(12) + const [maskPad, setMaskPad] = createSignal(9) + const [maskHeight, setMaskHeight] = createSignal(0) + const [debug, setDebug] = createSignal(false) + const [odoBlur, setOdoBlur] = createSignal(false) + + const nextHeading = () => { + setHeadingIndex((i) => { + const next = (i + 1) % HEADINGS.length + setHeading(HEADINGS[next]) + return next + }) + } + + const prevHeading = () => { + setHeadingIndex((i) => { + const prev = (i - 1 + HEADINGS.length) % HEADINGS.length + setHeading(HEADINGS[prev]) + return prev + }) + } + + const toggleCycling = () => { + if (cycling()) { + clearTimeout(cycleTimer) + cycleTimer = undefined + setCycling(false) + return + } + setCycling(true) + const tick = () => { + if (!cycling()) return + nextHeading() + cycleTimer = setTimeout(tick, 850 + Math.floor(Math.random() * 550)) + } + cycleTimer = setTimeout(tick, 850 + Math.floor(Math.random() * 550)) + } + + const clearHeading = () => { + setHeading(undefined) + if (cycling()) { + clearTimeout(cycleTimer) + cycleTimer = undefined + setCycling(false) + } + } + + onCleanup(() => { + if (cycleTimer) clearTimeout(cycleTimer) + }) + + const vars = () => ({ + "--h-duration": `${duration()}ms`, + "--h-duration-raw": `${duration()}`, + "--h-blur": `${blur()}px`, + "--h-travel": `${travel()}px`, + "--h-spring": `cubic-bezier(0.34, ${bounce()}, 0.64, 1)`, + "--h-spring-soft": `cubic-bezier(0.34, ${Math.max(bounce() * 0.7, 1)}, 0.64, 1)`, + "--h-mask-size": `${maskSize()}px`, + "--h-mask-pad": `${maskPad()}px`, + "--h-mask-height": `${maskHeight()}px`, + "--h-mask-bg": "#1a1a1a", + }) + + return ( + <div style={{ display: "grid", gap: "24px", padding: "20px", "max-width": "820px", ...vars() }}> + <style>{STYLES}</style> + + {/* ── Variant cards ─────────────────────────────────── */} + <div style={{ display: "grid", "grid-template-columns": "1fr", gap: "16px" }}> + <div style={cardStyle}> + <span style={cardLabel}>TextReveal (production)</span> + <span style={thinkingRow}> + <TextShimmer text="Thinking" active={active()} /> + <span style={headingSlot}> + <TextReveal + text={heading()} + duration={duration()} + travel={25} + edge={17} + spring={`cubic-bezier(0.34, ${bounce()}, 0.64, 1)`} + springSoft={`cubic-bezier(0.34, ${Math.max(bounce() * 0.7, 1)}, 0.64, 1)`} + growOnly + /> + </span> + </span> + </div> + {VARIANTS.map((v) => ( + <div style={cardStyle}> + <span style={cardLabel}>{v.label}</span> + <span style={thinkingRow}> + <TextShimmer text="Thinking" active={active()} /> + <span style={headingSlot}> + <AnimatedHeading + text={heading()} + variant={v.key} + debug={v.key === "odometer" && debug()} + odoBlur={v.key === "odometer" && odoBlur()} + /> + </span> + </span> + </div> + ))} + </div> + + {/* ── Sliders ──────────────────────────────────────── */} + <div + style={{ + "border-top": "1px solid var(--color-divider, #333)", + "padding-top": "16px", + display: "grid", + gap: "10px", + }} + > + <div style={{ display: "flex", "align-items": "center", gap: "12px" }}> + <span style={sliderLabel}>duration</span> + <input + type="range" + class="heading-slider" + min={200} + max={1400} + step={50} + value={duration()} + onInput={(e) => setDuration(Number(e.currentTarget.value))} + /> + <span style={sliderValue}>{duration()}ms</span> + </div> + + <div style={{ display: "flex", "align-items": "center", gap: "12px" }}> + <span style={sliderLabel}>blur</span> + <input + type="range" + class="heading-slider" + min={0} + max={16} + step={0.5} + value={blur()} + onInput={(e) => setBlur(Number(e.currentTarget.value))} + /> + <span style={sliderValue}>{blur()}px</span> + </div> + + <div style={{ display: "flex", "align-items": "center", gap: "12px" }}> + <span style={sliderLabel}>travel</span> + <input + type="range" + class="heading-slider" + min={4} + max={120} + step={1} + value={travel()} + onInput={(e) => setTravel(Number(e.currentTarget.value))} + /> + <span style={sliderValue}>{travel()}px</span> + </div> + + <div style={{ display: "flex", "align-items": "center", gap: "12px" }}> + <span style={sliderLabel}>bounce</span> + <input + type="range" + class="heading-slider" + min={1} + max={2.2} + step={0.05} + value={bounce()} + onInput={(e) => setBounce(Number(e.currentTarget.value))} + /> + <span style={sliderValue}> + {bounce().toFixed(2)} {bounce() <= 1.05 ? "(none)" : bounce() >= 1.9 ? "(heavy)" : ""} + </span> + </div> + + <div style={{ display: "flex", "align-items": "center", gap: "12px" }}> + <span style={sliderLabel}>mask</span> + <input + type="range" + class="heading-slider" + min={0} + max={50} + step={1} + value={maskSize()} + onInput={(e) => setMaskSize(Number(e.currentTarget.value))} + /> + <span style={sliderValue}> + {maskSize()}px {maskSize() === 0 ? "(hard)" : ""} + </span> + </div> + + <div style={{ display: "flex", "align-items": "center", gap: "12px" }}> + <span style={sliderLabel}>mask pad</span> + <input + type="range" + class="heading-slider" + min={0} + max={60} + step={1} + value={maskPad()} + onInput={(e) => setMaskPad(Number(e.currentTarget.value))} + /> + <span style={sliderValue}>{maskPad()}px</span> + </div> + + <div style={{ display: "flex", "align-items": "center", gap: "12px" }}> + <span style={sliderLabel}>mask height</span> + <input + type="range" + class="heading-slider" + min={0} + max={80} + step={1} + value={maskHeight()} + onInput={(e) => setMaskHeight(Number(e.currentTarget.value))} + /> + <span style={sliderValue}>{maskHeight()}px</span> + </div> + </div> + + {/* ── Controls ─────────────────────────────────────── */} + <div style={{ display: "grid", gap: "12px" }}> + <div style={{ display: "flex", gap: "8px", "flex-wrap": "wrap" }}> + <button onClick={toggleCycling} style={btn(cycling())}> + {cycling() ? "Stop sim" : "Simulate jitter"} + </button> + <button onClick={prevHeading} style={btn()}> + Prev + </button> + <button onClick={nextHeading} style={btn()}> + Next + </button> + <button onClick={clearHeading} style={btn()}> + Clear + </button> + <button onClick={() => setActive((v) => !v)} style={smallBtn(active())}> + {active() ? "Shimmer: on" : "Shimmer: off"} + </button> + <button onClick={() => setDebug((v) => !v)} style={smallBtn(debug())}> + {debug() ? "Debug mask: on" : "Debug mask"} + </button> + <button onClick={() => setOdoBlur((v) => !v)} style={smallBtn(odoBlur())}> + {odoBlur() ? "Odo blur: on" : "Odo blur"} + </button> + </div> + + <div style={{ display: "flex", gap: "6px", "flex-wrap": "wrap" }}> + {HEADINGS.map((h, i) => ( + <button + onClick={() => { + setHeadingIndex(i) + setHeading(h) + }} + style={smallBtn(headingIndex() === i)} + > + {h ?? "(no submessage)"} + </button> + ))} + </div> + + <div + style={{ + "font-size": "11px", + color: "var(--color-text-weak, #888)", + "font-family": "monospace", + }} + > + heading: {heading() ?? "(none)"} · sim: {cycling() ? "on" : "off"} · bounce: {bounce().toFixed(2)} · + odo-blur: {odoBlur() ? "on" : "off"} + </div> + </div> + </div> + ) + }, +} diff --git a/packages/ui/src/components/toast.stories.tsx b/packages/ui/src/components/toast.stories.tsx new file mode 100644 index 0000000000..ef9cbb68ef --- /dev/null +++ b/packages/ui/src/components/toast.stories.tsx @@ -0,0 +1,138 @@ +// @ts-nocheck +import * as mod from "./toast" +import { Button } from "./button" + +const docs = `### Overview +Toast notifications with optional icons, actions, and progress. + +Use brief titles/descriptions; limit actions to 1-2. + +### API +- Use \`showToast\` or \`showPromiseToast\` to trigger toasts. +- Render \`Toast.Region\` once per page. +- \`Toast\` subcomponents compose the structure. + +### Variants and states +- Variants: default, success, error, loading. +- Optional actions and persistent toasts. + +### Behavior +- Toasts render in a portal and auto-dismiss unless persistent. + +### Accessibility +- TODO: confirm aria-live behavior from Kobalte Toast. + +### Theming/tokens +- Uses \`data-component="toast"\` and slot data attributes. + +` + +export default { + title: "UI/Toast", + id: "components-toast", + component: mod.Toast, + tags: ["autodocs"], + parameters: { + docs: { + description: { + component: docs, + }, + }, + }, +} + +export const Basic = { + render: () => ( + <div style={{ display: "grid", gap: "12px" }}> + <mod.Toast.Region /> + <Button + variant="primary" + onClick={() => + mod.showToast({ + title: "Saved", + description: "Your changes are stored.", + variant: "success", + icon: "check", + }) + } + > + Show success toast + </Button> + <Button + variant="secondary" + onClick={() => + mod.showToast({ + description: "This action needs attention.", + variant: "error", + icon: "warning", + }) + } + > + Show error toast + </Button> + </div> + ), +} + +export const Actions = { + render: () => ( + <div style={{ display: "grid", gap: "12px" }}> + <mod.Toast.Region /> + <Button + variant="secondary" + onClick={() => + mod.showToast({ + title: "Update available", + description: "Restart to apply the update.", + actions: [ + { label: "Restart", onClick: "dismiss" }, + { label: "Later", onClick: "dismiss" }, + ], + }) + } + > + Show action toast + </Button> + </div> + ), +} + +export const Promise = { + render: () => ( + <div style={{ display: "grid", gap: "12px" }}> + <mod.Toast.Region /> + <Button + variant="secondary" + onClick={() => + mod.showPromiseToast(() => new Promise((resolve) => setTimeout(() => resolve(true), 800)), { + loading: "Saving...", + success: () => "Saved", + error: () => "Failed", + }) + } + > + Show promise toast + </Button> + </div> + ), +} + +export const Loading = { + render: () => ( + <div style={{ display: "grid", gap: "12px" }}> + <mod.Toast.Region /> + <Button + variant="secondary" + onClick={() => + mod.showToast({ + description: "Syncing...", + variant: "loading", + persistent: true, + }) + } + > + Show loading toast + </Button> + </div> + ), +} diff --git a/packages/ui/src/components/todo-panel-motion.stories.tsx b/packages/ui/src/components/todo-panel-motion.stories.tsx new file mode 100644 index 0000000000..39d3421578 --- /dev/null +++ b/packages/ui/src/components/todo-panel-motion.stories.tsx @@ -0,0 +1,584 @@ +// @ts-nocheck +import { createEffect, createMemo, createSignal, onCleanup } from "solid-js" +import type { Todo } from "@opencode-ai/sdk/v2" +import { useGlobalSync } from "@/context/global-sync" +import { SessionComposerRegion, createSessionComposerState } from "@/pages/session/composer" + +export default { + title: "UI/Todo Panel Motion", + id: "components-todo-panel-motion", + tags: ["autodocs"], + parameters: { + docs: { + description: { + component: `### Overview +This playground renders the real session composer region from app code. + +### Source path +- \`packages/app/src/pages/session/composer/session-composer-region.tsx\` + +### Includes +- \`SessionTodoDock\` (real) +- \`PromptInput\` (real) + +No visual reimplementation layer is used for the dock/input stack.`, + }, + }, + }, +} + +const pool = [ + "Refactor ToolStatusTitle DOM measurement to offscreen global measurer (unconstrained by timeline layout)", + "Remove inline measure nodes/CSS hooks and keep width morph behavior intact", + "Run typechecks/tests and report what changed", + "Verify reduced-motion behavior in timeline", + "Review diff for animation edge cases", + "Document rollout notes in PR description", + "Check keyboard and screen reader semantics", + "Add storybook controls for iteration speed", +] + +const btn = (accent?: boolean) => + ({ + padding: "6px 14px", + "border-radius": "6px", + border: "1px solid var(--color-divider, #333)", + background: accent ? "var(--color-accent, #58f)" : "var(--color-fill-element, #222)", + color: "var(--color-text, #eee)", + cursor: "pointer", + "font-size": "13px", + }) as const + +const css = ` +[data-component="todo-stage"] { + display: grid; + gap: 20px; + padding: 20px; +} + +[data-component="todo-preview"] { + height: 560px; + min-height: 0; +} + +[data-component="todo-session-root"] { + position: relative; + width: 100%; + height: 100%; + overflow: hidden; + display: flex; + flex-direction: column; + background: var(--background-base); + border: 1px solid var(--border-weak-base); + border-radius: 12px; +} + +[data-component="todo-session-frame"] { + flex: 1 1 auto; + min-height: 0; + display: flex; + flex-direction: column; +} + +[data-component="todo-session-panel"] { + position: relative; + flex: 1 1 auto; + min-height: 0; + height: 100%; + display: flex; + flex-direction: column; + background: var(--background-stronger); +} + +[data-slot="todo-preview-content"] { + flex: 1 1 auto; + min-height: 0; + overflow: hidden; +} + +[data-slot="todo-preview-scroll"] { + height: 100%; + overflow: auto; + min-height: 0; + padding: 14px 16px; + display: flex; + flex-direction: column; + gap: 10px; +} + +[data-slot="todo-preview-spacer"] { + flex: 1 1 auto; + min-height: 0; +} + +[data-slot="todo-preview-msg"] { + border-radius: 8px; + border: 1px solid var(--border-weak-base); + background: var(--surface-base); + color: var(--text-weak); + padding: 8px 10px; + font-size: 13px; + line-height: 1.35; +} + +[data-slot="todo-preview-msg"][data-strong="true"] { + color: var(--text-strong); +} +` + +export const Playground = { + render: () => { + const global = useGlobalSync() + const [open, setOpen] = createSignal(true) + const [step, setStep] = createSignal(1) + const [dockOpenDuration, setDockOpenDuration] = createSignal(0.3) + const [dockOpenBounce, setDockOpenBounce] = createSignal(0) + const [dockCloseDuration, setDockCloseDuration] = createSignal(0.3) + const [dockCloseBounce, setDockCloseBounce] = createSignal(0) + const [drawerExpandDuration, setDrawerExpandDuration] = createSignal(0.3) + const [drawerExpandBounce, setDrawerExpandBounce] = createSignal(0) + const [drawerCollapseDuration, setDrawerCollapseDuration] = createSignal(0.3) + const [drawerCollapseBounce, setDrawerCollapseBounce] = createSignal(0) + const [subtitleDuration, setSubtitleDuration] = createSignal(600) + const [subtitleAuto, setSubtitleAuto] = createSignal(true) + const [subtitleTravel, setSubtitleTravel] = createSignal(25) + const [subtitleEdge, setSubtitleEdge] = createSignal(17) + const [countDuration, setCountDuration] = createSignal(600) + const [countMask, setCountMask] = createSignal(18) + const [countMaskHeight, setCountMaskHeight] = createSignal(0) + const [countWidthDuration, setCountWidthDuration] = createSignal(560) + const state = createSessionComposerState({ closeMs: () => Math.round(dockCloseDuration() * 1000) }) + let frame + let composerRef + let scrollRef + + const todos = createMemo<Todo[]>(() => { + const done = Math.max(0, Math.min(3, step())) + return pool.slice(0, 3).map((content, i) => ({ + id: `todo-${i + 1}`, + content, + status: i < done ? "completed" : i === done && done < 3 ? "in_progress" : "pending", + })) + }) + + createEffect(() => { + global.todo.set("story-session", todos()) + }) + + const clear = () => { + if (frame) cancelAnimationFrame(frame) + frame = undefined + } + + const pin = () => { + if (!scrollRef) return + scrollRef.scrollTop = scrollRef.scrollHeight + } + + const collapsed = () => + !!composerRef?.querySelector('[data-action="session-todo-toggle-button"][data-collapsed="true"]') + + const setCollapsed = (value: boolean) => { + const button = composerRef?.querySelector('[data-action="session-todo-toggle-button"]') + if (!(button instanceof HTMLButtonElement)) return + if (collapsed() === value) return + button.click() + } + + const openDock = () => { + clear() + setOpen(true) + frame = requestAnimationFrame(() => { + pin() + frame = undefined + }) + } + + const closeDock = () => { + clear() + setOpen(false) + } + + const dockOpen = () => open() + + const toggleDock = () => { + if (dockOpen()) { + closeDock() + return + } + openDock() + } + + const toggleDrawer = () => { + if (!dockOpen()) { + openDock() + frame = requestAnimationFrame(() => { + pin() + setCollapsed(true) + frame = undefined + }) + return + } + setCollapsed(!collapsed()) + } + + const cycle = () => { + setStep((value) => (value + 1) % 4) + } + + onCleanup(clear) + + return ( + <div data-component="todo-stage"> + <style>{css}</style> + + <div data-component="todo-preview"> + <div data-component="todo-session-root"> + <div data-component="todo-session-frame"> + <div data-component="todo-session-panel"> + <div data-slot="todo-preview-content"> + <div data-slot="todo-preview-scroll" class="scroll-view__viewport" ref={scrollRef}> + <div data-slot="todo-preview-spacer" /> + <div data-slot="todo-preview-msg" data-strong="true"> + Thinking Checking type safety + </div> + <div data-slot="todo-preview-msg">Shell Prints five topic blocks between timed commands</div> + </div> + </div> + + <div ref={composerRef}> + <SessionComposerRegion + state={state} + centered={false} + inputRef={() => {}} + newSessionWorktree="" + onNewSessionWorktreeReset={() => {}} + onSubmit={() => {}} + onResponseSubmit={pin} + setPromptDockRef={() => {}} + dockOpenVisualDuration={dockOpenDuration()} + dockOpenBounce={dockOpenBounce()} + dockCloseVisualDuration={dockCloseDuration()} + dockCloseBounce={dockCloseBounce()} + drawerExpandVisualDuration={drawerExpandDuration()} + drawerExpandBounce={drawerExpandBounce()} + drawerCollapseVisualDuration={drawerCollapseDuration()} + drawerCollapseBounce={drawerCollapseBounce()} + subtitleDuration={subtitleDuration()} + subtitleTravel={subtitleAuto() ? undefined : subtitleTravel()} + subtitleEdge={subtitleAuto() ? undefined : subtitleEdge()} + countDuration={countDuration()} + countMask={countMask()} + countMaskHeight={countMaskHeight()} + countWidthDuration={countWidthDuration()} + /> + </div> + </div> + </div> + </div> + </div> + + <div style={{ display: "flex", gap: "8px", "flex-wrap": "wrap" }}> + <button onClick={toggleDock} style={btn(dockOpen())}> + {dockOpen() ? "Animate close" : "Animate open"} + </button> + <button onClick={toggleDrawer} style={btn(dockOpen() && collapsed())}> + {dockOpen() && collapsed() ? "Expand todo dock" : "Collapse todo dock"} + </button> + <button onClick={cycle} style={btn(step() > 0)}> + Cycle progress ({step()}/3 done) + </button> + {[0, 1, 2, 3].map((value) => ( + <button onClick={() => setStep(value)} style={btn(step() === value)}> + {value} done + </button> + ))} + </div> + + <div style={{ display: "grid", gap: "10px", "max-width": "560px" }}> + <div style={{ "font-size": "12px", color: "var(--color-text-secondary, #a3a3a3)" }}>Dock open</div> + <label style={{ display: "flex", "align-items": "center", gap: "12px" }}> + <span style={{ width: "110px", "font-size": "13px", color: "var(--color-text-secondary, #a3a3a3)" }}> + duration + </span> + <input + type="range" + min="0.1" + max="1" + step="0.01" + value={dockOpenDuration()} + onInput={(event) => setDockOpenDuration(event.currentTarget.valueAsNumber)} + style={{ flex: 1 }} + /> + <span style={{ width: "64px", "text-align": "right", "font-size": "13px" }}> + {Math.round(dockOpenDuration() * 1000)}ms + </span> + </label> + <label style={{ display: "flex", "align-items": "center", gap: "12px" }}> + <span style={{ width: "110px", "font-size": "13px", color: "var(--color-text-secondary, #a3a3a3)" }}> + bounce + </span> + <input + type="range" + min="0" + max="1" + step="0.01" + value={dockOpenBounce()} + onInput={(event) => setDockOpenBounce(event.currentTarget.valueAsNumber)} + style={{ flex: 1 }} + /> + <span style={{ width: "64px", "text-align": "right", "font-size": "13px" }}> + {dockOpenBounce().toFixed(2)} + </span> + </label> + + <div style={{ "font-size": "12px", color: "var(--color-text-secondary, #a3a3a3)", "margin-top": "4px" }}> + Dock close + </div> + <label style={{ display: "flex", "align-items": "center", gap: "12px" }}> + <span style={{ width: "110px", "font-size": "13px", color: "var(--color-text-secondary, #a3a3a3)" }}> + duration + </span> + <input + type="range" + min="0.1" + max="1" + step="0.01" + value={dockCloseDuration()} + onInput={(event) => setDockCloseDuration(event.currentTarget.valueAsNumber)} + style={{ flex: 1 }} + /> + <span style={{ width: "64px", "text-align": "right", "font-size": "13px" }}> + {Math.round(dockCloseDuration() * 1000)}ms + </span> + </label> + <label style={{ display: "flex", "align-items": "center", gap: "12px" }}> + <span style={{ width: "110px", "font-size": "13px", color: "var(--color-text-secondary, #a3a3a3)" }}> + bounce + </span> + <input + type="range" + min="0" + max="1" + step="0.01" + value={dockCloseBounce()} + onInput={(event) => setDockCloseBounce(event.currentTarget.valueAsNumber)} + style={{ flex: 1 }} + /> + <span style={{ width: "64px", "text-align": "right", "font-size": "13px" }}> + {dockCloseBounce().toFixed(2)} + </span> + </label> + + <div style={{ "font-size": "12px", color: "var(--color-text-secondary, #a3a3a3)", "margin-top": "4px" }}> + Drawer expand + </div> + <label style={{ display: "flex", "align-items": "center", gap: "12px" }}> + <span style={{ width: "110px", "font-size": "13px", color: "var(--color-text-secondary, #a3a3a3)" }}> + duration + </span> + <input + type="range" + min="0.1" + max="1" + step="0.01" + value={drawerExpandDuration()} + onInput={(event) => setDrawerExpandDuration(event.currentTarget.valueAsNumber)} + style={{ flex: 1 }} + /> + <span style={{ width: "64px", "text-align": "right", "font-size": "13px" }}> + {Math.round(drawerExpandDuration() * 1000)}ms + </span> + </label> + <label style={{ display: "flex", "align-items": "center", gap: "12px" }}> + <span style={{ width: "110px", "font-size": "13px", color: "var(--color-text-secondary, #a3a3a3)" }}> + bounce + </span> + <input + type="range" + min="0" + max="1" + step="0.01" + value={drawerExpandBounce()} + onInput={(event) => setDrawerExpandBounce(event.currentTarget.valueAsNumber)} + style={{ flex: 1 }} + /> + <span style={{ width: "64px", "text-align": "right", "font-size": "13px" }}> + {drawerExpandBounce().toFixed(2)} + </span> + </label> + + <div style={{ "font-size": "12px", color: "var(--color-text-secondary, #a3a3a3)", "margin-top": "4px" }}> + Drawer collapse + </div> + <label style={{ display: "flex", "align-items": "center", gap: "12px" }}> + <span style={{ width: "110px", "font-size": "13px", color: "var(--color-text-secondary, #a3a3a3)" }}> + duration + </span> + <input + type="range" + min="0.1" + max="1" + step="0.01" + value={drawerCollapseDuration()} + onInput={(event) => setDrawerCollapseDuration(event.currentTarget.valueAsNumber)} + style={{ flex: 1 }} + /> + <span style={{ width: "64px", "text-align": "right", "font-size": "13px" }}> + {Math.round(drawerCollapseDuration() * 1000)}ms + </span> + </label> + <label style={{ display: "flex", "align-items": "center", gap: "12px" }}> + <span style={{ width: "110px", "font-size": "13px", color: "var(--color-text-secondary, #a3a3a3)" }}> + bounce + </span> + <input + type="range" + min="0" + max="1" + step="0.01" + value={drawerCollapseBounce()} + onInput={(event) => setDrawerCollapseBounce(event.currentTarget.valueAsNumber)} + style={{ flex: 1 }} + /> + <span style={{ width: "64px", "text-align": "right", "font-size": "13px" }}> + {drawerCollapseBounce().toFixed(2)} + </span> + </label> + + <div style={{ "font-size": "12px", color: "var(--color-text-secondary, #a3a3a3)", "margin-top": "4px" }}> + Subtitle odometer + </div> + <label style={{ display: "flex", "align-items": "center", gap: "12px" }}> + <span style={{ width: "110px", "font-size": "13px", color: "var(--color-text-secondary, #a3a3a3)" }}> + duration + </span> + <input + type="range" + min="120" + max="1400" + step="10" + value={subtitleDuration()} + onInput={(event) => setSubtitleDuration(event.currentTarget.valueAsNumber)} + style={{ flex: 1 }} + /> + <span style={{ width: "64px", "text-align": "right", "font-size": "13px" }}> + {Math.round(subtitleDuration())}ms + </span> + </label> + <label style={{ display: "flex", "align-items": "center", gap: "12px" }}> + <span style={{ width: "110px", "font-size": "13px", color: "var(--color-text-secondary, #a3a3a3)" }}> + auto fit + </span> + <input + type="checkbox" + checked={subtitleAuto()} + onInput={(event) => setSubtitleAuto(event.currentTarget.checked)} + /> + <span style={{ width: "64px", "text-align": "right", "font-size": "13px" }}> + {subtitleAuto() ? "on" : "off"} + </span> + </label> + <label style={{ display: "flex", "align-items": "center", gap: "12px" }}> + <span style={{ width: "110px", "font-size": "13px", color: "var(--color-text-secondary, #a3a3a3)" }}> + travel + </span> + <input + type="range" + min="0" + max="40" + step="1" + value={subtitleTravel()} + onInput={(event) => setSubtitleTravel(event.currentTarget.valueAsNumber)} + style={{ flex: 1 }} + /> + <span style={{ width: "64px", "text-align": "right", "font-size": "13px" }}>{subtitleTravel()}px</span> + </label> + <label style={{ display: "flex", "align-items": "center", gap: "12px" }}> + <span style={{ width: "110px", "font-size": "13px", color: "var(--color-text-secondary, #a3a3a3)" }}> + edge + </span> + <input + type="range" + min="1" + max="40" + step="1" + value={subtitleEdge()} + onInput={(event) => setSubtitleEdge(event.currentTarget.valueAsNumber)} + style={{ flex: 1 }} + /> + <span style={{ width: "64px", "text-align": "right", "font-size": "13px" }}>{subtitleEdge()}%</span> + </label> + + <div style={{ "font-size": "12px", color: "var(--color-text-secondary, #a3a3a3)", "margin-top": "4px" }}> + Count odometer + </div> + <label style={{ display: "flex", "align-items": "center", gap: "12px" }}> + <span style={{ width: "110px", "font-size": "13px", color: "var(--color-text-secondary, #a3a3a3)" }}> + duration + </span> + <input + type="range" + min="120" + max="1400" + step="10" + value={countDuration()} + onInput={(event) => setCountDuration(event.currentTarget.valueAsNumber)} + style={{ flex: 1 }} + /> + <span style={{ width: "64px", "text-align": "right", "font-size": "13px" }}> + {Math.round(countDuration())}ms + </span> + </label> + <label style={{ display: "flex", "align-items": "center", gap: "12px" }}> + <span style={{ width: "110px", "font-size": "13px", color: "var(--color-text-secondary, #a3a3a3)" }}> + mask + </span> + <input + type="range" + min="4" + max="40" + step="1" + value={countMask()} + onInput={(event) => setCountMask(event.currentTarget.valueAsNumber)} + style={{ flex: 1 }} + /> + <span style={{ width: "64px", "text-align": "right", "font-size": "13px" }}>{countMask()}%</span> + </label> + <label style={{ display: "flex", "align-items": "center", gap: "12px" }}> + <span style={{ width: "110px", "font-size": "13px", color: "var(--color-text-secondary, #a3a3a3)" }}> + mask height + </span> + <input + type="range" + min="0" + max="14" + step="1" + value={countMaskHeight()} + onInput={(event) => setCountMaskHeight(event.currentTarget.valueAsNumber)} + style={{ flex: 1 }} + /> + <span style={{ width: "64px", "text-align": "right", "font-size": "13px" }}>{countMaskHeight()}px</span> + </label> + <label style={{ display: "flex", "align-items": "center", gap: "12px" }}> + <span style={{ width: "110px", "font-size": "13px", color: "var(--color-text-secondary, #a3a3a3)" }}> + width spring + </span> + <input + type="range" + min="0" + max="1200" + step="10" + value={countWidthDuration()} + onInput={(event) => setCountWidthDuration(event.currentTarget.valueAsNumber)} + style={{ flex: 1 }} + /> + <span style={{ width: "64px", "text-align": "right", "font-size": "13px" }}> + {Math.round(countWidthDuration())}ms + </span> + </label> + </div> + </div> + ) + }, +} diff --git a/packages/ui/src/components/tool-count-label.css b/packages/ui/src/components/tool-count-label.css new file mode 100644 index 0000000000..11a33ff5d1 --- /dev/null +++ b/packages/ui/src/components/tool-count-label.css @@ -0,0 +1,57 @@ +[data-component="tool-count-label"] { + display: inline-flex; + align-items: baseline; + white-space: nowrap; + gap: 0; + + [data-slot="tool-count-label-before"] { + display: inline-block; + white-space: pre; + line-height: inherit; + } + + [data-slot="tool-count-label-word"] { + display: inline-flex; + align-items: baseline; + white-space: pre; + line-height: inherit; + } + + [data-slot="tool-count-label-stem"] { + display: inline-block; + white-space: pre; + } + + [data-slot="tool-count-label-suffix"] { + display: inline-grid; + grid-template-columns: 0fr; + opacity: 0; + filter: blur(calc(var(--tool-motion-blur, 2px) * 0.42)); + overflow: hidden; + transform: translateX(-0.04em); + transition-property: grid-template-columns, opacity, filter, transform; + transition-duration: 250ms, 250ms, 250ms, 250ms; + transition-timing-function: + var(--tool-motion-ease, cubic-bezier(0.22, 1, 0.36, 1)), ease-out, ease-out, + var(--tool-motion-ease, cubic-bezier(0.22, 1, 0.36, 1)); + } + + [data-slot="tool-count-label-suffix"][data-active="true"] { + grid-template-columns: 1fr; + opacity: 1; + filter: blur(0); + transform: translateX(0); + } + + [data-slot="tool-count-label-suffix-inner"] { + min-width: 0; + overflow: hidden; + white-space: pre; + } +} + +@media (prefers-reduced-motion: reduce) { + [data-component="tool-count-label"] [data-slot="tool-count-label-suffix"] { + transition-duration: 0ms; + } +} diff --git a/packages/ui/src/components/tool-count-label.tsx b/packages/ui/src/components/tool-count-label.tsx new file mode 100644 index 0000000000..67e861cdcb --- /dev/null +++ b/packages/ui/src/components/tool-count-label.tsx @@ -0,0 +1,58 @@ +import { createMemo } from "solid-js" +import { AnimatedNumber } from "./animated-number" + +function split(text: string) { + const match = /{{\s*count\s*}}/.exec(text) + if (!match) return { before: "", after: text } + if (match.index === undefined) return { before: "", after: text } + return { + before: text.slice(0, match.index), + after: text.slice(match.index + match[0].length), + } +} + +function common(one: string, other: string) { + const a = Array.from(one) + const b = Array.from(other) + let i = 0 + while (i < a.length && i < b.length && a[i] === b[i]) i++ + return { + stem: a.slice(0, i).join(""), + one: a.slice(i).join(""), + other: b.slice(i).join(""), + } +} + +export function AnimatedCountLabel(props: { count: number; one: string; other: string; class?: string }) { + const one = createMemo(() => split(props.one)) + const other = createMemo(() => split(props.other)) + const singular = createMemo(() => Math.round(props.count) === 1) + const active = createMemo(() => (singular() ? one() : other())) + const suffix = createMemo(() => common(one().after, other().after)) + const splitSuffix = createMemo( + () => + one().before === other().before && + (one().after.startsWith(other().after) || other().after.startsWith(one().after)), + ) + const before = createMemo(() => (splitSuffix() ? one().before : active().before)) + const stem = createMemo(() => (splitSuffix() ? suffix().stem : active().after)) + const tail = createMemo(() => { + if (!splitSuffix()) return "" + if (singular()) return suffix().one + return suffix().other + }) + const showTail = createMemo(() => splitSuffix() && tail().length > 0) + + return ( + <span data-component="tool-count-label" class={props.class}> + <span data-slot="tool-count-label-before">{before()}</span> + <AnimatedNumber value={props.count} /> + <span data-slot="tool-count-label-word"> + <span data-slot="tool-count-label-stem">{stem()}</span> + <span data-slot="tool-count-label-suffix" data-active={showTail() ? "true" : "false"}> + <span data-slot="tool-count-label-suffix-inner">{tail()}</span> + </span> + </span> + </span> + ) +} diff --git a/packages/ui/src/components/tool-count-summary.css b/packages/ui/src/components/tool-count-summary.css new file mode 100644 index 0000000000..da8455267c --- /dev/null +++ b/packages/ui/src/components/tool-count-summary.css @@ -0,0 +1,102 @@ +[data-component="tool-count-summary"] { + display: inline-flex; + align-items: baseline; + white-space: nowrap; + + [data-slot="tool-count-summary-empty"] { + display: inline-grid; + grid-template-columns: 1fr; + align-items: baseline; + opacity: 1; + filter: blur(0); + transform: translateY(0) scale(1); + overflow: hidden; + transform-origin: left center; + transition-property: grid-template-columns, opacity, filter, transform; + transition-duration: + var(--tool-motion-spring-ms, 480ms), var(--tool-motion-fade-ms, 240ms), var(--tool-motion-fade-ms, 280ms), + var(--tool-motion-spring-ms, 480ms); + transition-timing-function: + var(--tool-motion-ease, cubic-bezier(0.22, 1, 0.36, 1)), ease-out, ease-out, + var(--tool-motion-ease, cubic-bezier(0.22, 1, 0.36, 1)); + } + + [data-slot="tool-count-summary-empty"][data-active="false"] { + grid-template-columns: 0fr; + opacity: 0; + filter: blur(calc(var(--tool-motion-blur, 2px) * 0.72)); + transform: translateY(0.05em) scale(0.985); + } + + [data-slot="tool-count-summary-item"] { + display: inline-grid; + grid-template-columns: 0fr; + align-items: baseline; + opacity: 0; + filter: blur(var(--tool-motion-blur, 2px)); + transform: translateY(0.06em) scale(0.985); + overflow: hidden; + transform-origin: left center; + transition-property: grid-template-columns, opacity, filter, transform; + transition-duration: + var(--tool-motion-spring-ms, 480ms), var(--tool-motion-fade-ms, 280ms), var(--tool-motion-fade-ms, 320ms), + var(--tool-motion-spring-ms, 480ms); + transition-timing-function: + var(--tool-motion-ease, cubic-bezier(0.22, 1, 0.36, 1)), ease-out, ease-out, + var(--tool-motion-ease, cubic-bezier(0.22, 1, 0.36, 1)); + } + + [data-slot="tool-count-summary-item"][data-active="true"] { + grid-template-columns: 1fr; + opacity: 1; + filter: blur(0); + transform: translateY(0) scale(1); + } + + [data-slot="tool-count-summary-empty-inner"] { + min-width: 0; + overflow: hidden; + white-space: nowrap; + } + + [data-slot="tool-count-summary-item-inner"] { + display: inline-flex; + align-items: baseline; + min-width: 0; + overflow: hidden; + white-space: nowrap; + } + + [data-slot="tool-count-summary-prefix"] { + display: inline-flex; + align-items: baseline; + justify-content: flex-start; + max-width: 0; + margin-right: 0; + opacity: 0; + filter: blur(calc(var(--tool-motion-blur, 2px) * 0.55)); + overflow: hidden; + transform: translateX(-0.08em); + transition-property: opacity, filter, transform; + transition-duration: + calc(var(--tool-motion-fade-ms, 200ms) * 0.75), calc(var(--tool-motion-fade-ms, 220ms) * 0.75), + calc(var(--tool-motion-fade-ms, 220ms) * 0.6); + transition-timing-function: ease-out, ease-out, ease-out; + } + + [data-slot="tool-count-summary-prefix"][data-active="true"] { + max-width: 1ch; + margin-right: 0.45ch; + opacity: 1; + filter: blur(0); + transform: translateX(0); + } +} + +@media (prefers-reduced-motion: reduce) { + [data-component="tool-count-summary"] [data-slot="tool-count-summary-empty"], + [data-component="tool-count-summary"] [data-slot="tool-count-summary-item"], + [data-component="tool-count-summary"] [data-slot="tool-count-summary-prefix"] { + transition-duration: 0ms; + } +} diff --git a/packages/ui/src/components/tool-count-summary.stories.tsx b/packages/ui/src/components/tool-count-summary.stories.tsx new file mode 100644 index 0000000000..4be3a02bbe --- /dev/null +++ b/packages/ui/src/components/tool-count-summary.stories.tsx @@ -0,0 +1,230 @@ +// @ts-nocheck +import { createSignal, onCleanup } from "solid-js" +import { AnimatedCountList, type CountItem } from "./tool-count-summary" +import { ToolStatusTitle } from "./tool-status-title" + +export default { + title: "UI/AnimatedCountList", + id: "components-animated-count-list", + tags: ["autodocs"], + parameters: { + docs: { + description: { + component: `### Overview +Animated count list that smoothly transitions items in/out as counts change. + +Uses \`grid-template-columns: 0fr → 1fr\` for width animations and the odometer +digit roller for count transitions. Shown here with \`ToolStatusTitle\` exactly +as it appears in the context tool group on the session page.`, + }, + }, + }, +} + +const TEXT = { + active: "Exploring", + done: "Explored", + read: { one: "{{count}} read", other: "{{count}} reads" }, + search: { one: "{{count}} search", other: "{{count}} searches" }, + list: { one: "{{count}} list", other: "{{count}} lists" }, +} as const + +function rand(min: number, max: number) { + return Math.floor(Math.random() * (max - min + 1)) + min +} + +const btn = (accent?: boolean) => + ({ + padding: "6px 14px", + "border-radius": "6px", + border: "1px solid var(--color-divider, #333)", + background: accent ? "var(--color-danger-fill, #c33)" : "var(--color-fill-element, #222)", + color: "var(--color-text, #eee)", + cursor: "pointer", + "font-size": "13px", + }) as const + +const smallBtn = (active?: boolean) => + ({ + padding: "4px 12px", + "border-radius": "6px", + border: active ? "1px solid var(--color-accent, #58f)" : "1px solid var(--color-divider, #333)", + background: active ? "var(--color-accent, #58f)" : "var(--color-fill-element, #222)", + color: "var(--color-text, #eee)", + cursor: "pointer", + "font-size": "12px", + }) as const + +export const Playground = { + render: () => { + const [reads, setReads] = createSignal(0) + const [searches, setSearches] = createSignal(0) + const [lists, setLists] = createSignal(0) + const [active, setActive] = createSignal(false) + const [reducedMotion, setReducedMotion] = createSignal(false) + + let timeouts: ReturnType<typeof setTimeout>[] = [] + + const clearAll = () => { + for (const t of timeouts) clearTimeout(t) + timeouts = [] + } + + onCleanup(clearAll) + + const startSim = () => { + clearAll() + setReads(0) + setSearches(0) + setLists(0) + setActive(true) + const steps = rand(3, 10) + let elapsed = 0 + + for (let i = 0; i < steps; i++) { + const delay = rand(300, 800) + elapsed += delay + const t = setTimeout(() => { + const pick = rand(0, 2) + if (pick === 0) setReads((n) => n + 1) + else if (pick === 1) setSearches((n) => n + 1) + else setLists((n) => n + 1) + }, elapsed) + timeouts.push(t) + } + + const end = setTimeout(() => setActive(false), elapsed + 100) + timeouts.push(end) + } + + const stopSim = () => { + clearAll() + setActive(false) + } + + const reset = () => { + stopSim() + setReads(0) + setSearches(0) + setLists(0) + } + + const items = (): CountItem[] => [ + { key: "read", count: reads(), one: TEXT.read.one, other: TEXT.read.other }, + { key: "search", count: searches(), one: TEXT.search.one, other: TEXT.search.other }, + { key: "list", count: lists(), one: TEXT.list.one, other: TEXT.list.other }, + ] + + return ( + <div style={{ display: "grid", gap: "24px", padding: "20px", "max-width": "520px" }}> + {reducedMotion() && ( + <style> + {`[data-reduced-motion="true"] *, + [data-reduced-motion="true"] *::before, + [data-reduced-motion="true"] *::after { + transition-duration: 0ms !important; + }`} + </style> + )} + + {/* Matches context-tool-group-trigger layout from message-part.tsx */} + <span + data-reduced-motion={reducedMotion()} + style={{ + display: "flex", + "align-items": "center", + gap: "8px", + "font-size": "14px", + "font-weight": "500", + color: "var(--text-strong, #eee)", + "min-width": "0", + }} + > + <span style={{ "flex-shrink": "0" }}> + <ToolStatusTitle active={active()} activeText={TEXT.active} doneText={TEXT.done} split={false} /> + </span> + <span + style={{ + "min-width": "0", + overflow: "hidden", + "text-overflow": "ellipsis", + "white-space": "nowrap", + "font-weight": "400", + color: "var(--text-base, #ccc)", + }} + > + <AnimatedCountList items={items()} fallback="" /> + </span> + </span> + + <div style={{ display: "flex", gap: "8px", "flex-wrap": "wrap" }}> + <button onClick={() => (active() ? stopSim() : startSim())} style={btn(active())}> + {active() ? "Stop" : "Simulate"} + </button> + <button onClick={reset} style={btn()}> + Reset + </button> + <button onClick={() => setReducedMotion((v) => !v)} style={smallBtn(reducedMotion())}> + {reducedMotion() ? "Motion: reduced" : "Motion: normal"} + </button> + </div> + + <div style={{ display: "flex", gap: "8px", "flex-wrap": "wrap" }}> + <button onClick={() => setReads((n) => n + 1)} style={smallBtn()}> + + read + </button> + <button onClick={() => setSearches((n) => n + 1)} style={smallBtn()}> + + search + </button> + <button onClick={() => setLists((n) => n + 1)} style={smallBtn()}> + + list + </button> + </div> + + <div + style={{ + "font-size": "11px", + color: "var(--color-text-weak, #888)", + "font-family": "monospace", + }} + > + motion: {reducedMotion() ? "reduced" : "normal"} · active: {active() ? "true" : "false"} · reads: {reads()} · + searches: {searches()} · lists: {lists()} + </div> + </div> + ) + }, +} + +export const Empty = { + render: () => ( + <span style={{ display: "flex", "align-items": "center", gap: "8px", "font-size": "14px", "font-weight": "500" }}> + <ToolStatusTitle active activeText="Exploring" doneText="Explored" split={false} /> + <AnimatedCountList + items={[ + { key: "read", count: 0, one: "{{count}} read", other: "{{count}} reads" }, + { key: "search", count: 0, one: "{{count}} search", other: "{{count}} searches" }, + ]} + fallback="" + /> + </span> + ), +} + +export const Done = { + render: () => ( + <span style={{ display: "flex", "align-items": "center", gap: "8px", "font-size": "14px", "font-weight": "500" }}> + <ToolStatusTitle active={false} activeText="Exploring" doneText="Explored" split={false} /> + <span style={{ "font-weight": "400", color: "var(--text-base, #ccc)" }}> + <AnimatedCountList + items={[ + { key: "read", count: 5, one: "{{count}} read", other: "{{count}} reads" }, + { key: "search", count: 3, one: "{{count}} search", other: "{{count}} searches" }, + { key: "list", count: 1, one: "{{count}} list", other: "{{count}} lists" }, + ]} + fallback="" + /> + </span> + </span> + ), +} diff --git a/packages/ui/src/components/tool-count-summary.tsx b/packages/ui/src/components/tool-count-summary.tsx new file mode 100644 index 0000000000..a5cb5b40d2 --- /dev/null +++ b/packages/ui/src/components/tool-count-summary.tsx @@ -0,0 +1,52 @@ +import { Index, createMemo } from "solid-js" +import { AnimatedCountLabel } from "./tool-count-label" + +export type CountItem = { + key: string + count: number + one: string + other: string +} + +export function AnimatedCountList(props: { items: CountItem[]; fallback?: string; class?: string }) { + const visible = createMemo(() => props.items.filter((item) => item.count > 0)) + const fallback = createMemo(() => props.fallback ?? "") + const showEmpty = createMemo(() => visible().length === 0 && fallback().length > 0) + + return ( + <span data-component="tool-count-summary" class={props.class}> + <span data-slot="tool-count-summary-empty" data-active={showEmpty() ? "true" : "false"}> + <span data-slot="tool-count-summary-empty-inner">{fallback()}</span> + </span> + + <Index each={props.items}> + {(item, index) => { + const active = createMemo(() => item().count > 0) + const hasPrev = createMemo(() => { + for (let i = index - 1; i >= 0; i--) { + if (props.items[i].count > 0) return true + } + return false + }) + + return ( + <> + <span data-slot="tool-count-summary-prefix" data-active={active() && hasPrev() ? "true" : "false"}> + , + </span> + <span data-slot="tool-count-summary-item" data-active={active() ? "true" : "false"}> + <span data-slot="tool-count-summary-item-inner"> + <AnimatedCountLabel + one={item().one} + other={item().other} + count={Math.max(0, Math.round(item().count))} + /> + </span> + </span> + </> + ) + }} + </Index> + </span> + ) +} diff --git a/packages/ui/src/components/tool-status-title.css b/packages/ui/src/components/tool-status-title.css new file mode 100644 index 0000000000..d4415bd2da --- /dev/null +++ b/packages/ui/src/components/tool-status-title.css @@ -0,0 +1,89 @@ +[data-component="tool-status-title"] { + display: inline-flex; + align-items: baseline; + white-space: nowrap; + text-align: start; + + [data-slot="tool-status-suffix"] { + display: inline-flex; + align-items: baseline; + white-space: nowrap; + } + + [data-slot="tool-status-prefix"] { + white-space: nowrap; + flex-shrink: 0; + } + + [data-slot="tool-status-swap"], + [data-slot="tool-status-tail"] { + display: inline-grid; + overflow: hidden; + justify-items: start; + transition: width var(--tool-motion-spring-ms, 480ms) var(--tool-motion-ease, cubic-bezier(0.22, 1, 0.36, 1)); + } + + [data-slot="tool-status-active"], + [data-slot="tool-status-done"] { + grid-area: 1 / 1; + white-space: nowrap; + justify-self: start; + text-align: start; + transition-property: opacity, filter, transform; + transition-duration: + var(--tool-motion-fade-ms, 240ms), calc(var(--tool-motion-fade-ms, 240ms) * 0.8), + calc(var(--tool-motion-fade-ms, 240ms) * 0.8); + transition-timing-function: ease-out, ease-out, ease-out; + } + + &[data-ready="false"] { + [data-slot="tool-status-swap"], + [data-slot="tool-status-tail"] { + transition-duration: 0ms; + } + + [data-slot="tool-status-active"], + [data-slot="tool-status-done"] { + transition-duration: 0ms; + } + } + + [data-slot="tool-status-active"] { + opacity: 0; + filter: blur(calc(var(--tool-motion-blur, 2px) * 0.45)); + transform: translateY(0.03em); + } + + [data-slot="tool-status-done"] { + color: var(--text-strong); + opacity: 1; + filter: blur(0); + transform: translateY(0); + } + + &[data-active="true"] { + [data-slot="tool-status-active"] { + opacity: 1; + filter: blur(0); + transform: translateY(0); + } + + [data-slot="tool-status-done"] { + opacity: 0; + filter: blur(calc(var(--tool-motion-blur, 2px) * 0.45)); + transform: translateY(0.03em); + } + } +} + +@media (prefers-reduced-motion: reduce) { + [data-component="tool-status-title"] [data-slot="tool-status-swap"], + [data-component="tool-status-title"] [data-slot="tool-status-tail"] { + transition-duration: 0ms; + } + + [data-component="tool-status-title"] [data-slot="tool-status-active"], + [data-component="tool-status-title"] [data-slot="tool-status-done"] { + transition-duration: 0ms; + } +} diff --git a/packages/ui/src/components/tool-status-title.tsx b/packages/ui/src/components/tool-status-title.tsx new file mode 100644 index 0000000000..68440b6c63 --- /dev/null +++ b/packages/ui/src/components/tool-status-title.tsx @@ -0,0 +1,133 @@ +import { Show, createEffect, createMemo, createSignal, on, onCleanup, onMount } from "solid-js" +import { TextShimmer } from "./text-shimmer" + +function common(active: string, done: string) { + const a = Array.from(active) + const b = Array.from(done) + let i = 0 + while (i < a.length && i < b.length && a[i] === b[i]) i++ + return { + prefix: a.slice(0, i).join(""), + active: a.slice(i).join(""), + done: b.slice(i).join(""), + } +} + +function contentWidth(el: HTMLSpanElement | undefined) { + if (!el) return 0 + const range = document.createRange() + range.selectNodeContents(el) + return Math.ceil(range.getBoundingClientRect().width) +} + +export function ToolStatusTitle(props: { + active: boolean + activeText: string + doneText: string + class?: string + split?: boolean +}) { + const split = createMemo(() => common(props.activeText, props.doneText)) + const suffix = createMemo( + () => (props.split ?? true) && split().prefix.length >= 2 && split().active.length > 0 && split().done.length > 0, + ) + const prefixLen = createMemo(() => Array.from(split().prefix).length) + const activeTail = createMemo(() => (suffix() ? split().active : props.activeText)) + const doneTail = createMemo(() => (suffix() ? split().done : props.doneText)) + + const [width, setWidth] = createSignal("auto") + const [ready, setReady] = createSignal(false) + let activeRef: HTMLSpanElement | undefined + let doneRef: HTMLSpanElement | undefined + let frame: number | undefined + let readyFrame: number | undefined + + const measure = () => { + const target = props.active ? activeRef : doneRef + const px = contentWidth(target) + if (px > 0) setWidth(`${px}px`) + } + + const schedule = () => { + if (typeof requestAnimationFrame !== "function") { + measure() + return + } + if (frame !== undefined) cancelAnimationFrame(frame) + frame = requestAnimationFrame(() => { + frame = undefined + measure() + }) + } + + const finish = () => { + if (typeof requestAnimationFrame !== "function") { + setReady(true) + return + } + if (readyFrame !== undefined) cancelAnimationFrame(readyFrame) + readyFrame = requestAnimationFrame(() => { + readyFrame = undefined + setReady(true) + }) + } + + createEffect(on([() => props.active, activeTail, doneTail, suffix], () => schedule())) + + onMount(() => { + measure() + const fonts = typeof document !== "undefined" ? document.fonts : undefined + if (!fonts) { + finish() + return + } + fonts.ready.finally(() => { + measure() + finish() + }) + }) + + onCleanup(() => { + if (frame !== undefined) cancelAnimationFrame(frame) + if (readyFrame !== undefined) cancelAnimationFrame(readyFrame) + }) + + return ( + <span + data-component="tool-status-title" + data-active={props.active ? "true" : "false"} + data-ready={ready() ? "true" : "false"} + data-mode={suffix() ? "suffix" : "swap"} + class={props.class} + aria-label={props.active ? props.activeText : props.doneText} + > + <Show + when={suffix()} + fallback={ + <span data-slot="tool-status-swap" style={{ width: width() }}> + <span data-slot="tool-status-active" ref={activeRef}> + <TextShimmer text={activeTail()} active={props.active} offset={0} /> + </span> + <span data-slot="tool-status-done" ref={doneRef}> + <TextShimmer text={doneTail()} active={false} offset={0} /> + </span> + </span> + } + > + <span data-slot="tool-status-suffix"> + <span data-slot="tool-status-prefix"> + <TextShimmer text={split().prefix} active={props.active} offset={0} /> + </span> + <span data-slot="tool-status-tail" style={{ width: width() }}> + <span data-slot="tool-status-active" ref={activeRef}> + <TextShimmer text={activeTail()} active={props.active} offset={prefixLen()} /> + </span> + <span data-slot="tool-status-done" ref={doneRef}> + <TextShimmer text={doneTail()} active={false} offset={prefixLen()} /> + </span> + </span> + </span> + </Show> + </span> + ) +} diff --git a/packages/ui/src/components/tooltip.stories.tsx b/packages/ui/src/components/tooltip.stories.tsx new file mode 100644 index 0000000000..efe11d92ef --- /dev/null +++ b/packages/ui/src/components/tooltip.stories.tsx @@ -0,0 +1,64 @@ +// @ts-nocheck +import * as mod from "./tooltip" +import { create } from "../storybook/scaffold" + +const docs = `### Overview +Tooltip for contextual hints and keybind callouts. + +Use for short hints; avoid long descriptions. + +### API +- Required: \`value\` (tooltip content). +- Optional: \`inactive\`, \`forceOpen\`, placement props from Kobalte. + +### Variants and states +- Supports keybind-style tooltip via \`TooltipKeybind\`. + +### Behavior +- Opens on hover/focus; can be forced open. + +### Accessibility +- TODO: confirm trigger semantics and focus behavior. + +### Theming/tokens +- Uses \`data-component="tooltip"\` and related slots. + +` + +const story = create({ title: "UI/Tooltip", mod, args: { value: "Tooltip", children: "Hover me" } }) + +export default { + title: "UI/Tooltip", + id: "components-tooltip", + component: story.meta.component, + tags: ["autodocs"], + parameters: { + docs: { + description: { + component: docs, + }, + }, + }, +} + +export const Basic = story.Basic + +export const Keybind = { + render: () => ( + <mod.TooltipKeybind title="Search" keybind="Cmd+K"> + <span style={{ "text-decoration": "underline" }}>Hover for keybind</span> + </mod.TooltipKeybind> + ), +} + +export const ForcedOpen = { + args: { + forceOpen: true, + }, +} + +export const Inactive = { + args: { + inactive: true, + }, +} diff --git a/packages/ui/src/components/tooltip.tsx b/packages/ui/src/components/tooltip.tsx index 055e504654..63105d00fc 100644 --- a/packages/ui/src/components/tooltip.tsx +++ b/packages/ui/src/components/tooltip.tsx @@ -47,7 +47,7 @@ export function Tooltip(props: TooltipProps) { <Switch> <Match when={local.inactive}>{local.children}</Match> <Match when={true}> - <KobalteTooltip gutter={4} {...others} open={local.forceOpen || open()} onOpenChange={setOpen}> + <KobalteTooltip gutter={4} {...others} closeDelay={0} open={local.forceOpen || open()} onOpenChange={setOpen}> <KobalteTooltip.Trigger as={"div"} data-component="tooltip-trigger" class={local.class}> {local.children} </KobalteTooltip.Trigger> diff --git a/packages/ui/src/components/typewriter.stories.tsx b/packages/ui/src/components/typewriter.stories.tsx new file mode 100644 index 0000000000..880ca74894 --- /dev/null +++ b/packages/ui/src/components/typewriter.stories.tsx @@ -0,0 +1,51 @@ +// @ts-nocheck +import * as mod from "./typewriter" +import { create } from "../storybook/scaffold" + +const docs = `### Overview +Animated typewriter text effect for short inline messages. + +Use for short status lines; avoid long paragraphs. + +### API +- Optional: \`text\` string; if absent, nothing is rendered. +- Optional: \`as\` to change the rendered element. + +### Variants and states +- Single animation style with cursor blink. + +### Behavior +- Types one character at a time with randomized delays. + +### Accessibility +- TODO: confirm if cursor should be aria-hidden in all contexts. + +### Theming/tokens +- Uses \`blinking-cursor\` class for cursor styling. + +` + +const story = create({ title: "UI/Typewriter", mod, args: { text: "Typewriter text" } }) + +export default { + title: "UI/Typewriter", + id: "components-typewriter", + component: story.meta.component, + tags: ["autodocs"], + parameters: { + docs: { + description: { + component: docs, + }, + }, + }, +} + +export const Basic = story.Basic + +export const Inline = { + args: { + text: "Inline typewriter", + as: "span", + }, +} diff --git a/packages/ui/src/context/data.tsx b/packages/ui/src/context/data.tsx index 2c44763f53..e116199eb2 100644 --- a/packages/ui/src/context/data.tsx +++ b/packages/ui/src/context/data.tsx @@ -1,14 +1,4 @@ -import type { - Message, - Session, - Part, - FileDiff, - SessionStatus, - PermissionRequest, - QuestionRequest, - QuestionAnswer, - ProviderListResponse, -} from "@opencode-ai/sdk/v2" +import type { Message, Session, Part, FileDiff, SessionStatus, ProviderListResponse } from "@opencode-ai/sdk/v2" import { createSimpleContext } from "./helper" import { PreloadMultiFileDiffResult } from "@pierre/diffs/ssr" @@ -24,12 +14,6 @@ type Data = { session_diff_preload?: { [sessionID: string]: PreloadMultiFileDiffResult<any>[] } - permission?: { - [sessionID: string]: PermissionRequest[] - } - question?: { - [sessionID: string]: QuestionRequest[] - } message: { [sessionID: string]: Message[] } @@ -38,16 +22,6 @@ type Data = { } } -export type PermissionRespondFn = (input: { - sessionID: string - permissionID: string - response: "once" | "always" | "reject" -}) => void - -export type QuestionReplyFn = (input: { requestID: string; answers: QuestionAnswer[] }) => void - -export type QuestionRejectFn = (input: { requestID: string }) => void - export type NavigateToSessionFn = (sessionID: string) => void export type SessionHrefFn = (sessionID: string) => string @@ -57,9 +31,6 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({ init: (props: { data: Data directory: string - onPermissionRespond?: PermissionRespondFn - onQuestionReply?: QuestionReplyFn - onQuestionReject?: QuestionRejectFn onNavigateToSession?: NavigateToSessionFn onSessionHref?: SessionHrefFn }) => { @@ -70,9 +41,6 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({ get directory() { return props.directory }, - respondToPermission: props.onPermissionRespond, - replyToQuestion: props.onQuestionReply, - rejectQuestion: props.onQuestionReject, navigateToSession: props.onNavigateToSession, sessionHref: props.onSessionHref, } diff --git a/packages/ui/src/context/diff.tsx b/packages/ui/src/context/diff.tsx deleted file mode 100644 index 747de9cc8d..0000000000 --- a/packages/ui/src/context/diff.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import type { ValidComponent } from "solid-js" -import { createSimpleContext } from "./helper" - -const ctx = createSimpleContext<ValidComponent, { component: ValidComponent }>({ - name: "DiffComponent", - init: (props) => props.component, -}) - -export const DiffComponentProvider = ctx.provider -export const useDiffComponent = ctx.use diff --git a/packages/ui/src/context/code.tsx b/packages/ui/src/context/file.tsx similarity index 65% rename from packages/ui/src/context/code.tsx rename to packages/ui/src/context/file.tsx index 3a25115273..f94368cb18 100644 --- a/packages/ui/src/context/code.tsx +++ b/packages/ui/src/context/file.tsx @@ -2,9 +2,9 @@ import type { ValidComponent } from "solid-js" import { createSimpleContext } from "./helper" const ctx = createSimpleContext<ValidComponent, { component: ValidComponent }>({ - name: "CodeComponent", + name: "FileComponent", init: (props) => props.component, }) -export const CodeComponentProvider = ctx.provider -export const useCodeComponent = ctx.use +export const FileComponentProvider = ctx.provider +export const useFileComponent = ctx.use diff --git a/packages/ui/src/context/index.ts b/packages/ui/src/context/index.ts index 5615dd0ec0..2db004985f 100644 --- a/packages/ui/src/context/index.ts +++ b/packages/ui/src/context/index.ts @@ -1,5 +1,5 @@ export * from "./helper" export * from "./data" -export * from "./diff" +export * from "./file" export * from "./dialog" export * from "./i18n" diff --git a/packages/ui/src/hooks/create-auto-scroll.tsx b/packages/ui/src/hooks/create-auto-scroll.tsx index c32017739c..3dc520c621 100644 --- a/packages/ui/src/hooks/create-auto-scroll.tsx +++ b/packages/ui/src/hooks/create-auto-scroll.tsx @@ -48,14 +48,14 @@ export function createAutoScroll(options: AutoScrollOptions) { autoTimer = setTimeout(() => { auto = undefined autoTimer = undefined - }, 250) + }, 1500) } const isAuto = (el: HTMLElement) => { const a = auto if (!a) return false - if (Date.now() - a.time > 250) { + if (Date.now() - a.time > 1500) { auto = undefined return false } @@ -78,14 +78,19 @@ export function createAutoScroll(options: AutoScrollOptions) { const scrollToBottom = (force: boolean) => { if (!force && !active()) return + + if (force && store.userScrolled) setStore("userScrolled", false) + const el = scroll if (!el) return if (!force && store.userScrolled) return - if (force && store.userScrolled) setStore("userScrolled", false) const distance = distanceFromBottom(el) - if (distance < 2) return + if (distance < 2) { + markAuto(el) + return + } // For auto-following content we prefer immediate updates to avoid // visible "catch up" animations while content is still settling. @@ -142,7 +147,10 @@ export function createAutoScroll(options: AutoScrollOptions) { const handleInteraction = () => { if (!active()) return - stop() + const selection = window.getSelection() + if (selection && selection.toString().length > 0) { + stop() + } } const updateOverflowAnchor = (el: HTMLElement) => { diff --git a/packages/ui/src/i18n/ar.ts b/packages/ui/src/i18n/ar.ts index 4d79f3d001..d75918aa7c 100644 --- a/packages/ui/src/i18n/ar.ts +++ b/packages/ui/src/i18n/ar.ts @@ -3,6 +3,9 @@ export const dict = { "ui.sessionReview.title.lastTurn": "تغييرات آخر دور", "ui.sessionReview.diffStyle.unified": "موحد", "ui.sessionReview.diffStyle.split": "منقسم", + "ui.sessionReview.openFile": "فتح ملف", + "ui.sessionReview.selection.line": "سطر {{line}}", + "ui.sessionReview.selection.lines": "الأسطر {{start}}-{{end}}", "ui.sessionReview.expandAll": "توسيع الكل", "ui.sessionReview.collapseAll": "طي الكل", "ui.sessionReview.change.added": "مضاف", @@ -13,6 +16,15 @@ export const dict = { "ui.sessionReview.largeDiff.title": "Diff كبير جدا لعرضه", "ui.sessionReview.largeDiff.meta": "الحد: {{limit}} سطرًا متغيرًا. الحالي: {{current}} سطرًا متغيرًا.", "ui.sessionReview.largeDiff.renderAnyway": "اعرض على أي حال", + "ui.fileMedia.kind.image": "صورة", + "ui.fileMedia.kind.audio": "صوت", + "ui.fileMedia.state.removed": "تمت إزالة {{kind}}", + "ui.fileMedia.state.loading": "جاري تحميل {{kind}}...", + "ui.fileMedia.state.error": "خطأ في تحميل {{kind}}", + "ui.fileMedia.state.unavailable": "{{kind}} غير متوفر", + "ui.fileMedia.binary.title": "ملف ثنائي", + "ui.fileMedia.binary.description.path": "{{path}} عبارة عن ملف ثنائي ولا يمكن عرضه.", + "ui.fileMedia.binary.description.default": "هذا ملف ثنائي ولا يمكن عرضه.", "ui.lineComment.label.prefix": "تعليق على ", "ui.lineComment.label.suffix": "", @@ -28,6 +40,9 @@ export const dict = { "ui.sessionTurn.retry.retrying": "إعادة المحاولة", "ui.sessionTurn.retry.inSeconds": "خلال {{seconds}} ثواني", + "ui.sessionTurn.retry.attempt": "المحاولة رقم {{attempt}}", + "ui.sessionTurn.retry.attemptLine": "{{line}} - المحاولة رقم {{attempt}}", + "ui.sessionTurn.retry.geminiHot": "gemini مزدحم حاليا", "ui.sessionTurn.error.freeUsageExceeded": "تم تجاوز حد الاستخدام المجاني", "ui.sessionTurn.error.addCredits": "إضافة رصيد", @@ -44,6 +59,14 @@ export const dict = { "ui.sessionTurn.status.gatheringThoughts": "جمع الأفكار", "ui.sessionTurn.status.consideringNextSteps": "النظر في الخطوات التالية", + "ui.messagePart.questions.dismissed": "تم رفض الأسئلة", + "ui.messagePart.compaction": "تم ضغط السجل", + "ui.messagePart.context.read.one": "{{count}} قراءة", + "ui.messagePart.context.read.other": "{{count}} قراءات", + "ui.messagePart.context.search.one": "{{count}} بحث", + "ui.messagePart.context.search.other": "{{count}} عمليات بحث", + "ui.messagePart.context.list.one": "{{count}} قائمة", + "ui.messagePart.context.list.other": "{{count}} قوائم", "ui.messagePart.diagnostic.error": "خطأ", "ui.messagePart.title.edit": "تحرير", "ui.messagePart.title.write": "كتابة", @@ -63,6 +86,7 @@ export const dict = { "ui.textField.copied": "تم النسخ", "ui.imagePreview.alt": "معاينة الصورة", + "ui.scrollView.ariaLabel": "محتوى قابل للتمرير", "ui.tool.read": "قراءة", "ui.tool.loaded": "تم التحميل", @@ -70,12 +94,15 @@ export const dict = { "ui.tool.glob": "Glob", "ui.tool.grep": "Grep", "ui.tool.webfetch": "جلب الويب", + "ui.tool.websearch": "بحث الويب", + "ui.tool.codesearch": "بحث الكود", "ui.tool.shell": "Shell", "ui.tool.patch": "تصحيح", "ui.tool.todos": "المهام", "ui.tool.todos.read": "قراءة المهام", "ui.tool.questions": "أسئلة", "ui.tool.agent": "وكيل {{type}}", + "ui.tool.agent.default": "وكيل", "ui.common.file.one": "ملف", "ui.common.file.other": "ملفات", @@ -102,6 +129,7 @@ export const dict = { "ui.message.copyResponse": "نسخ الرد", "ui.message.copied": "تم النسخ!", "ui.message.interrupted": "تمت المقاطعة", + "ui.message.queued": "في الانتظار", "ui.message.attachment.alt": "مرفق", "ui.patch.action.deleted": "محذوف", diff --git a/packages/ui/src/i18n/br.ts b/packages/ui/src/i18n/br.ts index 777f1455bd..085184fcce 100644 --- a/packages/ui/src/i18n/br.ts +++ b/packages/ui/src/i18n/br.ts @@ -3,6 +3,9 @@ export const dict = { "ui.sessionReview.title.lastTurn": "Alterações do último turno", "ui.sessionReview.diffStyle.unified": "Unificado", "ui.sessionReview.diffStyle.split": "Dividido", + "ui.sessionReview.openFile": "Abrir arquivo", + "ui.sessionReview.selection.line": "linha {{line}}", + "ui.sessionReview.selection.lines": "linhas {{start}}-{{end}}", "ui.sessionReview.expandAll": "Expandir tudo", "ui.sessionReview.collapseAll": "Recolher tudo", "ui.sessionReview.change.added": "Adicionado", @@ -13,6 +16,15 @@ export const dict = { "ui.sessionReview.largeDiff.title": "Diff grande demais para renderizar", "ui.sessionReview.largeDiff.meta": "Limite: {{limit}} linhas alteradas. Atual: {{current}} linhas alteradas.", "ui.sessionReview.largeDiff.renderAnyway": "Renderizar mesmo assim", + "ui.fileMedia.kind.image": "imagem", + "ui.fileMedia.kind.audio": "áudio", + "ui.fileMedia.state.removed": "Removido: {{kind}}", + "ui.fileMedia.state.loading": "Carregando {{kind}}...", + "ui.fileMedia.state.error": "Erro ao carregar {{kind}}", + "ui.fileMedia.state.unavailable": "{{kind}} indisponível", + "ui.fileMedia.binary.title": "Arquivo binário", + "ui.fileMedia.binary.description.path": "Não é possível exibir {{path}} porque é um arquivo binário.", + "ui.fileMedia.binary.description.default": "Não é possível exibir o arquivo porque ele é binário.", "ui.lineComment.label.prefix": "Comentar em ", "ui.lineComment.label.suffix": "", @@ -28,6 +40,9 @@ export const dict = { "ui.sessionTurn.retry.retrying": "tentando novamente", "ui.sessionTurn.retry.inSeconds": "em {{seconds}}s", + "ui.sessionTurn.retry.attempt": "tentativa #{{attempt}}", + "ui.sessionTurn.retry.attemptLine": "{{line}} - tentativa #{{attempt}}", + "ui.sessionTurn.retry.geminiHot": "gemini está muito sobrecarregado agora", "ui.sessionTurn.error.freeUsageExceeded": "Limite de uso gratuito excedido", "ui.sessionTurn.error.addCredits": "Adicionar créditos", @@ -44,6 +59,14 @@ export const dict = { "ui.sessionTurn.status.gatheringThoughts": "Organizando pensamentos", "ui.sessionTurn.status.consideringNextSteps": "Considerando próximos passos", + "ui.messagePart.questions.dismissed": "Perguntas descartadas", + "ui.messagePart.compaction": "Histórico compactado", + "ui.messagePart.context.read.one": "{{count}} leitura", + "ui.messagePart.context.read.other": "{{count}} leituras", + "ui.messagePart.context.search.one": "{{count}} pesquisa", + "ui.messagePart.context.search.other": "{{count}} pesquisas", + "ui.messagePart.context.list.one": "{{count}} lista", + "ui.messagePart.context.list.other": "{{count}} listas", "ui.messagePart.diagnostic.error": "Erro", "ui.messagePart.title.edit": "Editar", "ui.messagePart.title.write": "Escrever", @@ -63,6 +86,7 @@ export const dict = { "ui.textField.copied": "Copiado", "ui.imagePreview.alt": "Visualização de imagem", + "ui.scrollView.ariaLabel": "conteúdo rolável", "ui.tool.read": "Ler", "ui.tool.loaded": "Carregado", @@ -70,12 +94,15 @@ export const dict = { "ui.tool.glob": "Glob", "ui.tool.grep": "Grep", "ui.tool.webfetch": "Buscar Web", + "ui.tool.websearch": "Pesquisa na Web", + "ui.tool.codesearch": "Pesquisa de Código", "ui.tool.shell": "Shell", "ui.tool.patch": "Patch", "ui.tool.todos": "Tarefas", "ui.tool.todos.read": "Ler tarefas", "ui.tool.questions": "Perguntas", "ui.tool.agent": "Agente {{type}}", + "ui.tool.agent.default": "Agente", "ui.common.file.one": "arquivo", "ui.common.file.other": "arquivos", @@ -102,6 +129,7 @@ export const dict = { "ui.message.copyResponse": "Copiar resposta", "ui.message.copied": "Copiado!", "ui.message.interrupted": "Interrompido", + "ui.message.queued": "Na fila", "ui.message.attachment.alt": "anexo", "ui.patch.action.deleted": "Excluído", diff --git a/packages/ui/src/i18n/bs.ts b/packages/ui/src/i18n/bs.ts index e499647dff..28a292989a 100644 --- a/packages/ui/src/i18n/bs.ts +++ b/packages/ui/src/i18n/bs.ts @@ -7,6 +7,9 @@ export const dict = { "ui.sessionReview.title.lastTurn": "Promjene u posljednjem potezu", "ui.sessionReview.diffStyle.unified": "Ujedinjeno", "ui.sessionReview.diffStyle.split": "Podijeljeno", + "ui.sessionReview.openFile": "Otvori fajl", + "ui.sessionReview.selection.line": "linija {{line}}", + "ui.sessionReview.selection.lines": "linije {{start}}-{{end}}", "ui.sessionReview.expandAll": "Proširi sve", "ui.sessionReview.collapseAll": "Sažmi sve", "ui.sessionReview.change.added": "Dodano", @@ -17,6 +20,15 @@ export const dict = { "ui.sessionReview.largeDiff.title": "Diff je prevelik za prikaz", "ui.sessionReview.largeDiff.meta": "Limit: {{limit}} izmijenjenih linija. Trenutno: {{current}} izmijenjenih linija.", "ui.sessionReview.largeDiff.renderAnyway": "Prikaži svejedno", + "ui.fileMedia.kind.image": "slika", + "ui.fileMedia.kind.audio": "audio", + "ui.fileMedia.state.removed": "Uklonjeno: {{kind}}", + "ui.fileMedia.state.loading": "Učitavanje: {{kind}}...", + "ui.fileMedia.state.error": "Greška pri učitavanju: {{kind}}", + "ui.fileMedia.state.unavailable": "Nedostupno: {{kind}}", + "ui.fileMedia.binary.title": "Binarni fajl", + "ui.fileMedia.binary.description.path": "{{path}} se ne može prikazati jer je binarni fajl.", + "ui.fileMedia.binary.description.default": "Ovaj fajl se ne može prikazati jer je binarni.", "ui.lineComment.label.prefix": "Komentar na ", "ui.lineComment.label.suffix": "", @@ -32,6 +44,9 @@ export const dict = { "ui.sessionTurn.retry.retrying": "ponovni pokušaj", "ui.sessionTurn.retry.inSeconds": "za {{seconds}}s", + "ui.sessionTurn.retry.attempt": "pokušaj #{{attempt}}", + "ui.sessionTurn.retry.attemptLine": "{{line}} - pokušaj #{{attempt}}", + "ui.sessionTurn.retry.geminiHot": "gemini je trenutno preopterećen", "ui.sessionTurn.error.freeUsageExceeded": "Besplatna upotreba premašena", "ui.sessionTurn.error.addCredits": "Dodaj kredite", @@ -48,6 +63,14 @@ export const dict = { "ui.sessionTurn.status.gatheringThoughts": "Sređivanje misli", "ui.sessionTurn.status.consideringNextSteps": "Razmatranje sljedećih koraka", + "ui.messagePart.questions.dismissed": "Pitanja odbačena", + "ui.messagePart.compaction": "Historija sažeta", + "ui.messagePart.context.read.one": "{{count}} čitanje", + "ui.messagePart.context.read.other": "{{count}} čitanja", + "ui.messagePart.context.search.one": "{{count}} pretraga", + "ui.messagePart.context.search.other": "{{count}} pretrage", + "ui.messagePart.context.list.one": "{{count}} lista", + "ui.messagePart.context.list.other": "{{count}} liste", "ui.messagePart.diagnostic.error": "Greška", "ui.messagePart.title.edit": "Uredi", "ui.messagePart.title.write": "Napiši", @@ -67,6 +90,7 @@ export const dict = { "ui.textField.copied": "Kopirano", "ui.imagePreview.alt": "Pregled slike", + "ui.scrollView.ariaLabel": "sadržaj za pomjeranje", "ui.tool.read": "Čitanje", "ui.tool.loaded": "Učitano", @@ -74,12 +98,15 @@ export const dict = { "ui.tool.glob": "Glob", "ui.tool.grep": "Grep", "ui.tool.webfetch": "Web preuzimanje", + "ui.tool.websearch": "Pretraga weba", + "ui.tool.codesearch": "Pretraga koda", "ui.tool.shell": "Shell", "ui.tool.patch": "Patch", "ui.tool.todos": "Lista zadataka", "ui.tool.todos.read": "Čitanje liste zadataka", "ui.tool.questions": "Pitanja", "ui.tool.agent": "{{type}} agent", + "ui.tool.agent.default": "agent", "ui.common.file.one": "datoteka", "ui.common.file.other": "datoteke", @@ -106,6 +133,7 @@ export const dict = { "ui.message.copyResponse": "Kopiraj odgovor", "ui.message.copied": "Kopirano!", "ui.message.interrupted": "Prekinuto", + "ui.message.queued": "U redu", "ui.message.attachment.alt": "prilog", "ui.patch.action.deleted": "Obrisano", diff --git a/packages/ui/src/i18n/da.ts b/packages/ui/src/i18n/da.ts index 546040598f..30ff4639a9 100644 --- a/packages/ui/src/i18n/da.ts +++ b/packages/ui/src/i18n/da.ts @@ -3,6 +3,9 @@ export const dict = { "ui.sessionReview.title.lastTurn": "Ændringer fra sidste tur", "ui.sessionReview.diffStyle.unified": "Samlet", "ui.sessionReview.diffStyle.split": "Opdelt", + "ui.sessionReview.openFile": "Åbn fil", + "ui.sessionReview.selection.line": "linje {{line}}", + "ui.sessionReview.selection.lines": "linjer {{start}}-{{end}}", "ui.sessionReview.expandAll": "Udvid alle", "ui.sessionReview.collapseAll": "Skjul alle", @@ -14,6 +17,15 @@ export const dict = { "ui.sessionReview.largeDiff.title": "Diff er for stor til at blive vist", "ui.sessionReview.largeDiff.meta": "Grænse: {{limit}} ændrede linjer. Nuværende: {{current}} ændrede linjer.", "ui.sessionReview.largeDiff.renderAnyway": "Vis alligevel", + "ui.fileMedia.kind.image": "billede", + "ui.fileMedia.kind.audio": "lyd", + "ui.fileMedia.state.removed": "Fjernet: {{kind}}", + "ui.fileMedia.state.loading": "Indlæser {{kind}}...", + "ui.fileMedia.state.error": "Fejl ved indlæsning: {{kind}}", + "ui.fileMedia.state.unavailable": "Utilgængelig: {{kind}}", + "ui.fileMedia.binary.title": "Binær fil", + "ui.fileMedia.binary.description.path": "{{path}} kan ikke vises, fordi det er en binær fil.", + "ui.fileMedia.binary.description.default": "Denne fil kan ikke vises, fordi det er en binær fil.", "ui.lineComment.label.prefix": "Kommenter på ", "ui.lineComment.label.suffix": "", "ui.lineComment.editorLabel.prefix": "Kommenterer på ", @@ -27,6 +39,9 @@ export const dict = { "ui.sessionTurn.retry.retrying": "prøver igen", "ui.sessionTurn.retry.inSeconds": "om {{seconds}}s", + "ui.sessionTurn.retry.attempt": "forsøg #{{attempt}}", + "ui.sessionTurn.retry.attemptLine": "{{line}} - forsøg #{{attempt}}", + "ui.sessionTurn.retry.geminiHot": "gemini er meget overbelastet lige nu", "ui.sessionTurn.error.freeUsageExceeded": "Gratis forbrug overskredet", "ui.sessionTurn.error.addCredits": "Tilføj kreditter", @@ -43,6 +58,14 @@ export const dict = { "ui.sessionTurn.status.gatheringThoughts": "Samler tanker", "ui.sessionTurn.status.consideringNextSteps": "Overvejer næste skridt", + "ui.messagePart.questions.dismissed": "Spørgsmål afvist", + "ui.messagePart.compaction": "Historik komprimeret", + "ui.messagePart.context.read.one": "{{count}} læsning", + "ui.messagePart.context.read.other": "{{count}} læsninger", + "ui.messagePart.context.search.one": "{{count}} søgning", + "ui.messagePart.context.search.other": "{{count}} søgninger", + "ui.messagePart.context.list.one": "{{count}} liste", + "ui.messagePart.context.list.other": "{{count}} lister", "ui.messagePart.diagnostic.error": "Fejl", "ui.messagePart.title.edit": "Rediger", "ui.messagePart.title.write": "Skriv", @@ -62,6 +85,7 @@ export const dict = { "ui.textField.copied": "Kopieret", "ui.imagePreview.alt": "Billedforhåndsvisning", + "ui.scrollView.ariaLabel": "rulbart indhold", "ui.tool.read": "Læs", "ui.tool.loaded": "Indlæst", @@ -69,12 +93,15 @@ export const dict = { "ui.tool.glob": "Glob", "ui.tool.grep": "Grep", "ui.tool.webfetch": "Webhentning", + "ui.tool.websearch": "Websøgning", + "ui.tool.codesearch": "Kodesøgning", "ui.tool.shell": "Shell", "ui.tool.patch": "Patch", "ui.tool.todos": "Opgaver", "ui.tool.todos.read": "Læs opgaver", "ui.tool.questions": "Spørgsmål", "ui.tool.agent": "{{type}} Agent", + "ui.tool.agent.default": "Agent", "ui.common.file.one": "fil", "ui.common.file.other": "filer", @@ -101,6 +128,7 @@ export const dict = { "ui.message.copyResponse": "Kopier svar", "ui.message.copied": "Kopieret!", "ui.message.interrupted": "Afbrudt", + "ui.message.queued": "I kø", "ui.message.attachment.alt": "vedhæftning", "ui.patch.action.deleted": "Slettet", diff --git a/packages/ui/src/i18n/de.ts b/packages/ui/src/i18n/de.ts index bf5730f85f..bbfcd0f68a 100644 --- a/packages/ui/src/i18n/de.ts +++ b/packages/ui/src/i18n/de.ts @@ -7,6 +7,9 @@ export const dict = { "ui.sessionReview.title.lastTurn": "Änderungen der letzten Runde", "ui.sessionReview.diffStyle.unified": "Vereinheitlicht", "ui.sessionReview.diffStyle.split": "Geteilt", + "ui.sessionReview.openFile": "Datei öffnen", + "ui.sessionReview.selection.line": "Zeile {{line}}", + "ui.sessionReview.selection.lines": "Zeilen {{start}}-{{end}}", "ui.sessionReview.expandAll": "Alle erweitern", "ui.sessionReview.collapseAll": "Alle reduzieren", @@ -18,6 +21,17 @@ export const dict = { "ui.sessionReview.largeDiff.title": "Diff zu groß zum Rendern", "ui.sessionReview.largeDiff.meta": "Limit: {{limit}} geänderte Zeilen. Aktuell: {{current}} geänderte Zeilen.", "ui.sessionReview.largeDiff.renderAnyway": "Trotzdem rendern", + "ui.fileMedia.kind.image": "bild", + "ui.fileMedia.kind.audio": "audio", + "ui.fileMedia.state.removed": "{{kind}} entfernt", + "ui.fileMedia.state.loading": "{{kind}} wird geladen", + "ui.fileMedia.state.error": "Fehler bei {{kind}}", + "ui.fileMedia.state.unavailable": "{{kind}} nicht verfügbar", + "ui.fileMedia.binary.title": "Binärdatei", + "ui.fileMedia.binary.description.path": + "{{path}} kann nicht angezeigt werden, da es sich um eine Binärdatei handelt.", + "ui.fileMedia.binary.description.default": + "Diese Datei kann nicht angezeigt werden, da es sich um eine Binärdatei handelt.", "ui.lineComment.label.prefix": "Kommentar zu ", "ui.lineComment.label.suffix": "", "ui.lineComment.editorLabel.prefix": "Kommentiere ", @@ -31,6 +45,9 @@ export const dict = { "ui.sessionTurn.retry.retrying": "erneuter Versuch", "ui.sessionTurn.retry.inSeconds": "in {{seconds}}s", + "ui.sessionTurn.retry.attempt": "Versuch #{{attempt}}", + "ui.sessionTurn.retry.attemptLine": "{{line}} - Versuch #{{attempt}}", + "ui.sessionTurn.retry.geminiHot": "gemini ist gerade sehr überlastet", "ui.sessionTurn.error.freeUsageExceeded": "Kostenloses Nutzungslimit überschritten", "ui.sessionTurn.error.addCredits": "Guthaben aufladen", @@ -47,6 +64,14 @@ export const dict = { "ui.sessionTurn.status.gatheringThoughts": "Gedanken sammeln", "ui.sessionTurn.status.consideringNextSteps": "Nächste Schritte erwägen", + "ui.messagePart.questions.dismissed": "Fragen verworfen", + "ui.messagePart.compaction": "Verlauf komprimiert", + "ui.messagePart.context.read.one": "{{count}} Lesevorgang", + "ui.messagePart.context.read.other": "{{count}} Lesevorgänge", + "ui.messagePart.context.search.one": "{{count}} Suche", + "ui.messagePart.context.search.other": "{{count}} Suchen", + "ui.messagePart.context.list.one": "{{count}} Liste", + "ui.messagePart.context.list.other": "{{count}} Listen", "ui.messagePart.diagnostic.error": "Fehler", "ui.messagePart.title.edit": "Bearbeiten", "ui.messagePart.title.write": "Schreiben", @@ -66,6 +91,7 @@ export const dict = { "ui.textField.copied": "Kopiert", "ui.imagePreview.alt": "Bildvorschau", + "ui.scrollView.ariaLabel": "scrollbarer Inhalt", "ui.tool.read": "Lesen", "ui.tool.loaded": "Geladen", @@ -73,12 +99,15 @@ export const dict = { "ui.tool.glob": "Glob", "ui.tool.grep": "Grep", "ui.tool.webfetch": "Webabruf", + "ui.tool.websearch": "Websuche", + "ui.tool.codesearch": "Codesuche", "ui.tool.shell": "Shell", "ui.tool.patch": "Patch", "ui.tool.todos": "Aufgaben", "ui.tool.todos.read": "Aufgaben lesen", "ui.tool.questions": "Fragen", "ui.tool.agent": "{{type}} Agent", + "ui.tool.agent.default": "Agent", "ui.common.file.one": "Datei", "ui.common.file.other": "Dateien", @@ -105,6 +134,7 @@ export const dict = { "ui.message.copyResponse": "Antwort kopieren", "ui.message.copied": "Kopiert!", "ui.message.interrupted": "Unterbrochen", + "ui.message.queued": "In Warteschlange", "ui.message.attachment.alt": "Anhang", "ui.patch.action.deleted": "Gelöscht", diff --git a/packages/ui/src/i18n/en.ts b/packages/ui/src/i18n/en.ts index 4c9b89c6cf..7f4a4020ad 100644 --- a/packages/ui/src/i18n/en.ts +++ b/packages/ui/src/i18n/en.ts @@ -1,4 +1,4 @@ -export const dict = { +export const dict: Record<string, string> = { "ui.sessionReview.title": "Session changes", "ui.sessionReview.title.lastTurn": "Last turn changes", "ui.sessionReview.diffStyle.unified": "Unified", @@ -13,6 +13,19 @@ export const dict = { "ui.sessionReview.largeDiff.title": "Diff too large to render", "ui.sessionReview.largeDiff.meta": "Limit: {{limit}} changed lines. Current: {{current}} changed lines.", "ui.sessionReview.largeDiff.renderAnyway": "Render anyway", + "ui.sessionReview.openFile": "Open file", + "ui.sessionReview.selection.line": "line {{line}}", + "ui.sessionReview.selection.lines": "lines {{start}}-{{end}}", + + "ui.fileMedia.kind.image": "image", + "ui.fileMedia.kind.audio": "audio", + "ui.fileMedia.state.removed": "Removed {{kind}} file.", + "ui.fileMedia.state.loading": "Loading {{kind}}...", + "ui.fileMedia.state.error": "Unable to load {{kind}}.", + "ui.fileMedia.state.unavailable": "{{kind}} preview unavailable.", + "ui.fileMedia.binary.title": "Binary file", + "ui.fileMedia.binary.description.path": "{{path}} is binary.", + "ui.fileMedia.binary.description.default": "Binary content", "ui.lineComment.label.prefix": "Comment on ", "ui.lineComment.label.suffix": "", @@ -28,6 +41,9 @@ export const dict = { "ui.sessionTurn.retry.retrying": "retrying", "ui.sessionTurn.retry.inSeconds": "in {{seconds}}s", + "ui.sessionTurn.retry.attempt": "attempt #{{attempt}}", + "ui.sessionTurn.retry.attemptLine": "{{line}} - attempt #{{attempt}}", + "ui.sessionTurn.retry.geminiHot": "gemini is way too hot right now", "ui.sessionTurn.error.freeUsageExceeded": "Free usage exceeded", "ui.sessionTurn.error.addCredits": "Add credits", @@ -49,6 +65,14 @@ export const dict = { "ui.messagePart.title.write": "Write", "ui.messagePart.option.typeOwnAnswer": "Type your own answer", "ui.messagePart.review.title": "Review your answers", + "ui.messagePart.questions.dismissed": "Questions dismissed", + "ui.messagePart.compaction": "History compacted", + "ui.messagePart.context.read.one": "{{count}} read", + "ui.messagePart.context.read.other": "{{count}} reads", + "ui.messagePart.context.search.one": "{{count}} search", + "ui.messagePart.context.search.other": "{{count}} searches", + "ui.messagePart.context.list.one": "{{count}} list", + "ui.messagePart.context.list.other": "{{count}} lists", "ui.list.loading": "Loading", "ui.list.empty": "No results", @@ -63,6 +87,7 @@ export const dict = { "ui.textField.copied": "Copied", "ui.imagePreview.alt": "Image preview", + "ui.scrollView.ariaLabel": "scrollable content", "ui.tool.read": "Read", "ui.tool.loaded": "Loaded", @@ -70,12 +95,15 @@ export const dict = { "ui.tool.glob": "Glob", "ui.tool.grep": "Grep", "ui.tool.webfetch": "Webfetch", + "ui.tool.websearch": "Web Search", + "ui.tool.codesearch": "Code Search", "ui.tool.shell": "Shell", "ui.tool.patch": "Patch", "ui.tool.todos": "To-dos", "ui.tool.todos.read": "Read to-dos", "ui.tool.questions": "Questions", "ui.tool.agent": "{{type}} Agent", + "ui.tool.agent.default": "Agent", "ui.common.file.one": "file", "ui.common.file.other": "files", @@ -102,6 +130,7 @@ export const dict = { "ui.message.copyResponse": "Copy response", "ui.message.copied": "Copied", "ui.message.interrupted": "Interrupted", + "ui.message.queued": "Queued", "ui.message.attachment.alt": "attachment", "ui.patch.action.deleted": "Deleted", diff --git a/packages/ui/src/i18n/es.ts b/packages/ui/src/i18n/es.ts index 2f21b398f1..52f1506c04 100644 --- a/packages/ui/src/i18n/es.ts +++ b/packages/ui/src/i18n/es.ts @@ -3,6 +3,9 @@ export const dict = { "ui.sessionReview.title.lastTurn": "Cambios del último turno", "ui.sessionReview.diffStyle.unified": "Unificado", "ui.sessionReview.diffStyle.split": "Dividido", + "ui.sessionReview.openFile": "Abrir archivo", + "ui.sessionReview.selection.line": "línea {{line}}", + "ui.sessionReview.selection.lines": "líneas {{start}}-{{end}}", "ui.sessionReview.expandAll": "Expandir todo", "ui.sessionReview.collapseAll": "Colapsar todo", "ui.sessionReview.change.added": "Añadido", @@ -13,6 +16,15 @@ export const dict = { "ui.sessionReview.largeDiff.title": "Diff demasiado grande para renderizar", "ui.sessionReview.largeDiff.meta": "Límite: {{limit}} líneas modificadas. Actual: {{current}} líneas modificadas.", "ui.sessionReview.largeDiff.renderAnyway": "Renderizar de todos modos", + "ui.fileMedia.kind.image": "imagen", + "ui.fileMedia.kind.audio": "audio", + "ui.fileMedia.state.removed": "Archivo de {{kind}} eliminado", + "ui.fileMedia.state.loading": "Cargando archivo de {{kind}}", + "ui.fileMedia.state.error": "Error en el archivo de {{kind}}", + "ui.fileMedia.state.unavailable": "Archivo de {{kind}} no disponible", + "ui.fileMedia.binary.title": "Archivo binario", + "ui.fileMedia.binary.description.path": "No se puede mostrar {{path}} porque es un archivo binario.", + "ui.fileMedia.binary.description.default": "No se puede mostrar este archivo porque es un archivo binario.", "ui.lineComment.label.prefix": "Comentar en ", "ui.lineComment.label.suffix": "", @@ -28,6 +40,9 @@ export const dict = { "ui.sessionTurn.retry.retrying": "reintentando", "ui.sessionTurn.retry.inSeconds": "en {{seconds}}s", + "ui.sessionTurn.retry.attempt": "intento #{{attempt}}", + "ui.sessionTurn.retry.attemptLine": "{{line}} - intento #{{attempt}}", + "ui.sessionTurn.retry.geminiHot": "gemini está demasiado saturado", "ui.sessionTurn.error.freeUsageExceeded": "Límite de uso gratuito excedido", "ui.sessionTurn.error.addCredits": "Añadir créditos", @@ -44,6 +59,14 @@ export const dict = { "ui.sessionTurn.status.gatheringThoughts": "Recopilando pensamientos", "ui.sessionTurn.status.consideringNextSteps": "Considerando siguientes pasos", + "ui.messagePart.questions.dismissed": "Preguntas descartadas", + "ui.messagePart.compaction": "Historial compactado", + "ui.messagePart.context.read.one": "{{count}} lectura", + "ui.messagePart.context.read.other": "{{count}} lecturas", + "ui.messagePart.context.search.one": "{{count}} búsqueda", + "ui.messagePart.context.search.other": "{{count}} búsquedas", + "ui.messagePart.context.list.one": "{{count}} lista", + "ui.messagePart.context.list.other": "{{count}} listas", "ui.messagePart.diagnostic.error": "Error", "ui.messagePart.title.edit": "Editar", "ui.messagePart.title.write": "Escribir", @@ -63,6 +86,7 @@ export const dict = { "ui.textField.copied": "Copiado", "ui.imagePreview.alt": "Vista previa de imagen", + "ui.scrollView.ariaLabel": "contenido desplazable", "ui.tool.read": "Leer", "ui.tool.loaded": "Cargado", @@ -70,12 +94,15 @@ export const dict = { "ui.tool.glob": "Glob", "ui.tool.grep": "Grep", "ui.tool.webfetch": "Webfetch", + "ui.tool.websearch": "Búsqueda web", + "ui.tool.codesearch": "Búsqueda de código", "ui.tool.shell": "Shell", "ui.tool.patch": "Parche", "ui.tool.todos": "Tareas", "ui.tool.todos.read": "Leer tareas", "ui.tool.questions": "Preguntas", "ui.tool.agent": "Agente {{type}}", + "ui.tool.agent.default": "Agente", "ui.common.file.one": "archivo", "ui.common.file.other": "archivos", @@ -102,6 +129,7 @@ export const dict = { "ui.message.copyResponse": "Copiar respuesta", "ui.message.copied": "¡Copiado!", "ui.message.interrupted": "Interrumpido", + "ui.message.queued": "En cola", "ui.message.attachment.alt": "adjunto", "ui.patch.action.deleted": "Eliminado", diff --git a/packages/ui/src/i18n/fr.ts b/packages/ui/src/i18n/fr.ts index d4ea938684..f42c13882d 100644 --- a/packages/ui/src/i18n/fr.ts +++ b/packages/ui/src/i18n/fr.ts @@ -3,6 +3,9 @@ export const dict = { "ui.sessionReview.title.lastTurn": "Modifications du dernier tour", "ui.sessionReview.diffStyle.unified": "Unifié", "ui.sessionReview.diffStyle.split": "Divisé", + "ui.sessionReview.openFile": "Ouvrir le fichier", + "ui.sessionReview.selection.line": "ligne {{line}}", + "ui.sessionReview.selection.lines": "lignes {{start}}-{{end}}", "ui.sessionReview.expandAll": "Tout développer", "ui.sessionReview.collapseAll": "Tout réduire", "ui.sessionReview.change.added": "Ajouté", @@ -13,6 +16,15 @@ export const dict = { "ui.sessionReview.largeDiff.title": "Diff trop volumineux pour être affiché", "ui.sessionReview.largeDiff.meta": "Limite : {{limit}} lignes modifiées. Actuel : {{current}} lignes modifiées.", "ui.sessionReview.largeDiff.renderAnyway": "Afficher quand même", + "ui.fileMedia.kind.image": "image", + "ui.fileMedia.kind.audio": "audio", + "ui.fileMedia.state.removed": "Fichier {{kind}} supprimé", + "ui.fileMedia.state.loading": "Chargement du fichier {{kind}}", + "ui.fileMedia.state.error": "Erreur avec le fichier {{kind}}", + "ui.fileMedia.state.unavailable": "Fichier {{kind}} indisponible", + "ui.fileMedia.binary.title": "Fichier binaire", + "ui.fileMedia.binary.description.path": "Impossible d'afficher {{path}} car il s'agit d'un fichier binaire.", + "ui.fileMedia.binary.description.default": "Impossible d'afficher ce fichier car il s'agit d'un fichier binaire.", "ui.lineComment.label.prefix": "Commenter sur ", "ui.lineComment.label.suffix": "", @@ -28,6 +40,9 @@ export const dict = { "ui.sessionTurn.retry.retrying": "nouvelle tentative", "ui.sessionTurn.retry.inSeconds": "dans {{seconds}}s", + "ui.sessionTurn.retry.attempt": "tentative n°{{attempt}}", + "ui.sessionTurn.retry.attemptLine": "{{line}} - tentative n°{{attempt}}", + "ui.sessionTurn.retry.geminiHot": "gemini est en surchauffe", "ui.sessionTurn.error.freeUsageExceeded": "Limite d'utilisation gratuite dépassée", "ui.sessionTurn.error.addCredits": "Ajouter des crédits", @@ -44,6 +59,14 @@ export const dict = { "ui.sessionTurn.status.gatheringThoughts": "Rassemblement des idées", "ui.sessionTurn.status.consideringNextSteps": "Examen des prochaines étapes", + "ui.messagePart.questions.dismissed": "Questions ignorées", + "ui.messagePart.compaction": "Historique compacté", + "ui.messagePart.context.read.one": "{{count}} lecture", + "ui.messagePart.context.read.other": "{{count}} lectures", + "ui.messagePart.context.search.one": "{{count}} recherche", + "ui.messagePart.context.search.other": "{{count}} recherches", + "ui.messagePart.context.list.one": "{{count}} liste", + "ui.messagePart.context.list.other": "{{count}} listes", "ui.messagePart.diagnostic.error": "Erreur", "ui.messagePart.title.edit": "Modifier", "ui.messagePart.title.write": "Écrire", @@ -63,6 +86,7 @@ export const dict = { "ui.textField.copied": "Copié", "ui.imagePreview.alt": "Aperçu de l'image", + "ui.scrollView.ariaLabel": "contenu défilable", "ui.tool.read": "Lire", "ui.tool.loaded": "Chargé", @@ -70,12 +94,15 @@ export const dict = { "ui.tool.glob": "Glob", "ui.tool.grep": "Grep", "ui.tool.webfetch": "Webfetch", + "ui.tool.websearch": "Recherche Web", + "ui.tool.codesearch": "Recherche de code", "ui.tool.shell": "Shell", "ui.tool.patch": "Patch", "ui.tool.todos": "Tâches", "ui.tool.todos.read": "Lire les tâches", "ui.tool.questions": "Questions", "ui.tool.agent": "Agent {{type}}", + "ui.tool.agent.default": "Agent", "ui.common.file.one": "fichier", "ui.common.file.other": "fichiers", @@ -102,6 +129,7 @@ export const dict = { "ui.message.copyResponse": "Copier la réponse", "ui.message.copied": "Copié !", "ui.message.interrupted": "Interrompu", + "ui.message.queued": "En file", "ui.message.attachment.alt": "pièce jointe", "ui.patch.action.deleted": "Supprimé", diff --git a/packages/ui/src/i18n/ja.ts b/packages/ui/src/i18n/ja.ts index 0a4366ebef..0c9e4da2bd 100644 --- a/packages/ui/src/i18n/ja.ts +++ b/packages/ui/src/i18n/ja.ts @@ -3,6 +3,9 @@ export const dict = { "ui.sessionReview.title.lastTurn": "前回ターンの変更", "ui.sessionReview.diffStyle.unified": "Unified", "ui.sessionReview.diffStyle.split": "Split", + "ui.sessionReview.openFile": "ファイルを開く", + "ui.sessionReview.selection.line": "{{line}} 行目", + "ui.sessionReview.selection.lines": "{{start}}-{{end}} 行目", "ui.sessionReview.expandAll": "すべて展開", "ui.sessionReview.collapseAll": "すべて折りたたむ", @@ -14,6 +17,15 @@ export const dict = { "ui.sessionReview.largeDiff.title": "差分が大きすぎて表示できません", "ui.sessionReview.largeDiff.meta": "上限: {{limit}} 変更行。現在: {{current}} 変更行。", "ui.sessionReview.largeDiff.renderAnyway": "それでも表示する", + "ui.fileMedia.kind.image": "画像", + "ui.fileMedia.kind.audio": "音声", + "ui.fileMedia.state.removed": "{{kind}}は削除されました", + "ui.fileMedia.state.loading": "{{kind}}を読み込んでいます...", + "ui.fileMedia.state.error": "{{kind}}の読み込みに失敗しました", + "ui.fileMedia.state.unavailable": "{{kind}}は表示できません", + "ui.fileMedia.binary.title": "バイナリファイル", + "ui.fileMedia.binary.description.path": "{{path}} はバイナリファイルのため表示できません。", + "ui.fileMedia.binary.description.default": "このファイルはバイナリファイルのため表示できません。", "ui.lineComment.label.prefix": "", "ui.lineComment.label.suffix": "へのコメント", "ui.lineComment.editorLabel.prefix": "", @@ -27,6 +39,9 @@ export const dict = { "ui.sessionTurn.retry.retrying": "再試行中", "ui.sessionTurn.retry.inSeconds": "{{seconds}}秒後", + "ui.sessionTurn.retry.attempt": "{{attempt}}回目", + "ui.sessionTurn.retry.attemptLine": "{{line}} - {{attempt}}回目", + "ui.sessionTurn.retry.geminiHot": "gemini が混雑しています", "ui.sessionTurn.error.freeUsageExceeded": "無料使用制限に達しました", "ui.sessionTurn.error.addCredits": "クレジットを追加", @@ -43,6 +58,14 @@ export const dict = { "ui.sessionTurn.status.gatheringThoughts": "考えをまとめています", "ui.sessionTurn.status.consideringNextSteps": "次のステップを検討中", + "ui.messagePart.questions.dismissed": "質問をスキップしました", + "ui.messagePart.compaction": "履歴を圧縮しました", + "ui.messagePart.context.read.one": "{{count}} 件の読み取り", + "ui.messagePart.context.read.other": "{{count}} 件の読み取り", + "ui.messagePart.context.search.one": "{{count}} 件の検索", + "ui.messagePart.context.search.other": "{{count}} 件の検索", + "ui.messagePart.context.list.one": "{{count}} 件のリスト", + "ui.messagePart.context.list.other": "{{count}} 件のリスト", "ui.messagePart.diagnostic.error": "エラー", "ui.messagePart.title.edit": "編集", "ui.messagePart.title.write": "作成", @@ -62,6 +85,7 @@ export const dict = { "ui.textField.copied": "コピーしました", "ui.imagePreview.alt": "画像プレビュー", + "ui.scrollView.ariaLabel": "スクロール可能なコンテンツ", "ui.tool.read": "読み込み", "ui.tool.loaded": "読み込み済み", @@ -69,12 +93,15 @@ export const dict = { "ui.tool.glob": "Glob", "ui.tool.grep": "Grep", "ui.tool.webfetch": "Webfetch", + "ui.tool.websearch": "Web検索", + "ui.tool.codesearch": "コード検索", "ui.tool.shell": "Shell", "ui.tool.patch": "Patch", "ui.tool.todos": "Todo", "ui.tool.todos.read": "Todo読み込み", "ui.tool.questions": "質問", "ui.tool.agent": "{{type}}エージェント", + "ui.tool.agent.default": "エージェント", "ui.common.file.one": "ファイル", "ui.common.file.other": "ファイル", @@ -101,6 +128,7 @@ export const dict = { "ui.message.copyResponse": "応答をコピー", "ui.message.copied": "コピーしました!", "ui.message.interrupted": "中断", + "ui.message.queued": "待機中", "ui.message.attachment.alt": "添付ファイル", "ui.patch.action.deleted": "削除済み", diff --git a/packages/ui/src/i18n/ko.ts b/packages/ui/src/i18n/ko.ts index 58bd51b991..74c2d4ec80 100644 --- a/packages/ui/src/i18n/ko.ts +++ b/packages/ui/src/i18n/ko.ts @@ -3,6 +3,9 @@ export const dict = { "ui.sessionReview.title.lastTurn": "마지막 턴 변경 사항", "ui.sessionReview.diffStyle.unified": "통합 보기", "ui.sessionReview.diffStyle.split": "분할 보기", + "ui.sessionReview.openFile": "파일 열기", + "ui.sessionReview.selection.line": "{{line}}번 줄", + "ui.sessionReview.selection.lines": "{{start}}-{{end}}번 줄", "ui.sessionReview.expandAll": "모두 펼치기", "ui.sessionReview.collapseAll": "모두 접기", "ui.sessionReview.change.added": "추가됨", @@ -13,6 +16,15 @@ export const dict = { "ui.sessionReview.largeDiff.title": "차이가 너무 커서 렌더링할 수 없습니다", "ui.sessionReview.largeDiff.meta": "제한: {{limit}} 변경 줄. 현재: {{current}} 변경 줄.", "ui.sessionReview.largeDiff.renderAnyway": "그래도 렌더링", + "ui.fileMedia.kind.image": "이미지", + "ui.fileMedia.kind.audio": "오디오", + "ui.fileMedia.state.removed": "{{kind}} 제거됨", + "ui.fileMedia.state.loading": "{{kind}} 로드 중...", + "ui.fileMedia.state.error": "{{kind}} 로드 오류", + "ui.fileMedia.state.unavailable": "{{kind}} 사용 불가", + "ui.fileMedia.binary.title": "바이너리 파일", + "ui.fileMedia.binary.description.path": "{{path}}은(는) 바이너리 파일이므로 표시할 수 없습니다.", + "ui.fileMedia.binary.description.default": "바이너리 파일이므로 표시할 수 없습니다.", "ui.lineComment.label.prefix": "", "ui.lineComment.label.suffix": "에 댓글 달기", @@ -28,6 +40,9 @@ export const dict = { "ui.sessionTurn.retry.retrying": "재시도 중", "ui.sessionTurn.retry.inSeconds": "{{seconds}}초 후", + "ui.sessionTurn.retry.attempt": "{{attempt}}번째", + "ui.sessionTurn.retry.attemptLine": "{{line}} - {{attempt}}번째", + "ui.sessionTurn.retry.geminiHot": "gemini가 현재 과부하 상태입니다", "ui.sessionTurn.error.freeUsageExceeded": "무료 사용량 초과", "ui.sessionTurn.error.addCredits": "크레딧 추가", @@ -44,6 +59,14 @@ export const dict = { "ui.sessionTurn.status.gatheringThoughts": "생각 정리 중", "ui.sessionTurn.status.consideringNextSteps": "다음 단계 고려 중", + "ui.messagePart.questions.dismissed": "질문 무시됨", + "ui.messagePart.compaction": "기록이 압축됨", + "ui.messagePart.context.read.one": "{{count}}개 읽음", + "ui.messagePart.context.read.other": "{{count}}개 읽음", + "ui.messagePart.context.search.one": "{{count}}개 검색", + "ui.messagePart.context.search.other": "{{count}}개 검색", + "ui.messagePart.context.list.one": "{{count}}개 목록", + "ui.messagePart.context.list.other": "{{count}}개 목록", "ui.messagePart.diagnostic.error": "오류", "ui.messagePart.title.edit": "편집", "ui.messagePart.title.write": "작성", @@ -63,6 +86,7 @@ export const dict = { "ui.textField.copied": "복사됨", "ui.imagePreview.alt": "이미지 미리보기", + "ui.scrollView.ariaLabel": "스크롤 가능한 콘텐츠", "ui.tool.read": "읽기", "ui.tool.loaded": "로드됨", @@ -70,12 +94,15 @@ export const dict = { "ui.tool.glob": "Glob", "ui.tool.grep": "Grep", "ui.tool.webfetch": "웹 가져오기", + "ui.tool.websearch": "웹 검색", + "ui.tool.codesearch": "코드 검색", "ui.tool.shell": "셸", "ui.tool.patch": "패치", "ui.tool.todos": "할 일", "ui.tool.todos.read": "할 일 읽기", "ui.tool.questions": "질문", "ui.tool.agent": "{{type}} 에이전트", + "ui.tool.agent.default": "에이전트", "ui.common.file.one": "파일", "ui.common.file.other": "파일", @@ -102,6 +129,7 @@ export const dict = { "ui.message.copyResponse": "응답 복사", "ui.message.copied": "복사됨!", "ui.message.interrupted": "중단됨", + "ui.message.queued": "대기 중", "ui.message.attachment.alt": "첨부 파일", "ui.patch.action.deleted": "삭제됨", diff --git a/packages/ui/src/i18n/no.ts b/packages/ui/src/i18n/no.ts index b7e604f9ac..489f218ca5 100644 --- a/packages/ui/src/i18n/no.ts +++ b/packages/ui/src/i18n/no.ts @@ -6,6 +6,9 @@ export const dict: Record<Keys, string> = { "ui.sessionReview.title.lastTurn": "Endringer i siste tur", "ui.sessionReview.diffStyle.unified": "Samlet", "ui.sessionReview.diffStyle.split": "Delt", + "ui.sessionReview.openFile": "Åpne fil", + "ui.sessionReview.selection.line": "linje {{line}}", + "ui.sessionReview.selection.lines": "linjer {{start}}-{{end}}", "ui.sessionReview.expandAll": "Utvid alle", "ui.sessionReview.collapseAll": "Fold sammen alle", "ui.sessionReview.change.added": "Lagt til", @@ -16,6 +19,15 @@ export const dict: Record<Keys, string> = { "ui.sessionReview.largeDiff.title": "Diff er for stor til å gjengi", "ui.sessionReview.largeDiff.meta": "Grense: {{limit}} endrede linjer. Nåværende: {{current}} endrede linjer.", "ui.sessionReview.largeDiff.renderAnyway": "Gjengi likevel", + "ui.fileMedia.kind.image": "bilde", + "ui.fileMedia.kind.audio": "lyd", + "ui.fileMedia.state.removed": "Fjernet: {{kind}}", + "ui.fileMedia.state.loading": "Laster inn {{kind}}...", + "ui.fileMedia.state.error": "Feil ved innlasting: {{kind}}", + "ui.fileMedia.state.unavailable": "Ikke tilgjengelig: {{kind}}", + "ui.fileMedia.binary.title": "Binærfil", + "ui.fileMedia.binary.description.path": "{{path}} kan ikke vises fordi det er en binærfil.", + "ui.fileMedia.binary.description.default": "Denne filen kan ikke vises fordi det er en binærfil.", "ui.lineComment.label.prefix": "Kommenter på ", "ui.lineComment.label.suffix": "", @@ -31,6 +43,9 @@ export const dict: Record<Keys, string> = { "ui.sessionTurn.retry.retrying": "Prøver igjen", "ui.sessionTurn.retry.inSeconds": "om {{seconds}}s", + "ui.sessionTurn.retry.attempt": "forsøk #{{attempt}}", + "ui.sessionTurn.retry.attemptLine": "{{line}} - forsøk #{{attempt}}", + "ui.sessionTurn.retry.geminiHot": "gemini er veldig overbelastet nå", "ui.sessionTurn.error.freeUsageExceeded": "Gratis bruk overskredet", "ui.sessionTurn.error.addCredits": "Legg til kreditt", @@ -47,6 +62,14 @@ export const dict: Record<Keys, string> = { "ui.sessionTurn.status.gatheringThoughts": "Samler tanker", "ui.sessionTurn.status.consideringNextSteps": "Vurderer neste trinn", + "ui.messagePart.questions.dismissed": "Spørsmål avvist", + "ui.messagePart.compaction": "Historikk komprimert", + "ui.messagePart.context.read.one": "{{count}} lest", + "ui.messagePart.context.read.other": "{{count}} lest", + "ui.messagePart.context.search.one": "{{count}} søk", + "ui.messagePart.context.search.other": "{{count}} søk", + "ui.messagePart.context.list.one": "{{count}} liste", + "ui.messagePart.context.list.other": "{{count}} lister", "ui.messagePart.diagnostic.error": "Feil", "ui.messagePart.title.edit": "Rediger", "ui.messagePart.title.write": "Skriv", @@ -66,6 +89,7 @@ export const dict: Record<Keys, string> = { "ui.textField.copied": "Kopiert", "ui.imagePreview.alt": "Bildeforhåndsvisning", + "ui.scrollView.ariaLabel": "rullbart innhold", "ui.tool.read": "Les", "ui.tool.loaded": "Lastet", @@ -73,12 +97,15 @@ export const dict: Record<Keys, string> = { "ui.tool.glob": "Glob", "ui.tool.grep": "Grep", "ui.tool.webfetch": "Webhenting", + "ui.tool.websearch": "Nettsøk", + "ui.tool.codesearch": "Kodesøk", "ui.tool.shell": "Shell", "ui.tool.patch": "Patch", "ui.tool.todos": "Gjøremål", "ui.tool.todos.read": "Les gjøremål", "ui.tool.questions": "Spørsmål", "ui.tool.agent": "{{type}}-agent", + "ui.tool.agent.default": "agent", "ui.common.file.one": "fil", "ui.common.file.other": "filer", @@ -105,6 +132,7 @@ export const dict: Record<Keys, string> = { "ui.message.copyResponse": "Kopier svar", "ui.message.copied": "Kopiert!", "ui.message.interrupted": "Avbrutt", + "ui.message.queued": "I kø", "ui.message.attachment.alt": "vedlegg", "ui.patch.action.deleted": "Slettet", diff --git a/packages/ui/src/i18n/pl.ts b/packages/ui/src/i18n/pl.ts index fbccb92207..9b37a0fd6c 100644 --- a/packages/ui/src/i18n/pl.ts +++ b/packages/ui/src/i18n/pl.ts @@ -3,6 +3,9 @@ export const dict = { "ui.sessionReview.title.lastTurn": "Zmiany z ostatniej tury", "ui.sessionReview.diffStyle.unified": "Ujednolicony", "ui.sessionReview.diffStyle.split": "Podzielony", + "ui.sessionReview.openFile": "Otwórz plik", + "ui.sessionReview.selection.line": "linia {{line}}", + "ui.sessionReview.selection.lines": "linie {{start}}-{{end}}", "ui.sessionReview.expandAll": "Rozwiń wszystko", "ui.sessionReview.collapseAll": "Zwiń wszystko", @@ -14,6 +17,15 @@ export const dict = { "ui.sessionReview.largeDiff.title": "Diff jest zbyt duży, aby go wyrenderować", "ui.sessionReview.largeDiff.meta": "Limit: {{limit}} zmienionych linii. Obecnie: {{current}} zmienionych linii.", "ui.sessionReview.largeDiff.renderAnyway": "Renderuj mimo to", + "ui.fileMedia.kind.image": "obraz", + "ui.fileMedia.kind.audio": "dźwięk", + "ui.fileMedia.state.removed": "{{kind}} usunięty", + "ui.fileMedia.state.loading": "Wczytywanie: {{kind}}...", + "ui.fileMedia.state.error": "Błąd wczytywania: {{kind}}", + "ui.fileMedia.state.unavailable": "{{kind}} niedostępny", + "ui.fileMedia.binary.title": "Plik binarny", + "ui.fileMedia.binary.description.path": "Nie można wyświetlić pliku {{path}}, ponieważ jest to plik binarny.", + "ui.fileMedia.binary.description.default": "Nie można wyświetlić tego pliku, ponieważ jest to plik binarny.", "ui.lineComment.label.prefix": "Komentarz do ", "ui.lineComment.label.suffix": "", "ui.lineComment.editorLabel.prefix": "Komentowanie: ", @@ -27,6 +39,9 @@ export const dict = { "ui.sessionTurn.retry.retrying": "ponawianie", "ui.sessionTurn.retry.inSeconds": "za {{seconds}}s", + "ui.sessionTurn.retry.attempt": "próba #{{attempt}}", + "ui.sessionTurn.retry.attemptLine": "{{line}} - próba #{{attempt}}", + "ui.sessionTurn.retry.geminiHot": "gemini jest teraz mocno przeciążony", "ui.sessionTurn.error.freeUsageExceeded": "Przekroczono limit darmowego użytkowania", "ui.sessionTurn.error.addCredits": "Dodaj kredyty", @@ -43,6 +58,14 @@ export const dict = { "ui.sessionTurn.status.gatheringThoughts": "Zbieranie myśli", "ui.sessionTurn.status.consideringNextSteps": "Rozważanie kolejnych kroków", + "ui.messagePart.questions.dismissed": "Pytania odrzucone", + "ui.messagePart.compaction": "Historia skompaktowana", + "ui.messagePart.context.read.one": "{{count}} odczyt", + "ui.messagePart.context.read.other": "{{count}} odczyty", + "ui.messagePart.context.search.one": "{{count}} wyszukiwanie", + "ui.messagePart.context.search.other": "{{count}} wyszukiwania", + "ui.messagePart.context.list.one": "{{count}} lista", + "ui.messagePart.context.list.other": "{{count}} listy", "ui.messagePart.diagnostic.error": "Błąd", "ui.messagePart.title.edit": "Edycja", "ui.messagePart.title.write": "Pisanie", @@ -62,6 +85,7 @@ export const dict = { "ui.textField.copied": "Skopiowano", "ui.imagePreview.alt": "Podgląd obrazu", + "ui.scrollView.ariaLabel": "treść przewijana", "ui.tool.read": "Odczyt", "ui.tool.loaded": "Załadowano", @@ -69,12 +93,15 @@ export const dict = { "ui.tool.glob": "Glob", "ui.tool.grep": "Grep", "ui.tool.webfetch": "Pobieranie sieciowe", + "ui.tool.websearch": "Wyszukiwanie w sieci", + "ui.tool.codesearch": "Wyszukiwanie kodu", "ui.tool.shell": "Terminal", "ui.tool.patch": "Patch", "ui.tool.todos": "Zadania", "ui.tool.todos.read": "Czytaj zadania", "ui.tool.questions": "Pytania", "ui.tool.agent": "Agent {{type}}", + "ui.tool.agent.default": "Agent", "ui.common.file.one": "plik", "ui.common.file.other": "pliki", @@ -101,6 +128,7 @@ export const dict = { "ui.message.copyResponse": "Kopiuj odpowiedź", "ui.message.copied": "Skopiowano!", "ui.message.interrupted": "Przerwano", + "ui.message.queued": "W kolejce", "ui.message.attachment.alt": "załącznik", "ui.patch.action.deleted": "Usunięto", diff --git a/packages/ui/src/i18n/ru.ts b/packages/ui/src/i18n/ru.ts index 705f2d2109..7157670c42 100644 --- a/packages/ui/src/i18n/ru.ts +++ b/packages/ui/src/i18n/ru.ts @@ -3,6 +3,9 @@ export const dict = { "ui.sessionReview.title.lastTurn": "Изменения последнего хода", "ui.sessionReview.diffStyle.unified": "Объединённый", "ui.sessionReview.diffStyle.split": "Разделённый", + "ui.sessionReview.openFile": "Открыть файл", + "ui.sessionReview.selection.line": "строка {{line}}", + "ui.sessionReview.selection.lines": "строки {{start}}-{{end}}", "ui.sessionReview.expandAll": "Развернуть всё", "ui.sessionReview.collapseAll": "Свернуть всё", @@ -14,6 +17,15 @@ export const dict = { "ui.sessionReview.largeDiff.title": "Diff слишком большой для отображения", "ui.sessionReview.largeDiff.meta": "Лимит: {{limit}} изменённых строк. Текущий: {{current}} изменённых строк.", "ui.sessionReview.largeDiff.renderAnyway": "Отобразить всё равно", + "ui.fileMedia.kind.image": "изображение", + "ui.fileMedia.kind.audio": "аудио", + "ui.fileMedia.state.removed": "{{kind}} удалено", + "ui.fileMedia.state.loading": "Загружается {{kind}}...", + "ui.fileMedia.state.error": "Не удалось загрузить {{kind}}", + "ui.fileMedia.state.unavailable": "{{kind}} недоступно", + "ui.fileMedia.binary.title": "Бинарный файл", + "ui.fileMedia.binary.description.path": "Невозможно отобразить {{path}}, так как это бинарный файл.", + "ui.fileMedia.binary.description.default": "Невозможно отобразить этот файл, так как он бинарный.", "ui.lineComment.label.prefix": "Комментарий к ", "ui.lineComment.label.suffix": "", "ui.lineComment.editorLabel.prefix": "Комментирование: ", @@ -27,6 +39,9 @@ export const dict = { "ui.sessionTurn.retry.retrying": "повтор", "ui.sessionTurn.retry.inSeconds": "через {{seconds}}с", + "ui.sessionTurn.retry.attempt": "попытка №{{attempt}}", + "ui.sessionTurn.retry.attemptLine": "{{line}} - попытка №{{attempt}}", + "ui.sessionTurn.retry.geminiHot": "gemini сейчас перегружен", "ui.sessionTurn.error.freeUsageExceeded": "Лимит бесплатного использования превышен", "ui.sessionTurn.error.addCredits": "Добавить кредиты", @@ -43,6 +58,14 @@ export const dict = { "ui.sessionTurn.status.gatheringThoughts": "Сбор мыслей", "ui.sessionTurn.status.consideringNextSteps": "Рассмотрение следующих шагов", + "ui.messagePart.questions.dismissed": "Вопросы отклонены", + "ui.messagePart.compaction": "История сжата", + "ui.messagePart.context.read.one": "{{count}} чтение", + "ui.messagePart.context.read.other": "{{count}} чтений", + "ui.messagePart.context.search.one": "{{count}} поиск", + "ui.messagePart.context.search.other": "{{count}} поисков", + "ui.messagePart.context.list.one": "{{count}} список", + "ui.messagePart.context.list.other": "{{count}} списков", "ui.messagePart.diagnostic.error": "Ошибка", "ui.messagePart.title.edit": "Редактировать", "ui.messagePart.title.write": "Написать", @@ -62,6 +85,7 @@ export const dict = { "ui.textField.copied": "Скопировано", "ui.imagePreview.alt": "Предпросмотр изображения", + "ui.scrollView.ariaLabel": "прокручиваемый контент", "ui.tool.read": "Чтение", "ui.tool.loaded": "Загружено", @@ -69,12 +93,15 @@ export const dict = { "ui.tool.glob": "Glob", "ui.tool.grep": "Grep", "ui.tool.webfetch": "Webfetch", + "ui.tool.websearch": "Веб-поиск", + "ui.tool.codesearch": "Поиск кода", "ui.tool.shell": "Оболочка", "ui.tool.patch": "Патч", "ui.tool.todos": "Задачи", "ui.tool.todos.read": "Читать задачи", "ui.tool.questions": "Вопросы", "ui.tool.agent": "Агент {{type}}", + "ui.tool.agent.default": "Агент", "ui.common.file.one": "файл", "ui.common.file.other": "файлов", @@ -101,6 +128,7 @@ export const dict = { "ui.message.copyResponse": "Копировать ответ", "ui.message.copied": "Скопировано!", "ui.message.interrupted": "Прервано", + "ui.message.queued": "В очереди", "ui.message.attachment.alt": "вложение", "ui.patch.action.deleted": "Удалено", diff --git a/packages/ui/src/i18n/th.ts b/packages/ui/src/i18n/th.ts index cf536e1ff6..553638cf43 100644 --- a/packages/ui/src/i18n/th.ts +++ b/packages/ui/src/i18n/th.ts @@ -3,6 +3,9 @@ export const dict = { "ui.sessionReview.title.lastTurn": "การเปลี่ยนแปลงของเทิร์นล่าสุด", "ui.sessionReview.diffStyle.unified": "แบบรวม", "ui.sessionReview.diffStyle.split": "แบบแยก", + "ui.sessionReview.openFile": "เปิดไฟล์", + "ui.sessionReview.selection.line": "บรรทัดที่ {{line}}", + "ui.sessionReview.selection.lines": "บรรทัดที่ {{start}}-{{end}}", "ui.sessionReview.expandAll": "ขยายทั้งหมด", "ui.sessionReview.collapseAll": "ย่อทั้งหมด", "ui.sessionReview.change.added": "เพิ่ม", @@ -14,6 +17,15 @@ export const dict = { "ui.sessionReview.largeDiff.meta": "ขีดจำกัด: {{limit}} บรรทัดที่เปลี่ยนแปลง. ปัจจุบัน: {{current}} บรรทัดที่เปลี่ยนแปลง.", "ui.sessionReview.largeDiff.renderAnyway": "แสดงผลต่อไป", + "ui.fileMedia.kind.image": "รูปภาพ", + "ui.fileMedia.kind.audio": "เสียง", + "ui.fileMedia.state.removed": "ลบ{{kind}}แล้ว", + "ui.fileMedia.state.loading": "กำลังโหลด{{kind}}...", + "ui.fileMedia.state.error": "เกิดข้อผิดพลาดในการโหลด{{kind}}", + "ui.fileMedia.state.unavailable": "{{kind}}ไม่พร้อมใช้งาน", + "ui.fileMedia.binary.title": "ไฟล์ไบนารี", + "ui.fileMedia.binary.description.path": "{{path}} เป็นไฟล์ไบนารีและไม่สามารถแสดงผลได้", + "ui.fileMedia.binary.description.default": "ไฟล์ไบนารีไม่สามารถแสดงผลได้", "ui.lineComment.label.prefix": "แสดงความคิดเห็นบน ", "ui.lineComment.label.suffix": "", @@ -29,6 +41,9 @@ export const dict = { "ui.sessionTurn.retry.retrying": "กำลังลองใหม่", "ui.sessionTurn.retry.inSeconds": "ใน {{seconds}}วิ", + "ui.sessionTurn.retry.attempt": "ครั้งที่ {{attempt}}", + "ui.sessionTurn.retry.attemptLine": "{{line}} - ครั้งที่ {{attempt}}", + "ui.sessionTurn.retry.geminiHot": "gemini กำลังใช้งานหนาแน่นมาก", "ui.sessionTurn.error.freeUsageExceeded": "เกินขีดจำกัดการใช้งานฟรี", "ui.sessionTurn.error.addCredits": "เพิ่มเครดิต", @@ -45,6 +60,14 @@ export const dict = { "ui.sessionTurn.status.gatheringThoughts": "รวบรวมความคิด", "ui.sessionTurn.status.consideringNextSteps": "พิจารณาขั้นตอนถัดไป", + "ui.messagePart.questions.dismissed": "ละทิ้งคำถามแล้ว", + "ui.messagePart.compaction": "ประวัติถูกบีบอัด", + "ui.messagePart.context.read.one": "อ่าน {{count}} รายการ", + "ui.messagePart.context.read.other": "อ่าน {{count}} รายการ", + "ui.messagePart.context.search.one": "ค้นหา {{count}} รายการ", + "ui.messagePart.context.search.other": "ค้นหา {{count}} รายการ", + "ui.messagePart.context.list.one": "รายการ {{count}} รายการ", + "ui.messagePart.context.list.other": "รายการ {{count}} รายการ", "ui.messagePart.diagnostic.error": "ข้อผิดพลาด", "ui.messagePart.title.edit": "แก้ไข", "ui.messagePart.title.write": "เขียน", @@ -64,6 +87,7 @@ export const dict = { "ui.textField.copied": "คัดลอกแล้ว", "ui.imagePreview.alt": "ตัวอย่างรูปภาพ", + "ui.scrollView.ariaLabel": "เนื้อหาที่เลื่อนได้", "ui.tool.read": "อ่าน", "ui.tool.loaded": "โหลดแล้ว", @@ -71,12 +95,15 @@ export const dict = { "ui.tool.glob": "Glob", "ui.tool.grep": "Grep", "ui.tool.webfetch": "ดึงจากเว็บ", + "ui.tool.websearch": "ค้นหาเว็บ", + "ui.tool.codesearch": "ค้นหาโค้ด", "ui.tool.shell": "เชลล์", "ui.tool.patch": "แพตช์", "ui.tool.todos": "รายการงาน", "ui.tool.todos.read": "อ่านรายการงาน", "ui.tool.questions": "คำถาม", "ui.tool.agent": "เอเจนต์ {{type}}", + "ui.tool.agent.default": "เอเจนต์", "ui.common.file.one": "ไฟล์", "ui.common.file.other": "ไฟล์", @@ -103,6 +130,7 @@ export const dict = { "ui.message.copyResponse": "คัดลอกคำตอบ", "ui.message.copied": "คัดลอกแล้ว!", "ui.message.interrupted": "ถูกขัดจังหวะ", + "ui.message.queued": "อยู่ในคิว", "ui.message.attachment.alt": "ไฟล์แนบ", "ui.patch.action.deleted": "ลบ", diff --git a/packages/ui/src/i18n/tr.ts b/packages/ui/src/i18n/tr.ts new file mode 100644 index 0000000000..5b4d71e4aa --- /dev/null +++ b/packages/ui/src/i18n/tr.ts @@ -0,0 +1,142 @@ +import { dict as en } from "./en" + +type Keys = keyof typeof en + +export const dict = { + "ui.sessionReview.title": "Oturum değişiklikleri", + "ui.sessionReview.title.lastTurn": "Son tur değişiklikleri", + "ui.sessionReview.diffStyle.unified": "Birleşik", + "ui.sessionReview.diffStyle.split": "Bölünmüş", + "ui.sessionReview.openFile": "Dosyayı aç", + "ui.sessionReview.selection.line": "satır {{line}}", + "ui.sessionReview.selection.lines": "satırlar {{start}}-{{end}}", + "ui.sessionReview.expandAll": "Tümünü genişlet", + "ui.sessionReview.collapseAll": "Tümünü daralt", + + "ui.sessionReview.change.added": "Eklendi", + "ui.sessionReview.change.removed": "Kaldırıldı", + "ui.sessionReview.change.modified": "Değiştirildi", + "ui.sessionReview.image.loading": "Yükleniyor...", + "ui.sessionReview.image.placeholder": "Görsel", + "ui.sessionReview.largeDiff.title": "Fark gösterimi için çok büyük", + "ui.sessionReview.largeDiff.meta": "Limit: {{limit}} değişen satır. Mevcut: {{current}} değişen satır.", + "ui.sessionReview.largeDiff.renderAnyway": "Yine de göster", + + "ui.lineComment.label.prefix": "Yorum: ", + "ui.lineComment.label.suffix": "", + "ui.lineComment.editorLabel.prefix": "Yorum yapılıyor: ", + "ui.lineComment.editorLabel.suffix": "", + "ui.lineComment.placeholder": "Yorum ekle", + "ui.lineComment.submit": "Yorum yap", + + "ui.sessionTurn.steps.show": "Adımları göster", + "ui.sessionTurn.steps.hide": "Adımları gizle", + "ui.sessionTurn.summary.response": "Yanıt", + "ui.sessionTurn.diff.showMore": "Daha fazla değişiklik göster ({{count}})", + + "ui.sessionTurn.retry.retrying": "yeniden deneniyor", + "ui.sessionTurn.retry.inSeconds": "{{seconds}}sn içinde", + "ui.sessionTurn.retry.attempt": "deneme #{{attempt}}", + "ui.sessionTurn.retry.attemptLine": "{{line}} - deneme #{{attempt}}", + "ui.sessionTurn.retry.geminiHot": "gemini şu anda aşırı yoğun", + "ui.sessionTurn.error.freeUsageExceeded": "Ücretsiz kullanım aşıldı", + "ui.sessionTurn.error.addCredits": "Kredi ekle", + + "ui.sessionTurn.status.delegating": "Görev devrediliyor", + "ui.sessionTurn.status.planning": "Sonraki adımlar planlanıyor", + "ui.sessionTurn.status.gatheringContext": "Keşfediliyor", + "ui.sessionTurn.status.gatheredContext": "Keşfedildi", + "ui.sessionTurn.status.searchingCodebase": "Kod tabanı aranıyor", + "ui.sessionTurn.status.searchingWeb": "Web aranıyor", + "ui.sessionTurn.status.makingEdits": "Düzenlemeler yapılıyor", + "ui.sessionTurn.status.runningCommands": "Komutlar çalıştırılıyor", + "ui.sessionTurn.status.thinking": "Düşünüyor", + "ui.sessionTurn.status.thinkingWithTopic": "Düşünüyor - {{topic}}", + "ui.sessionTurn.status.gatheringThoughts": "Düşünceler toplanıyor", + "ui.sessionTurn.status.consideringNextSteps": "Sonraki adımlar değerlendiriliyor", + + "ui.messagePart.questions.dismissed": "Sorular reddedildi", + "ui.messagePart.compaction": "Geçmiş sıkıştırıldı", + "ui.messagePart.context.read.one": "{{count}} okuma", + "ui.messagePart.context.read.other": "{{count}} okuma", + "ui.messagePart.context.search.one": "{{count}} arama", + "ui.messagePart.context.search.other": "{{count}} arama", + "ui.messagePart.context.list.one": "{{count}} liste", + "ui.messagePart.context.list.other": "{{count}} liste", + "ui.messagePart.diagnostic.error": "Hata", + "ui.messagePart.title.edit": "Düzenle", + "ui.messagePart.title.write": "Yaz", + "ui.messagePart.option.typeOwnAnswer": "Kendi cevabınızı yazın", + "ui.messagePart.review.title": "Cevapları inceleyin", + + "ui.list.loading": "Yükleniyor", + "ui.list.empty": "Sonuç bulunamadı", + "ui.list.clearFilter": "Filtreyi temizle", + "ui.list.emptyWithFilter.prefix": "Sonuç bulunamadı:", + "ui.list.emptyWithFilter.suffix": "", + + "ui.messageNav.newMessage": "Yeni mesaj", + + "ui.textField.copyToClipboard": "Panoya kopyala", + "ui.textField.copyLink": "Bağlantı kopyala", + "ui.textField.copied": "Kopyalandı", + + "ui.imagePreview.alt": "Görsel önizleme", + "ui.scrollView.ariaLabel": "kaydırılabilir içerik", + + "ui.tool.read": "Oku", + "ui.tool.loaded": "Yüklendi", + "ui.tool.list": "Listele", + "ui.tool.glob": "Glob", + "ui.tool.grep": "Grep", + "ui.tool.webfetch": "Web getir", + "ui.tool.websearch": "Web Araması", + "ui.tool.codesearch": "Kod Araması", + "ui.tool.shell": "Kabuk", + "ui.tool.patch": "Yama", + "ui.tool.todos": "Görevler", + "ui.tool.todos.read": "Görevleri oku", + "ui.tool.questions": "Sorular", + "ui.tool.agent": "{{type}} Ajan", + "ui.tool.agent.default": "Ajan", + + "ui.common.file.one": "dosya", + "ui.common.file.other": "dosya", + "ui.common.question.one": "soru", + "ui.common.question.other": "soru", + + "ui.common.add": "Ekle", + "ui.common.back": "Geri", + "ui.common.cancel": "İptal", + "ui.common.confirm": "Onayla", + "ui.common.dismiss": "Kapat", + "ui.common.close": "Kapat", + "ui.common.next": "İleri", + "ui.common.submit": "Gönder", + + "ui.permission.deny": "Reddet", + "ui.permission.allowAlways": "Her zaman izin ver", + "ui.permission.allowOnce": "Bir kez izin ver", + + "ui.message.expand": "Mesajı genişlet", + "ui.message.collapse": "Mesajı daralt", + "ui.message.copy": "Kopyala", + "ui.message.copyMessage": "Mesajı kopyala", + "ui.message.copyResponse": "Yanıtı kopyala", + "ui.message.copied": "Kopyalandı", + "ui.message.interrupted": "Kesildi", + "ui.message.queued": "Sırada", + "ui.message.attachment.alt": "ek", + + "ui.patch.action.deleted": "Silindi", + "ui.patch.action.created": "Oluşturuldu", + "ui.patch.action.moved": "Taşındı", + "ui.patch.action.patched": "Yamalandı", + + "ui.question.subtitle.answered": "{{count}} cevaplandı", + "ui.question.answer.none": "(cevap yok)", + "ui.question.review.notAnswered": "(cevaplanmadı)", + "ui.question.multiHint": "Geçerli tüm cevapları seçin", + "ui.question.singleHint": "Bir cevap seçin", + "ui.question.custom.placeholder": "Cevabınızı yazın...", +} satisfies Partial<Record<Keys, string>> diff --git a/packages/ui/src/i18n/zh.ts b/packages/ui/src/i18n/zh.ts index 5d3d5613da..638230544c 100644 --- a/packages/ui/src/i18n/zh.ts +++ b/packages/ui/src/i18n/zh.ts @@ -7,6 +7,9 @@ export const dict = { "ui.sessionReview.title.lastTurn": "上一轮变更", "ui.sessionReview.diffStyle.unified": "统一", "ui.sessionReview.diffStyle.split": "拆分", + "ui.sessionReview.openFile": "打开文件", + "ui.sessionReview.selection.line": "第 {{line}} 行", + "ui.sessionReview.selection.lines": "第 {{start}}-{{end}} 行", "ui.sessionReview.expandAll": "全部展开", "ui.sessionReview.collapseAll": "全部收起", "ui.sessionReview.change.added": "已添加", @@ -17,6 +20,15 @@ export const dict = { "ui.sessionReview.largeDiff.title": "差异过大,无法渲染", "ui.sessionReview.largeDiff.meta": "限制:{{limit}} 行变更。当前:{{current}} 行变更。", "ui.sessionReview.largeDiff.renderAnyway": "仍然渲染", + "ui.fileMedia.kind.image": "图片", + "ui.fileMedia.kind.audio": "音频", + "ui.fileMedia.state.removed": "{{kind}}已移除", + "ui.fileMedia.state.loading": "正在加载{{kind}}...", + "ui.fileMedia.state.error": "加载{{kind}}失败", + "ui.fileMedia.state.unavailable": "{{kind}}不可预览", + "ui.fileMedia.binary.title": "二进制文件", + "ui.fileMedia.binary.description.path": "无法显示 {{path}},因为它是二进制文件。", + "ui.fileMedia.binary.description.default": "无法显示此文件,因为它是二进制文件。", "ui.lineComment.label.prefix": "评论 ", "ui.lineComment.label.suffix": "", @@ -32,6 +44,9 @@ export const dict = { "ui.sessionTurn.retry.retrying": "重试中", "ui.sessionTurn.retry.inSeconds": "{{seconds}} 秒后", + "ui.sessionTurn.retry.attempt": "第 {{attempt}} 次", + "ui.sessionTurn.retry.attemptLine": "{{line}} - 第 {{attempt}} 次", + "ui.sessionTurn.retry.geminiHot": "gemini 当前过载", "ui.sessionTurn.error.freeUsageExceeded": "免费使用额度已用完", "ui.sessionTurn.error.addCredits": "添加积分", @@ -48,6 +63,14 @@ export const dict = { "ui.sessionTurn.status.gatheringThoughts": "正在整理思路", "ui.sessionTurn.status.consideringNextSteps": "正在考虑下一步", + "ui.messagePart.questions.dismissed": "问题已忽略", + "ui.messagePart.compaction": "历史已压缩", + "ui.messagePart.context.read.one": "{{count}} 次读取", + "ui.messagePart.context.read.other": "{{count}} 次读取", + "ui.messagePart.context.search.one": "{{count}} 次搜索", + "ui.messagePart.context.search.other": "{{count}} 次搜索", + "ui.messagePart.context.list.one": "{{count}} 个列表", + "ui.messagePart.context.list.other": "{{count}} 个列表", "ui.messagePart.diagnostic.error": "错误", "ui.messagePart.title.edit": "编辑", "ui.messagePart.title.write": "写入", @@ -67,6 +90,7 @@ export const dict = { "ui.textField.copied": "已复制", "ui.imagePreview.alt": "图片预览", + "ui.scrollView.ariaLabel": "可滚动内容", "ui.tool.read": "读取", "ui.tool.loaded": "已加载", @@ -74,12 +98,15 @@ export const dict = { "ui.tool.glob": "Glob", "ui.tool.grep": "Grep", "ui.tool.webfetch": "Webfetch", + "ui.tool.websearch": "网络搜索", + "ui.tool.codesearch": "代码搜索", "ui.tool.shell": "Shell", "ui.tool.patch": "补丁", "ui.tool.todos": "待办", "ui.tool.todos.read": "读取待办", "ui.tool.questions": "问题", "ui.tool.agent": "{{type}} 智能体", + "ui.tool.agent.default": "智能体", "ui.common.file.one": "个文件", "ui.common.file.other": "个文件", @@ -106,6 +133,7 @@ export const dict = { "ui.message.copyResponse": "复制回复", "ui.message.copied": "已复制!", "ui.message.interrupted": "已中断", + "ui.message.queued": "排队中", "ui.message.attachment.alt": "附件", "ui.patch.action.deleted": "已删除", diff --git a/packages/ui/src/i18n/zht.ts b/packages/ui/src/i18n/zht.ts index b61349e25d..f793ce345b 100644 --- a/packages/ui/src/i18n/zht.ts +++ b/packages/ui/src/i18n/zht.ts @@ -7,6 +7,9 @@ export const dict = { "ui.sessionReview.title.lastTurn": "上一輪變更", "ui.sessionReview.diffStyle.unified": "整合", "ui.sessionReview.diffStyle.split": "拆分", + "ui.sessionReview.openFile": "開啟檔案", + "ui.sessionReview.selection.line": "第 {{line}} 行", + "ui.sessionReview.selection.lines": "第 {{start}}-{{end}} 行", "ui.sessionReview.expandAll": "全部展開", "ui.sessionReview.collapseAll": "全部收合", "ui.sessionReview.change.added": "已新增", @@ -17,6 +20,15 @@ export const dict = { "ui.sessionReview.largeDiff.title": "差異過大,無法渲染", "ui.sessionReview.largeDiff.meta": "限制:{{limit}} 行變更。目前:{{current}} 行變更。", "ui.sessionReview.largeDiff.renderAnyway": "仍然渲染", + "ui.fileMedia.kind.image": "圖片", + "ui.fileMedia.kind.audio": "音訊", + "ui.fileMedia.state.removed": "{{kind}}已移除", + "ui.fileMedia.state.loading": "正在載入{{kind}}...", + "ui.fileMedia.state.error": "載入{{kind}}失敗", + "ui.fileMedia.state.unavailable": "{{kind}}無法預覽", + "ui.fileMedia.binary.title": "二進位檔案", + "ui.fileMedia.binary.description.path": "無法顯示 {{path}},因為它是二進位檔案。", + "ui.fileMedia.binary.description.default": "無法顯示此檔案,因為它是二進位檔案。", "ui.lineComment.label.prefix": "評論 ", "ui.lineComment.label.suffix": "", @@ -32,6 +44,9 @@ export const dict = { "ui.sessionTurn.retry.retrying": "重試中", "ui.sessionTurn.retry.inSeconds": "{{seconds}} 秒後", + "ui.sessionTurn.retry.attempt": "第 {{attempt}} 次", + "ui.sessionTurn.retry.attemptLine": "{{line}} - 第 {{attempt}} 次", + "ui.sessionTurn.retry.geminiHot": "gemini 目前過載", "ui.sessionTurn.error.freeUsageExceeded": "免費使用額度已用完", "ui.sessionTurn.error.addCredits": "新增點數", @@ -48,6 +63,14 @@ export const dict = { "ui.sessionTurn.status.gatheringThoughts": "正在整理思緒", "ui.sessionTurn.status.consideringNextSteps": "正在考慮下一步", + "ui.messagePart.questions.dismissed": "問題已略過", + "ui.messagePart.compaction": "歷史已壓縮", + "ui.messagePart.context.read.one": "{{count}} 次讀取", + "ui.messagePart.context.read.other": "{{count}} 次讀取", + "ui.messagePart.context.search.one": "{{count}} 次搜尋", + "ui.messagePart.context.search.other": "{{count}} 次搜尋", + "ui.messagePart.context.list.one": "{{count}} 個清單", + "ui.messagePart.context.list.other": "{{count}} 個清單", "ui.messagePart.diagnostic.error": "錯誤", "ui.messagePart.title.edit": "編輯", "ui.messagePart.title.write": "寫入", @@ -67,6 +90,7 @@ export const dict = { "ui.textField.copied": "已複製", "ui.imagePreview.alt": "圖片預覽", + "ui.scrollView.ariaLabel": "可捲動內容", "ui.tool.read": "讀取", "ui.tool.loaded": "已載入", @@ -74,12 +98,15 @@ export const dict = { "ui.tool.glob": "Glob", "ui.tool.grep": "Grep", "ui.tool.webfetch": "Webfetch", + "ui.tool.websearch": "網頁搜尋", + "ui.tool.codesearch": "程式碼搜尋", "ui.tool.shell": "Shell", "ui.tool.patch": "修補", "ui.tool.todos": "待辦", "ui.tool.todos.read": "讀取待辦", "ui.tool.questions": "問題", "ui.tool.agent": "{{type}} 代理程式", + "ui.tool.agent.default": "代理程式", "ui.common.file.one": "個檔案", "ui.common.file.other": "個檔案", @@ -106,6 +133,7 @@ export const dict = { "ui.message.copyResponse": "複製回覆", "ui.message.copied": "已複製!", "ui.message.interrupted": "已中斷", + "ui.message.queued": "排隊中", "ui.message.attachment.alt": "附件", "ui.patch.action.deleted": "已刪除", diff --git a/packages/ui/src/pierre/comment-hover.ts b/packages/ui/src/pierre/comment-hover.ts new file mode 100644 index 0000000000..1d3674cf6f --- /dev/null +++ b/packages/ui/src/pierre/comment-hover.ts @@ -0,0 +1,74 @@ +export type HoverCommentLine = { + lineNumber: number + side?: "additions" | "deletions" +} + +export function createHoverCommentUtility(props: { + label: string + getHoveredLine: () => HoverCommentLine | undefined + onSelect: (line: HoverCommentLine) => void +}) { + if (typeof document === "undefined") return + + const button = document.createElement("button") + button.type = "button" + button.ariaLabel = props.label + button.textContent = "+" + button.style.width = "20px" + button.style.height = "20px" + button.style.display = "flex" + button.style.alignItems = "center" + button.style.justifyContent = "center" + button.style.border = "none" + button.style.borderRadius = "var(--radius-md)" + button.style.background = "var(--icon-interactive-base)" + button.style.color = "var(--white)" + button.style.boxShadow = "var(--shadow-xs)" + button.style.fontSize = "14px" + button.style.lineHeight = "1" + button.style.cursor = "pointer" + button.style.position = "relative" + button.style.left = "30px" + button.style.top = "calc((var(--diffs-line-height, 24px) - 20px) / 2)" + + let line: HoverCommentLine | undefined + + const sync = () => { + const next = props.getHoveredLine() + if (!next) return + line = next + } + + const loop = () => { + if (!button.isConnected) return + sync() + requestAnimationFrame(loop) + } + + const open = () => { + const next = props.getHoveredLine() ?? line + if (!next) return + props.onSelect(next) + } + + requestAnimationFrame(loop) + button.addEventListener("mouseenter", sync) + button.addEventListener("mousemove", sync) + button.addEventListener("pointerdown", (event) => { + event.preventDefault() + event.stopPropagation() + sync() + }) + button.addEventListener("mousedown", (event) => { + event.preventDefault() + event.stopPropagation() + sync() + }) + button.addEventListener("click", (event) => { + event.preventDefault() + event.stopPropagation() + open() + }) + + return button +} diff --git a/packages/ui/src/pierre/commented-lines.ts b/packages/ui/src/pierre/commented-lines.ts new file mode 100644 index 0000000000..d2fa648663 --- /dev/null +++ b/packages/ui/src/pierre/commented-lines.ts @@ -0,0 +1,91 @@ +import { type SelectedLineRange } from "@pierre/diffs" +import { diffLineIndex, diffRowIndex, findDiffSide } from "./diff-selection" + +export type CommentSide = "additions" | "deletions" + +function annotationIndex(node: HTMLElement) { + const value = node.dataset.lineAnnotation?.split(",")[1] + if (!value) return + const line = parseInt(value, 10) + if (Number.isNaN(line)) return + return line +} + +function clear(root: ShadowRoot) { + const marked = Array.from(root.querySelectorAll("[data-comment-selected]")) + for (const node of marked) { + if (!(node instanceof HTMLElement)) continue + node.removeAttribute("data-comment-selected") + } +} + +export function markCommentedDiffLines(root: ShadowRoot, ranges: SelectedLineRange[]) { + clear(root) + + const diffs = root.querySelector("[data-diff]") + if (!(diffs instanceof HTMLElement)) return + + const split = diffs.dataset.diffType === "split" + const rows = Array.from(diffs.querySelectorAll("[data-line-index]")).filter( + (node): node is HTMLElement => node instanceof HTMLElement, + ) + if (rows.length === 0) return + + const annotations = Array.from(diffs.querySelectorAll("[data-line-annotation]")).filter( + (node): node is HTMLElement => node instanceof HTMLElement, + ) + + for (const range of ranges) { + const start = diffRowIndex(root, split, range.start, range.side as CommentSide | undefined) + if (start === undefined) continue + + const end = (() => { + const same = range.end === range.start && (range.endSide == null || range.endSide === range.side) + if (same) return start + return diffRowIndex(root, split, range.end, (range.endSide ?? range.side) as CommentSide | undefined) + })() + if (end === undefined) continue + + const first = Math.min(start, end) + const last = Math.max(start, end) + + for (const row of rows) { + const idx = diffLineIndex(split, row) + if (idx === undefined || idx < first || idx > last) continue + row.setAttribute("data-comment-selected", "") + } + + for (const annotation of annotations) { + const idx = annotationIndex(annotation) + if (idx === undefined || idx < first || idx > last) continue + annotation.setAttribute("data-comment-selected", "") + } + } +} + +export function markCommentedFileLines(root: ShadowRoot, ranges: SelectedLineRange[]) { + clear(root) + + const annotations = Array.from(root.querySelectorAll("[data-line-annotation]")).filter( + (node): node is HTMLElement => node instanceof HTMLElement, + ) + + for (const range of ranges) { + const start = Math.max(1, Math.min(range.start, range.end)) + const end = Math.max(range.start, range.end) + + for (let line = start; line <= end; line++) { + const nodes = Array.from(root.querySelectorAll(`[data-line="${line}"], [data-column-number="${line}"]`)) + for (const node of nodes) { + if (!(node instanceof HTMLElement)) continue + node.setAttribute("data-comment-selected", "") + } + } + + for (const annotation of annotations) { + const line = annotationIndex(annotation) + if (line === undefined || line < start || line > end) continue + annotation.setAttribute("data-comment-selected", "") + } + } +} diff --git a/packages/ui/src/pierre/diff-selection.ts b/packages/ui/src/pierre/diff-selection.ts new file mode 100644 index 0000000000..bc008b1b2e --- /dev/null +++ b/packages/ui/src/pierre/diff-selection.ts @@ -0,0 +1,71 @@ +import { type SelectedLineRange } from "@pierre/diffs" + +export type DiffSelectionSide = "additions" | "deletions" + +export function findDiffSide(node: HTMLElement): DiffSelectionSide { + const line = node.closest("[data-line], [data-alt-line]") + if (line instanceof HTMLElement) { + const type = line.dataset.lineType + if (type === "change-deletion") return "deletions" + if (type === "change-addition" || type === "change-additions") return "additions" + } + + const code = node.closest("[data-code]") + if (!(code instanceof HTMLElement)) return "additions" + return code.hasAttribute("data-deletions") ? "deletions" : "additions" +} + +export function diffLineIndex(split: boolean, node: HTMLElement) { + const raw = node.dataset.lineIndex + if (!raw) return + + const values = raw + .split(",") + .map((x) => parseInt(x, 10)) + .filter((x) => !Number.isNaN(x)) + if (values.length === 0) return + if (!split) return values[0] + if (values.length === 2) return values[1] + return values[0] +} + +export function diffRowIndex(root: ShadowRoot, split: boolean, line: number, side: DiffSelectionSide | undefined) { + const rows = Array.from(root.querySelectorAll(`[data-line="${line}"], [data-alt-line="${line}"]`)).filter( + (node): node is HTMLElement => node instanceof HTMLElement, + ) + if (rows.length === 0) return + + const target = side ?? "additions" + for (const row of rows) { + if (findDiffSide(row) === target) return diffLineIndex(split, row) + if (parseInt(row.dataset.altLine ?? "", 10) === line) return diffLineIndex(split, row) + } +} + +export function fixDiffSelection(root: ShadowRoot | undefined, range: SelectedLineRange | null) { + if (!range) return range + if (!root) return + + const diffs = root.querySelector("[data-diff]") + if (!(diffs instanceof HTMLElement)) return + + const split = diffs.dataset.diffType === "split" + const start = diffRowIndex(root, split, range.start, range.side) + const end = diffRowIndex(root, split, range.end, range.endSide ?? range.side) + + if (start === undefined || end === undefined) { + if (root.querySelector("[data-line], [data-alt-line]") == null) return + return null + } + if (start <= end) return range + + const side = range.endSide ?? range.side + const swapped: SelectedLineRange = { + start: range.end, + end: range.start, + } + + if (side) swapped.side = side + if (range.endSide && range.side) swapped.endSide = range.side + return swapped +} diff --git a/packages/ui/src/pierre/file-find.ts b/packages/ui/src/pierre/file-find.ts new file mode 100644 index 0000000000..7d55cfa72b --- /dev/null +++ b/packages/ui/src/pierre/file-find.ts @@ -0,0 +1,576 @@ +import { createEffect, createSignal, onCleanup, onMount } from "solid-js" + +export type FindHost = { + element: () => HTMLElement | undefined + open: () => void + close: () => void + next: (dir: 1 | -1) => void + isOpen: () => boolean +} + +type FileFindSide = "additions" | "deletions" + +export type FileFindReveal = { + side: FileFindSide + line: number + col: number + len: number +} + +type FileFindHit = FileFindReveal & { + range: Range + alt?: number +} + +const hosts = new Set<FindHost>() +let target: FindHost | undefined +let current: FindHost | undefined +let installed = false + +function isEditable(node: unknown): boolean { + if (!(node instanceof HTMLElement)) return false + if (node.closest("[data-prevent-autofocus]")) return true + if (node.isContentEditable) return true + return /^(INPUT|TEXTAREA|SELECT|BUTTON)$/.test(node.tagName) +} + +function hostForNode(node: unknown) { + if (!(node instanceof Node)) return + for (const host of hosts) { + const el = host.element() + if (el && el.isConnected && el.contains(node)) return host + } +} + +function installShortcuts() { + if (installed) return + if (typeof window === "undefined") return + installed = true + + window.addEventListener( + "keydown", + (event) => { + if (event.defaultPrevented) return + if (isEditable(event.target)) return + + const mod = event.metaKey || event.ctrlKey + if (!mod) return + + const key = event.key.toLowerCase() + if (key === "g") { + const host = current + if (!host || !host.isOpen()) return + event.preventDefault() + event.stopPropagation() + host.next(event.shiftKey ? -1 : 1) + return + } + + if (key !== "f") return + + const active = current + if (active && active.isOpen()) { + event.preventDefault() + event.stopPropagation() + active.open() + return + } + + const host = hostForNode(document.activeElement) ?? hostForNode(event.target) ?? target ?? Array.from(hosts)[0] + if (!host) return + + event.preventDefault() + event.stopPropagation() + host.open() + }, + { capture: true }, + ) +} + +function clearHighlightFind() { + const api = (globalThis as { CSS?: { highlights?: { delete: (name: string) => void } } }).CSS?.highlights + if (!api) return + api.delete("opencode-find") + api.delete("opencode-find-current") +} + +function supportsHighlights() { + const g = globalThis as unknown as { CSS?: { highlights?: unknown }; Highlight?: unknown } + return typeof g.Highlight === "function" && g.CSS?.highlights != null +} + +function scrollParent(el: HTMLElement): HTMLElement | undefined { + let parent = el.parentElement + while (parent) { + const style = getComputedStyle(parent) + if (style.overflowY === "auto" || style.overflowY === "scroll") return parent + parent = parent.parentElement + } +} + +type CreateFileFindOptions = { + wrapper: () => HTMLElement | undefined + overlay: () => HTMLDivElement | undefined + getRoot: () => ShadowRoot | undefined + shortcuts?: "global" | "disabled" +} + +export function createFileFind(opts: CreateFileFindOptions) { + let input: HTMLInputElement | undefined + let overlayFrame: number | undefined + let overlayScroll: HTMLElement[] = [] + let mode: "highlights" | "overlay" = "overlay" + let hits: FileFindHit[] = [] + + const [open, setOpen] = createSignal(false) + const [query, setQuery] = createSignal("") + const [index, setIndex] = createSignal(0) + const [count, setCount] = createSignal(0) + const [pos, setPos] = createSignal({ top: 8, right: 8 }) + + const clearOverlayScroll = () => { + for (const el of overlayScroll) el.removeEventListener("scroll", scheduleOverlay) + overlayScroll = [] + } + + const clearOverlay = () => { + const el = opts.overlay() + if (!el) return + if (overlayFrame !== undefined) { + cancelAnimationFrame(overlayFrame) + overlayFrame = undefined + } + el.innerHTML = "" + } + + const renderOverlay = () => { + if (mode !== "overlay") { + clearOverlay() + return + } + + const wrapper = opts.wrapper() + const overlay = opts.overlay() + if (!wrapper || !overlay) return + + clearOverlay() + if (hits.length === 0) return + + const base = wrapper.getBoundingClientRect() + const currentIndex = index() + const frag = document.createDocumentFragment() + + for (let i = 0; i < hits.length; i++) { + const range = hits[i].range + const active = i === currentIndex + for (const rect of Array.from(range.getClientRects())) { + if (!rect.width || !rect.height) continue + + const mark = document.createElement("div") + mark.style.position = "absolute" + mark.style.left = `${Math.round(rect.left - base.left)}px` + mark.style.top = `${Math.round(rect.top - base.top)}px` + mark.style.width = `${Math.round(rect.width)}px` + mark.style.height = `${Math.round(rect.height)}px` + mark.style.borderRadius = "2px" + mark.style.backgroundColor = active ? "var(--surface-warning-strong)" : "var(--surface-warning-base)" + mark.style.opacity = active ? "0.55" : "0.35" + if (active) mark.style.boxShadow = "inset 0 0 0 1px var(--border-warning-base)" + frag.appendChild(mark) + } + } + + overlay.appendChild(frag) + } + + function scheduleOverlay() { + if (mode !== "overlay") return + if (!open()) return + if (overlayFrame !== undefined) return + + overlayFrame = requestAnimationFrame(() => { + overlayFrame = undefined + renderOverlay() + }) + } + + const syncOverlayScroll = () => { + if (mode !== "overlay") return + const root = opts.getRoot() + + const next = root + ? Array.from(root.querySelectorAll("[data-code]")).filter( + (node): node is HTMLElement => node instanceof HTMLElement, + ) + : [] + if (next.length === overlayScroll.length && next.every((el, i) => el === overlayScroll[i])) return + + clearOverlayScroll() + overlayScroll = next + for (const el of overlayScroll) el.addEventListener("scroll", scheduleOverlay, { passive: true }) + } + + const clearFind = () => { + clearHighlightFind() + clearOverlay() + clearOverlayScroll() + hits = [] + setCount(0) + setIndex(0) + } + + const positionBar = () => { + if (typeof window === "undefined") return + const wrapper = opts.wrapper() + if (!wrapper) return + + const root = scrollParent(wrapper) ?? wrapper + const rect = root.getBoundingClientRect() + const title = parseFloat(getComputedStyle(root).getPropertyValue("--session-title-height")) + const header = Number.isNaN(title) ? 0 : title + + setPos({ + top: Math.round(rect.top) + header - 4, + right: Math.round(window.innerWidth - rect.right) + 8, + }) + } + + const scan = (root: ShadowRoot, value: string) => { + const needle = value.toLowerCase() + const ranges: FileFindHit[] = [] + const cols = Array.from(root.querySelectorAll("[data-content] [data-line], [data-column-content]")).filter( + (node): node is HTMLElement => node instanceof HTMLElement, + ) + + for (const col of cols) { + const text = col.textContent + if (!text) continue + + const hay = text.toLowerCase() + let at = hay.indexOf(needle) + if (at === -1) continue + + const row = col.closest("[data-line], [data-alt-line]") + if (!(row instanceof HTMLElement)) continue + + const primary = parseInt(row.dataset.line ?? "", 10) + const alt = parseInt(row.dataset.altLine ?? "", 10) + const line = (() => { + if (!Number.isNaN(primary)) return primary + if (!Number.isNaN(alt)) return alt + })() + if (line === undefined) continue + + const side = (() => { + const code = col.closest("[data-code]") + if (code instanceof HTMLElement) return code.hasAttribute("data-deletions") ? "deletions" : "additions" + + const row = col.closest("[data-line-type]") + if (!(row instanceof HTMLElement)) return "additions" + const type = row.dataset.lineType + if (type === "change-deletion") return "deletions" + return "additions" + })() as FileFindSide + + const nodes: Text[] = [] + const ends: number[] = [] + const walker = document.createTreeWalker(col, NodeFilter.SHOW_TEXT) + let node = walker.nextNode() + let pos = 0 + while (node) { + if (node instanceof Text) { + pos += node.data.length + nodes.push(node) + ends.push(pos) + } + node = walker.nextNode() + } + if (nodes.length === 0) continue + + const locate = (offset: number) => { + let lo = 0 + let hi = ends.length - 1 + while (lo < hi) { + const mid = (lo + hi) >> 1 + if (ends[mid] >= offset) hi = mid + else lo = mid + 1 + } + const prev = lo === 0 ? 0 : ends[lo - 1] + return { node: nodes[lo], offset: offset - prev } + } + + while (at !== -1) { + const start = locate(at) + const end = locate(at + value.length) + const range = document.createRange() + range.setStart(start.node, start.offset) + range.setEnd(end.node, end.offset) + ranges.push({ + range, + side, + line, + alt: Number.isNaN(alt) ? undefined : alt, + col: at + 1, + len: value.length, + }) + at = hay.indexOf(needle, at + value.length) + } + } + + return ranges + } + + const scrollToRange = (range: Range) => { + const scroll = () => { + const start = range.startContainer + const el = start instanceof Element ? start : start.parentElement + el?.scrollIntoView({ block: "center", inline: "center" }) + } + + scroll() + requestAnimationFrame(scroll) + } + + const setHighlights = (ranges: FileFindHit[], currentIndex: number) => { + const api = (globalThis as unknown as { CSS?: { highlights?: any }; Highlight?: any }).CSS?.highlights + const Highlight = (globalThis as unknown as { Highlight?: any }).Highlight + if (!api || typeof Highlight !== "function") return false + + api.delete("opencode-find") + api.delete("opencode-find-current") + + const active = ranges[currentIndex]?.range + if (active) api.set("opencode-find-current", new Highlight(active)) + + const rest = ranges.flatMap((hit, i) => (i === currentIndex ? [] : [hit.range])) + if (rest.length > 0) api.set("opencode-find", new Highlight(...rest)) + return true + } + + const select = (currentIndex: number, scroll: boolean) => { + const active = hits[currentIndex]?.range + if (!active) return false + + setIndex(currentIndex) + + if (mode === "highlights") { + if (!setHighlights(hits, currentIndex)) { + mode = "overlay" + apply({ reset: true, scroll }) + return false + } + if (scroll) scrollToRange(active) + return true + } + + clearHighlightFind() + syncOverlayScroll() + if (scroll) scrollToRange(active) + scheduleOverlay() + return true + } + + const apply = (args?: { reset?: boolean; scroll?: boolean }) => { + if (!open()) return + + const value = query().trim() + if (!value) { + clearFind() + return + } + + const root = opts.getRoot() + if (!root) return + + mode = supportsHighlights() ? "highlights" : "overlay" + + const ranges = scan(root, value) + const total = ranges.length + const desired = args?.reset ? 0 : index() + const currentIndex = total ? Math.min(desired, total - 1) : 0 + + hits = ranges + setCount(total) + setIndex(currentIndex) + + const active = ranges[currentIndex]?.range + if (mode === "highlights") { + clearOverlay() + clearOverlayScroll() + if (!setHighlights(ranges, currentIndex)) { + mode = "overlay" + clearHighlightFind() + syncOverlayScroll() + scheduleOverlay() + } + if (args?.scroll && active) scrollToRange(active) + return + } + + clearHighlightFind() + syncOverlayScroll() + if (args?.scroll && active) scrollToRange(active) + scheduleOverlay() + } + + const close = () => { + setOpen(false) + setQuery("") + clearFind() + if (current === host) current = undefined + } + + const clear = () => { + setQuery("") + clearFind() + } + + const activate = () => { + if (opts.shortcuts !== "disabled") { + if (current && current !== host) current.close() + current = host + target = host + } + + if (!open()) setOpen(true) + } + + const focus = () => { + activate() + requestAnimationFrame(() => { + apply({ scroll: true }) + input?.focus() + input?.select() + }) + } + + const next = (dir: 1 | -1) => { + if (!open()) return + const total = count() + if (total <= 0) return + + const currentIndex = (index() + dir + total) % total + select(currentIndex, true) + } + + const reveal = (targetHit: FileFindReveal) => { + if (!open()) return false + if (hits.length === 0) return false + + const exact = hits.findIndex( + (hit) => + hit.side === targetHit.side && + hit.line === targetHit.line && + hit.col === targetHit.col && + hit.len === targetHit.len, + ) + const fallback = hits.findIndex( + (hit) => + (hit.line === targetHit.line || hit.alt === targetHit.line) && + hit.col === targetHit.col && + hit.len === targetHit.len, + ) + + const nextIndex = exact >= 0 ? exact : fallback + if (nextIndex < 0) return false + return select(nextIndex, true) + } + + const host: FindHost = { + element: opts.wrapper, + isOpen: () => open(), + next, + open: focus, + close, + } + + onMount(() => { + mode = supportsHighlights() ? "highlights" : "overlay" + if (opts.shortcuts !== "disabled") { + installShortcuts() + hosts.add(host) + if (!target) target = host + } + + onCleanup(() => { + if (opts.shortcuts !== "disabled") { + hosts.delete(host) + if (current === host) { + current = undefined + clearHighlightFind() + } + if (target === host) target = undefined + } + }) + }) + + createEffect(() => { + if (!open()) return + + const update = () => positionBar() + requestAnimationFrame(update) + window.addEventListener("resize", update, { passive: true }) + + const wrapper = opts.wrapper() + if (!wrapper) return + const root = scrollParent(wrapper) ?? wrapper + const observer = typeof ResizeObserver === "undefined" ? undefined : new ResizeObserver(() => update()) + observer?.observe(root) + + onCleanup(() => { + window.removeEventListener("resize", update) + observer?.disconnect() + }) + }) + + onCleanup(() => { + clearOverlayScroll() + clearOverlay() + if (current === host) { + current = undefined + clearHighlightFind() + } + }) + + return { + open, + query, + count, + index, + pos, + setInput: (el: HTMLInputElement) => { + input = el + }, + setQuery: (value: string, args?: { scroll?: boolean }) => { + setQuery(value) + setIndex(0) + apply({ reset: true, scroll: args?.scroll ?? true }) + }, + clear, + activate, + focus, + close, + next, + reveal, + refresh: (args?: { reset?: boolean; scroll?: boolean }) => apply(args), + onPointerDown: () => { + if (opts.shortcuts === "disabled") return + target = host + opts.wrapper()?.focus({ preventScroll: true }) + }, + onFocus: () => { + if (opts.shortcuts === "disabled") return + target = host + }, + onInputKeyDown: (event: KeyboardEvent) => { + if (event.key === "Escape") { + event.preventDefault() + close() + return + } + if (event.key !== "Enter") return + event.preventDefault() + next(event.shiftKey ? -1 : 1) + }, + } +} diff --git a/packages/ui/src/pierre/file-runtime.ts b/packages/ui/src/pierre/file-runtime.ts new file mode 100644 index 0000000000..a207210035 --- /dev/null +++ b/packages/ui/src/pierre/file-runtime.ts @@ -0,0 +1,114 @@ +type ReadyWatcher = { + observer?: MutationObserver + token: number +} + +export function createReadyWatcher(): ReadyWatcher { + return { token: 0 } +} + +export function clearReadyWatcher(state: ReadyWatcher) { + state.observer?.disconnect() + state.observer = undefined +} + +export function getViewerHost(container: HTMLElement | undefined) { + if (!container) return + const host = container.querySelector("diffs-container") + if (!(host instanceof HTMLElement)) return + return host +} + +export function getViewerRoot(container: HTMLElement | undefined) { + return getViewerHost(container)?.shadowRoot ?? undefined +} + +export function applyViewerScheme(host: HTMLElement | undefined) { + if (!host) return + if (typeof document === "undefined") return + + const scheme = document.documentElement.dataset.colorScheme + if (scheme === "dark" || scheme === "light") { + host.dataset.colorScheme = scheme + return + } + + host.removeAttribute("data-color-scheme") +} + +export function observeViewerScheme(getHost: () => HTMLElement | undefined) { + if (typeof document === "undefined") return () => {} + + applyViewerScheme(getHost()) + if (typeof MutationObserver === "undefined") return () => {} + + const root = document.documentElement + const monitor = new MutationObserver(() => applyViewerScheme(getHost())) + monitor.observe(root, { attributes: true, attributeFilter: ["data-color-scheme"] }) + return () => monitor.disconnect() +} + +export function notifyShadowReady(opts: { + state: ReadyWatcher + container: HTMLElement + getRoot: () => ShadowRoot | undefined + isReady: (root: ShadowRoot) => boolean + onReady: () => void + settleFrames?: number +}) { + clearReadyWatcher(opts.state) + opts.state.token += 1 + + const token = opts.state.token + const settle = Math.max(0, opts.settleFrames ?? 0) + + const runReady = () => { + const step = (left: number) => { + if (token !== opts.state.token) return + if (left <= 0) { + opts.onReady() + return + } + requestAnimationFrame(() => step(left - 1)) + } + + requestAnimationFrame(() => step(settle)) + } + + const observeRoot = (root: ShadowRoot) => { + if (opts.isReady(root)) { + runReady() + return + } + + if (typeof MutationObserver === "undefined") return + + clearReadyWatcher(opts.state) + opts.state.observer = new MutationObserver(() => { + if (token !== opts.state.token) return + if (!opts.isReady(root)) return + + clearReadyWatcher(opts.state) + runReady() + }) + opts.state.observer.observe(root, { childList: true, subtree: true }) + } + + const root = opts.getRoot() + if (!root) { + if (typeof MutationObserver === "undefined") return + + opts.state.observer = new MutationObserver(() => { + if (token !== opts.state.token) return + + const next = opts.getRoot() + if (!next) return + + observeRoot(next) + }) + opts.state.observer.observe(opts.container, { childList: true, subtree: true }) + return + } + + observeRoot(root) +} diff --git a/packages/ui/src/pierre/file-selection.ts b/packages/ui/src/pierre/file-selection.ts new file mode 100644 index 0000000000..fdc34729e7 --- /dev/null +++ b/packages/ui/src/pierre/file-selection.ts @@ -0,0 +1,85 @@ +import { type SelectedLineRange } from "@pierre/diffs" +import { toRange } from "./selection-bridge" + +export function findElement(node: Node | null): HTMLElement | undefined { + if (!node) return + if (node instanceof HTMLElement) return node + return node.parentElement ?? undefined +} + +export function findFileLineNumber(node: Node | null): number | undefined { + const el = findElement(node) + if (!el) return + + const line = el.closest("[data-line]") + if (!(line instanceof HTMLElement)) return + + const value = parseInt(line.dataset.line ?? "", 10) + if (Number.isNaN(value)) return + return value +} + +export function findDiffLineNumber(node: Node | null): number | undefined { + const el = findElement(node) + if (!el) return + + const line = el.closest("[data-line], [data-alt-line]") + if (!(line instanceof HTMLElement)) return + + const primary = parseInt(line.dataset.line ?? "", 10) + if (!Number.isNaN(primary)) return primary + + const alt = parseInt(line.dataset.altLine ?? "", 10) + if (!Number.isNaN(alt)) return alt +} + +export function findCodeSelectionSide(node: Node | null): SelectedLineRange["side"] { + const el = findElement(node) + if (!el) return + + const code = el.closest("[data-code]") + if (!(code instanceof HTMLElement)) return + if (code.hasAttribute("data-deletions")) return "deletions" + return "additions" +} + +export function readShadowLineSelection(opts: { + root: ShadowRoot + lineForNode: (node: Node | null) => number | undefined + sideForNode?: (node: Node | null) => SelectedLineRange["side"] + preserveTextSelection?: boolean +}) { + const selection = + (opts.root as unknown as { getSelection?: () => Selection | null }).getSelection?.() ?? window.getSelection() + if (!selection || selection.isCollapsed) return + + const domRange = + ( + selection as unknown as { + getComposedRanges?: (options?: { shadowRoots?: ShadowRoot[] }) => StaticRange[] + } + ).getComposedRanges?.({ shadowRoots: [opts.root] })?.[0] ?? + (selection.rangeCount > 0 ? selection.getRangeAt(0) : undefined) + + const startNode = domRange?.startContainer ?? selection.anchorNode + const endNode = domRange?.endContainer ?? selection.focusNode + if (!startNode || !endNode) return + if (!opts.root.contains(startNode) || !opts.root.contains(endNode)) return + + const start = opts.lineForNode(startNode) + const end = opts.lineForNode(endNode) + if (start === undefined || end === undefined) return + + const startSide = opts.sideForNode?.(startNode) + const endSide = opts.sideForNode?.(endNode) + const side = startSide ?? endSide + + const range: SelectedLineRange = { start, end } + if (side) range.side = side + if (endSide && side && endSide !== side) range.endSide = endSide + + return { + range, + text: opts.preserveTextSelection && domRange ? toRange(domRange).cloneRange() : undefined, + } +} diff --git a/packages/ui/src/pierre/index.ts b/packages/ui/src/pierre/index.ts index f226a9ae13..22586f0f58 100644 --- a/packages/ui/src/pierre/index.ts +++ b/packages/ui/src/pierre/index.ts @@ -1,5 +1,6 @@ import { DiffLineAnnotation, FileContents, FileDiffOptions, type SelectedLineRange } from "@pierre/diffs" import { ComponentProps } from "solid-js" +import { lineCommentStyles } from "../components/line-comment-styles" export type DiffProps<T = {}> = FileDiffOptions<T> & { before: FileContents @@ -7,13 +8,15 @@ export type DiffProps<T = {}> = FileDiffOptions<T> & { annotations?: DiffLineAnnotation<T>[] selectedLines?: SelectedLineRange | null commentedLines?: SelectedLineRange[] + onLineNumberSelectionEnd?: (selection: SelectedLineRange | null) => void onRendered?: () => void class?: string classList?: ComponentProps<"div">["classList"] } const unsafeCSS = ` -[data-diff] { +[data-diff], +[data-file] { --diffs-bg: light-dark(var(--diffs-light-bg), var(--diffs-dark-bg)); --diffs-bg-buffer: var(--diffs-bg-buffer-override, light-dark( color-mix(in lab, var(--diffs-bg) 92%, var(--diffs-mixer)), color-mix(in lab, var(--diffs-bg) 92%, var(--diffs-mixer)))); --diffs-bg-hover: var(--diffs-bg-hover-override, light-dark( color-mix(in lab, var(--diffs-bg) 97%, var(--diffs-mixer)), color-mix(in lab, var(--diffs-bg) 91%, var(--diffs-mixer)))); @@ -44,7 +47,8 @@ const unsafeCSS = ` --diffs-bg-selection-text: rgb(from var(--surface-warning-strong) r g b / 0.2); } -:host([data-color-scheme='dark']) [data-diff] { +:host([data-color-scheme='dark']) [data-diff], +:host([data-color-scheme='dark']) [data-file] { --diffs-selection-number-fg: #fdfbfb; --diffs-bg-selection: var(--diffs-bg-selection-override, rgb(from var(--solaris-dark-6) r g b / 0.65)); --diffs-bg-selection-number: var( @@ -53,7 +57,8 @@ const unsafeCSS = ` ); } -[data-diff] ::selection { +[data-diff] ::selection, +[data-file] ::selection { background-color: var(--diffs-bg-selection-text); } @@ -69,25 +74,48 @@ const unsafeCSS = ` box-shadow: inset 0 0 0 9999px var(--diffs-bg-selection); } +[data-file] [data-line][data-comment-selected]:not([data-selected-line]) { + box-shadow: inset 0 0 0 9999px var(--diffs-bg-selection); +} + [data-diff] [data-column-number][data-comment-selected]:not([data-selected-line]) { box-shadow: inset 0 0 0 9999px var(--diffs-bg-selection-number); color: var(--diffs-selection-number-fg); } +[data-file] [data-column-number][data-comment-selected]:not([data-selected-line]) { + box-shadow: inset 0 0 0 9999px var(--diffs-bg-selection-number); + color: var(--diffs-selection-number-fg); +} + [data-diff] [data-line-annotation][data-comment-selected]:not([data-selected-line]) [data-annotation-content] { box-shadow: inset 0 0 0 9999px var(--diffs-bg-selection); } +[data-file] [data-line-annotation][data-comment-selected]:not([data-selected-line]) [data-annotation-content] { + box-shadow: inset 0 0 0 9999px var(--diffs-bg-selection); +} + [data-diff] [data-line][data-selected-line] { background-color: var(--diffs-bg-selection); box-shadow: inset 2px 0 0 var(--diffs-selection-border); } +[data-file] [data-line][data-selected-line] { + background-color: var(--diffs-bg-selection); + box-shadow: inset 2px 0 0 var(--diffs-selection-border); +} + [data-diff] [data-column-number][data-selected-line] { background-color: var(--diffs-bg-selection-number); color: var(--diffs-selection-number-fg); } +[data-file] [data-column-number][data-selected-line] { + background-color: var(--diffs-bg-selection-number); + color: var(--diffs-selection-number-fg); +} + [data-diff] [data-column-number][data-line-type='context'][data-selected-line], [data-diff] [data-column-number][data-line-type='context-expanded'][data-selected-line], [data-diff] [data-column-number][data-line-type='change-addition'][data-selected-line], @@ -123,9 +151,13 @@ const unsafeCSS = ` } [data-code] { overflow-x: auto !important; - overflow-y: hidden !important; + overflow-y: clip !important; } -}` +} + +${lineCommentStyles} + +` export function createDefaultOptions<T>(style: FileDiffOptions<T>["diffStyle"]) { return { diff --git a/packages/ui/src/pierre/media.ts b/packages/ui/src/pierre/media.ts new file mode 100644 index 0000000000..1ee63c25ba --- /dev/null +++ b/packages/ui/src/pierre/media.ts @@ -0,0 +1,110 @@ +import type { FileContent } from "@opencode-ai/sdk/v2" + +export type MediaKind = "image" | "audio" | "svg" + +const imageExtensions = new Set(["png", "jpg", "jpeg", "gif", "webp", "avif", "bmp", "ico", "tif", "tiff", "heic"]) +const audioExtensions = new Set(["mp3", "wav", "ogg", "m4a", "aac", "flac", "opus"]) + +type MediaValue = unknown + +function mediaRecord(value: unknown) { + if (!value || typeof value !== "object") return + return value as Partial<FileContent> & { + content?: unknown + encoding?: unknown + mimeType?: unknown + type?: unknown + } +} + +export function normalizeMimeType(type: string | undefined) { + if (!type) return + const mime = type.split(";", 1)[0]?.trim().toLowerCase() + if (!mime) return + if (mime === "audio/x-aac") return "audio/aac" + if (mime === "audio/x-m4a") return "audio/mp4" + return mime +} + +export function fileExtension(path: string | undefined) { + if (!path) return "" + const idx = path.lastIndexOf(".") + if (idx === -1) return "" + return path.slice(idx + 1).toLowerCase() +} + +export function mediaKindFromPath(path: string | undefined): MediaKind | undefined { + const ext = fileExtension(path) + if (ext === "svg") return "svg" + if (imageExtensions.has(ext)) return "image" + if (audioExtensions.has(ext)) return "audio" +} + +export function isBinaryContent(value: MediaValue) { + return mediaRecord(value)?.type === "binary" +} + +function validDataUrl(value: string, kind: MediaKind) { + if (kind === "svg") return value.startsWith("data:image/svg+xml") ? value : undefined + if (kind === "image") return value.startsWith("data:image/") ? value : undefined + if (value.startsWith("data:audio/x-aac;")) return value.replace("data:audio/x-aac;", "data:audio/aac;") + if (value.startsWith("data:audio/x-m4a;")) return value.replace("data:audio/x-m4a;", "data:audio/mp4;") + if (value.startsWith("data:audio/")) return value +} + +export function dataUrlFromMediaValue(value: MediaValue, kind: MediaKind) { + if (!value) return + + if (typeof value === "string") { + return validDataUrl(value, kind) + } + + const record = mediaRecord(value) + if (!record) return + + if (typeof record.content !== "string") return + + const mime = normalizeMimeType(typeof record.mimeType === "string" ? record.mimeType : undefined) + if (!mime) return + + if (kind === "svg") { + if (mime !== "image/svg+xml") return + if (record.encoding === "base64") return `data:image/svg+xml;base64,${record.content}` + return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(record.content)}` + } + + if (kind === "image" && !mime.startsWith("image/")) return + if (kind === "audio" && !mime.startsWith("audio/")) return + if (record.encoding !== "base64") return + + return `data:${mime};base64,${record.content}` +} + +function decodeBase64Utf8(value: string) { + if (typeof atob !== "function") return + + try { + const raw = atob(value) + const bytes = Uint8Array.from(raw, (x) => x.charCodeAt(0)) + if (typeof TextDecoder === "function") return new TextDecoder().decode(bytes) + return raw + } catch {} +} + +export function svgTextFromValue(value: MediaValue) { + const record = mediaRecord(value) + if (!record) return + if (typeof record.content !== "string") return + + const mime = normalizeMimeType(typeof record.mimeType === "string" ? record.mimeType : undefined) + if (mime !== "image/svg+xml") return + if (record.encoding === "base64") return decodeBase64Utf8(record.content) + return record.content +} + +export function hasMediaValue(value: MediaValue) { + if (typeof value === "string") return value.length > 0 + const record = mediaRecord(value) + if (!record) return false + return typeof record.content === "string" && record.content.length > 0 +} diff --git a/packages/ui/src/pierre/selection-bridge.ts b/packages/ui/src/pierre/selection-bridge.ts new file mode 100644 index 0000000000..d493ead3d9 --- /dev/null +++ b/packages/ui/src/pierre/selection-bridge.ts @@ -0,0 +1,129 @@ +import { type SelectedLineRange } from "@pierre/diffs" + +type PointerMode = "none" | "text" | "numbers" +type Side = SelectedLineRange["side"] +type LineSpan = Pick<SelectedLineRange, "start" | "end"> + +export function formatSelectedLineLabel(range: LineSpan) { + const start = Math.min(range.start, range.end) + const end = Math.max(range.start, range.end) + if (start === end) return `line ${start}` + return `lines ${start}-${end}` +} + +export function previewSelectedLines(source: string, range: LineSpan) { + const start = Math.max(1, Math.min(range.start, range.end)) + const end = Math.max(range.start, range.end) + const lines = source.split("\n").slice(start - 1, end) + if (lines.length === 0) return + return lines.slice(0, 2).join("\n") +} + +export function cloneSelectedLineRange(range: SelectedLineRange): SelectedLineRange { + const next: SelectedLineRange = { + start: range.start, + end: range.end, + } + + if (range.side) next.side = range.side + if (range.endSide) next.endSide = range.endSide + return next +} + +export function lineInSelectedRange(range: SelectedLineRange | null | undefined, line: number, side?: Side) { + if (!range) return false + + const start = Math.min(range.start, range.end) + const end = Math.max(range.start, range.end) + if (line < start || line > end) return false + if (!side) return true + + const first = range.side + const last = range.endSide ?? first + if (!first && !last) return true + if (!first || !last) return (first ?? last) === side + if (first === last) return first === side + if (line === start) return first === side + if (line === end) return last === side + return true +} + +export function isSingleLineSelection(range: SelectedLineRange | null) { + if (!range) return false + return range.start === range.end && (range.endSide == null || range.endSide === range.side) +} + +export function toRange(source: Range | StaticRange): Range { + if (source instanceof Range) return source + const range = new Range() + range.setStart(source.startContainer, source.startOffset) + range.setEnd(source.endContainer, source.endOffset) + return range +} + +export function restoreShadowTextSelection(root: ShadowRoot | undefined, range: Range | undefined) { + if (!root || !range) return + + requestAnimationFrame(() => { + const selection = + (root as unknown as { getSelection?: () => Selection | null }).getSelection?.() ?? window.getSelection() + if (!selection) return + + try { + selection.removeAllRanges() + selection.addRange(range) + } catch {} + }) +} + +export function createLineNumberSelectionBridge() { + let mode: PointerMode = "none" + let line: number | undefined + let moved = false + let pending = false + + const clear = () => { + mode = "none" + line = undefined + moved = false + } + + return { + begin(numberColumn: boolean, next: number | undefined) { + if (!numberColumn) { + mode = "text" + return + } + + mode = "numbers" + line = next + moved = false + }, + track(buttons: number, next: number | undefined) { + if (mode !== "numbers") return false + + if ((buttons & 1) === 0) { + clear() + return true + } + + if (next !== undefined && line !== undefined && next !== line) moved = true + return true + }, + finish() { + const current = mode + pending = current === "numbers" && moved + clear() + return current + }, + consume(range: SelectedLineRange | null) { + const result = pending && !isSingleLineSelection(range) + pending = false + return result + }, + reset() { + pending = false + clear() + }, + } +} diff --git a/packages/ui/src/storybook/fixtures.ts b/packages/ui/src/storybook/fixtures.ts new file mode 100644 index 0000000000..59d4129709 --- /dev/null +++ b/packages/ui/src/storybook/fixtures.ts @@ -0,0 +1,51 @@ +export const diff = { + before: { + name: "src/greet.ts", + contents: `export function greet(name: string) { + return \`Hello, \${name}!\` +} +`, + }, + after: { + name: "src/greet.ts", + contents: `export function greet(name: string, excited = false) { + const message = \`Hello, \${name}!\` + return excited ? \`\${message}!!\` : message +} +`, + }, +} + +export const code = { + name: "src/calc.ts", + contents: `export function sum(values: number[]) { + return values.reduce((total, value) => total + value, 0) +} + +export function average(values: number[]) { + if (values.length === 0) return 0 + return sum(values) / values.length +} +`, +} + +export const markdown = [ + "# Markdown", + "", + "Use **Markdown** for rich text.", + "", + "## Highlights", + "- Headings, lists, and code blocks", + "- Inline `code` and links", + "", + "```ts", + "export const value = 42", + "```", + "", + "More at https://example.com/docs", +].join("\n") + +export const changes = { + additions: 18, + deletions: 6, +} diff --git a/packages/ui/src/storybook/scaffold.tsx b/packages/ui/src/storybook/scaffold.tsx new file mode 100644 index 0000000000..2512aa09be --- /dev/null +++ b/packages/ui/src/storybook/scaffold.tsx @@ -0,0 +1,62 @@ +import { ErrorBoundary, type ValidComponent } from "solid-js" +import { Dynamic } from "solid-js/web" + +function fn(value: unknown): value is (...args: never[]) => unknown { + return typeof value === "function" +} + +function pick(mod: Record<string, unknown>, name?: string) { + if (name && fn(mod[name])) return mod[name] + if (fn(mod.default)) return mod.default + + const preferred = Object.keys(mod) + .filter((k) => k[0] && k[0] === k[0].toUpperCase()) + .find((k) => fn(mod[k])) + if (preferred) return mod[preferred] + + const first = Object.keys(mod).find((k) => fn(mod[k])) + if (first) return mod[first] + + return () => { + return ( + <div data-component="storybook-missing"> + <div>Missing component export.</div> + <div style="opacity:0.7;font-size:12px">Exports: {Object.keys(mod).join(", ") || "(none)"}</div> + </div> + ) + } +} + +export function create(input: { + title: string + mod: Record<string, unknown> + name?: string + args?: Record<string, unknown> +}) { + const component = pick(input.mod, input.name) as unknown as ValidComponent + + return { + meta: { + title: input.title, + component, + }, + Basic: { + args: input.args ?? {}, + render: (args: Record<string, unknown>) => { + return ( + <ErrorBoundary + fallback={(err) => { + return ( + <pre data-component="storybook-error" style="white-space:pre-wrap"> + {String(err)} + </pre> + ) + }} + > + <Dynamic component={component} {...args} /> + </ErrorBoundary> + ) + }, + }, + } +} diff --git a/packages/ui/src/styles/animations.css b/packages/ui/src/styles/animations.css index f8d11e0e50..f9a09df379 100644 --- a/packages/ui/src/styles/animations.css +++ b/packages/ui/src/styles/animations.css @@ -26,10 +26,10 @@ @keyframes pulse-opacity-dim { 0%, 100% { - opacity: 0; + opacity: 0.15; } 50% { - opacity: 0.2; + opacity: 0.35; } } diff --git a/packages/ui/src/styles/base.css b/packages/ui/src/styles/base.css index 33a2457058..b5604ad619 100644 --- a/packages/ui/src/styles/base.css +++ b/packages/ui/src/styles/base.css @@ -86,6 +86,17 @@ a { app-region: drag; } +*[data-tauri-drag-region] button, +*[data-tauri-drag-region] a, +*[data-tauri-drag-region] input, +*[data-tauri-drag-region] textarea, +*[data-tauri-drag-region] select, +*[data-tauri-drag-region] [role="button"], +*[data-tauri-drag-region] [role="menuitem"], +*[data-tauri-drag-region] [contenteditable] { + app-region: no-drag; +} + /* Add the correct font weight in Edge and Safari. */ diff --git a/packages/ui/src/styles/index.css b/packages/ui/src/styles/index.css index c0af0ac9b4..cec42f5a0c 100644 --- a/packages/ui/src/styles/index.css +++ b/packages/ui/src/styles/index.css @@ -7,15 +7,15 @@ @import "katex/dist/katex.min.css" layer(base); @import "../components/accordion.css" layer(components); +@import "../components/animated-number.css" layer(components); @import "../components/app-icon.css" layer(components); @import "../components/avatar.css" layer(components); @import "../components/basic-tool.css" layer(components); @import "../components/button.css" layer(components); @import "../components/card.css" layer(components); @import "../components/checkbox.css" layer(components); -@import "../components/code.css" layer(components); +@import "../components/file.css" layer(components); @import "../components/collapsible.css" layer(components); -@import "../components/diff.css" layer(components); @import "../components/diff-changes.css" layer(components); @import "../components/context-menu.css" layer(components); @import "../components/dropdown-menu.css" layer(components); @@ -28,7 +28,6 @@ @import "../components/icon-button.css" layer(components); @import "../components/image-preview.css" layer(components); @import "../components/keybind.css" layer(components); -@import "../components/line-comment.css" layer(components); @import "../components/text-field.css" layer(components); @import "../components/inline-input.css" layer(components); @import "../components/list.css" layer(components); @@ -47,10 +46,16 @@ @import "../components/scroll-view.css" layer(components); @import "../components/session-review.css" layer(components); @import "../components/session-turn.css" layer(components); +@import "../components/shell-submessage.css" layer(components); @import "../components/sticky-accordion-header.css" layer(components); @import "../components/tabs.css" layer(components); @import "../components/tag.css" layer(components); +@import "../components/text-reveal.css" layer(components); +@import "../components/text-strikethrough.css" layer(components); @import "../components/text-shimmer.css" layer(components); +@import "../components/tool-count-label.css" layer(components); +@import "../components/tool-count-summary.css" layer(components); +@import "../components/tool-status-title.css" layer(components); @import "../components/toast.css" layer(components); @import "../components/tooltip.css" layer(components); @import "../components/typewriter.css" layer(components); diff --git a/packages/ui/src/styles/tailwind/colors.css b/packages/ui/src/styles/tailwind/colors.css index 376cd35d32..e43f199ea5 100644 --- a/packages/ui/src/styles/tailwind/colors.css +++ b/packages/ui/src/styles/tailwind/colors.css @@ -1,4 +1,4 @@ -/* Generated by script/colors.ts */ +/* Generated by script/tailwind.ts */ /* Do not edit this file manually */ @theme { @@ -77,10 +77,6 @@ --color-text-weaker: var(--text-weaker); --color-text-strong: var(--text-strong); --color-text-interactive-base: var(--text-interactive-base); - --color-text-invert-base: var(--text-invert-base); - --color-text-invert-weak: var(--text-invert-weak); - --color-text-invert-weaker: var(--text-invert-weaker); - --color-text-invert-strong: var(--text-invert-strong); --color-text-on-brand-base: var(--text-on-brand-base); --color-text-on-interactive-base: var(--text-on-interactive-base); --color-text-on-interactive-weak: var(--text-on-interactive-weak); @@ -123,6 +119,7 @@ --color-border-weak-selected: var(--border-weak-selected); --color-border-weak-disabled: var(--border-weak-disabled); --color-border-weak-focus: var(--border-weak-focus); + --color-border-weaker-base: var(--border-weaker-base); --color-border-interactive-base: var(--border-interactive-base); --color-border-interactive-hover: var(--border-interactive-hover); --color-border-interactive-active: var(--border-interactive-active); @@ -233,12 +230,6 @@ --color-markdown-image-text: var(--markdown-image-text); --color-markdown-code-block: var(--markdown-code-block); --color-border-color: var(--border-color); - --color-border-weaker-base: var(--border-weaker-base); - --color-border-weaker-hover: var(--border-weaker-hover); - --color-border-weaker-active: var(--border-weaker-active); - --color-border-weaker-selected: var(--border-weaker-selected); - --color-border-weaker-disabled: var(--border-weaker-disabled); - --color-border-weaker-focus: var(--border-weaker-focus); --color-button-ghost-hover: var(--button-ghost-hover); --color-button-ghost-hover2: var(--button-ghost-hover2); } diff --git a/packages/ui/src/styles/theme.css b/packages/ui/src/styles/theme.css index 832b43ec74..702d1e4e67 100644 --- a/packages/ui/src/styles/theme.css +++ b/packages/ui/src/styles/theme.css @@ -89,205 +89,214 @@ color-scheme: light; --text-mix-blend-mode: multiply; - /* OC-1 fallback variables (light) */ - --background-base: #f8f7f7; - --background-weak: var(--smoke-light-3); - --background-strong: var(--smoke-light-1); + /* OC-2 fallback variables (light) */ + --background-base: #f8f8f8; + --background-weak: #f3f3f3; + --background-strong: #fcfcfc; --background-stronger: #fcfcfc; - --surface-base: var(--smoke-light-alpha-2); - --base: var(--smoke-light-alpha-2); - --surface-base-hover: #0500000f; - --surface-base-active: var(--smoke-light-alpha-3); - --surface-base-interactive-active: var(--cobalt-light-alpha-3); - --base2: var(--smoke-light-alpha-2); - --base3: var(--smoke-light-alpha-2); - --surface-inset-base: var(--smoke-light-alpha-2); - --surface-inset-base-hover: var(--smoke-light-alpha-3); - --surface-inset-strong: #1f000017; - --surface-inset-strong-hover: #1f000017; - --surface-raised-base: var(--smoke-light-alpha-1); - --surface-float-base: var(--smoke-dark-1); - --surface-float-base-hover: var(--smoke-dark-2); - --surface-raised-base-hover: var(--smoke-light-alpha-2); - --surface-raised-base-active: var(--smoke-light-alpha-3); - --surface-raised-strong: var(--smoke-light-1); - --surface-raised-strong-hover: var(--white); - --surface-raised-stronger: var(--white); - --surface-raised-stronger-hover: var(--white); - --surface-weak: var(--smoke-light-alpha-3); - --surface-weaker: var(--smoke-light-alpha-4); + --surface-base: rgba(0, 0, 0, 0.031); + --base: rgba(0, 0, 0, 0.034); + --surface-base-hover: rgba(0, 0, 0, 0.059); + --surface-base-active: rgba(0, 0, 0, 0.051); + --surface-base-interactive-active: rgba(3, 76, 255, 0.09); + --base2: rgba(0, 0, 0, 0.034); + --base3: rgba(0, 0, 0, 0.034); + --surface-inset-base: rgba(0, 0, 0, 0.034); + --surface-inset-base-hover: rgba(0, 0, 0, 0.055); + --surface-inset-strong: rgba(0, 0, 0, 0.09); + --surface-inset-strong-hover: rgba(0, 0, 0, 0.09); + --surface-raised-base: rgba(0, 0, 0, 0.031); + --surface-float-base: #161616; + --surface-float-base-hover: #1c1c1c; + --surface-raised-base-hover: rgba(0, 0, 0, 0.051); + --surface-raised-base-active: rgba(0, 0, 0, 0.09); + --surface-raised-strong: #fcfcfc; + --surface-raised-strong-hover: #ffffff; + --surface-raised-stronger: #ffffff; + --surface-raised-stronger-hover: #ffffff; + --surface-weak: rgba(0, 0, 0, 0.051); + --surface-weaker: rgba(0, 0, 0, 0.071); --surface-strong: #ffffff; --surface-stronger-non-alpha: var(--surface-raised-stronger-non-alpha); - --surface-raised-stronger-non-alpha: var(--white); - --surface-brand-base: var(--yuzu-light-9); - --surface-brand-hover: var(--yuzu-light-10); - --surface-interactive-base: var(--cobalt-light-3); - --surface-interactive-hover: #e5f0ff; - --surface-interactive-weak: var(--cobalt-light-2); - --surface-interactive-weak-hover: var(--cobalt-light-3); - --surface-success-base: var(--apple-light-3); - --surface-success-weak: var(--apple-light-2); - --surface-success-strong: var(--apple-light-9); - --surface-warning-base: var(--solaris-light-3); - --surface-warning-weak: var(--solaris-light-2); - --surface-warning-strong: var(--solaris-light-9); - --surface-critical-base: var(--ember-light-3); - --surface-critical-weak: var(--ember-light-2); - --surface-critical-strong: var(--ember-light-9); - --surface-info-base: var(--lilac-light-3); - --surface-info-weak: var(--lilac-light-2); - --surface-info-strong: var(--lilac-light-9); + --surface-raised-stronger-non-alpha: #ffffff; + --surface-brand-base: #dcde8d; + --surface-brand-hover: #d0d283; + --surface-interactive-base: #ecf3ff; + --surface-interactive-hover: #e0eaff; + --surface-interactive-weak: #f7faff; + --surface-interactive-weak-hover: #ecf3ff; + --surface-success-base: #dbfed7; + --surface-success-weak: #f0feee; + --surface-success-strong: #12c905; + --surface-warning-base: #fcf3cb; + --surface-warning-weak: #fdfaec; + --surface-warning-strong: #fbdd46; + --surface-critical-base: #feefeb; + --surface-critical-weak: #fff8f6; + --surface-critical-strong: #fc533a; + --surface-info-base: #fdecfe; + --surface-info-weak: #fef7ff; + --surface-info-strong: #a753ae; --surface-diff-unchanged-base: #ffffff00; - --surface-diff-skip-base: var(--smoke-light-2); - --surface-diff-hidden-base: var(--blue-light-3); - --surface-diff-hidden-weak: var(--blue-light-2); - --surface-diff-hidden-weaker: var(--blue-light-1); - --surface-diff-hidden-strong: var(--blue-light-5); - --surface-diff-hidden-stronger: var(--blue-light-9); - --surface-diff-add-base: #dafbe0; - --surface-diff-add-weak: var(--mint-light-2); - --surface-diff-add-weaker: var(--mint-light-1); - --surface-diff-add-strong: var(--mint-light-5); - --surface-diff-add-stronger: var(--mint-light-9); - --surface-diff-delete-base: var(--ember-light-3); - --surface-diff-delete-weak: var(--ember-light-2); - --surface-diff-delete-weaker: var(--ember-light-1); - --surface-diff-delete-strong: var(--ember-light-6); - --surface-diff-delete-stronger: var(--ember-light-9); - --input-base: var(--smoke-light-1); - --input-hover: var(--smoke-light-2); - --input-active: var(--cobalt-light-1); - --input-selected: var(--cobalt-light-4); - --input-focus: var(--cobalt-light-1); - --input-disabled: var(--smoke-light-4); - --text-base: var(--smoke-light-11); - --text-weak: var(--smoke-light-9); - --text-weaker: var(--smoke-light-8); - --text-strong: var(--smoke-light-12); - --text-invert-base: var(--smoke-dark-alpha-11); - --text-invert-weak: var(--smoke-dark-alpha-9); - --text-invert-weaker: var(--smoke-dark-alpha-8); - --text-invert-strong: var(--smoke-dark-alpha-12); - --text-interactive-base: var(--cobalt-light-9); - --text-on-brand-base: var(--smoke-light-alpha-11); - --text-on-interactive-base: var(--smoke-light-1); - --text-on-interactive-weak: var(--smoke-dark-alpha-11); - --text-on-success-base: var(--apple-light-10); - --text-on-critical-base: var(--ember-light-10); - --text-on-critical-weak: var(--ember-light-8); - --text-on-critical-strong: var(--ember-light-12); - --text-on-warning-base: var(--smoke-dark-alpha-11); - --text-on-info-base: var(--smoke-dark-alpha-11); - --text-diff-add-base: var(--mint-light-11); - --text-diff-delete-base: var(--ember-light-10); - --text-diff-delete-strong: var(--ember-light-12); - --text-diff-add-strong: var(--mint-light-12); - --text-on-info-weak: var(--smoke-dark-alpha-9); - --text-on-info-strong: var(--smoke-dark-alpha-12); - --text-on-warning-weak: var(--smoke-dark-alpha-9); - --text-on-warning-strong: var(--smoke-dark-alpha-12); - --text-on-success-weak: var(--apple-light-6); - --text-on-success-strong: var(--apple-light-12); - --text-on-brand-weak: var(--smoke-light-alpha-9); - --text-on-brand-weaker: var(--smoke-light-alpha-8); - --text-on-brand-strong: var(--smoke-light-alpha-12); - --button-primary-base: var(--smoke-light-12); - --button-secondary-base: #fdfcfc; - --button-secondary-hover: #faf9f9; - --border-base: var(--smoke-light-alpha-7); - --border-hover: var(--smoke-light-alpha-8); - --border-active: var(--smoke-light-alpha-9); - --border-selected: var(--cobalt-light-alpha-9); - --border-disabled: var(--smoke-light-alpha-8); - --border-focus: var(--smoke-light-alpha-9); - --border-weak-base: var(--smoke-light-alpha-5); - --border-strong-base: var(--smoke-light-alpha-7); - --border-strong-hover: var(--smoke-light-alpha-8); - --border-strong-active: var(--smoke-light-alpha-7); - --border-strong-selected: var(--cobalt-light-alpha-6); - --border-strong-disabled: var(--smoke-light-alpha-6); - --border-strong-focus: var(--smoke-light-alpha-7); - --border-weak-hover: var(--smoke-light-alpha-6); - --border-weak-active: var(--smoke-light-alpha-7); - --border-weak-selected: var(--cobalt-light-alpha-5); - --border-weak-disabled: var(--smoke-light-alpha-6); - --border-weak-focus: var(--smoke-light-alpha-7); - --border-interactive-base: var(--cobalt-light-7); - --border-interactive-hover: var(--cobalt-light-8); - --border-interactive-active: var(--cobalt-light-9); - --border-interactive-selected: var(--cobalt-light-9); - --border-interactive-disabled: var(--smoke-light-8); - --border-interactive-focus: var(--cobalt-light-9); - --border-success-base: var(--apple-light-6); - --border-success-hover: var(--apple-light-7); - --border-success-selected: var(--apple-light-9); - --border-warning-base: var(--solaris-light-6); - --border-warning-hover: var(--solaris-light-7); - --border-warning-selected: var(--solaris-light-9); - --border-critical-base: var(--ember-light-6); - --border-critical-hover: var(--ember-light-7); - --border-critical-selected: var(--ember-light-9); - --border-info-base: var(--lilac-light-6); - --border-info-hover: var(--lilac-light-7); - --border-info-selected: var(--lilac-light-9); - --icon-base: var(--smoke-light-9); - --icon-hover: var(--smoke-light-11); - --icon-active: var(--smoke-light-12); - --icon-selected: var(--smoke-light-12); - --icon-disabled: var(--smoke-light-8); - --icon-focus: var(--smoke-light-12); + --surface-diff-skip-base: #f8f8f8; + --surface-diff-hidden-base: #eaf4ff; + --surface-diff-hidden-weak: #f6faff; + --surface-diff-hidden-weaker: #fbfdff; + --surface-diff-hidden-strong: #cae3ff; + --surface-diff-hidden-stronger: #2090f5; + --surface-diff-add-base: #e3fae1; + --surface-diff-add-weak: #f4fcf3; + --surface-diff-add-weaker: #fbfefb; + --surface-diff-add-strong: #c2eebf; + --surface-diff-add-stronger: #9ff29a; + --surface-diff-delete-base: #feefeb; + --surface-diff-delete-weak: #fff8f6; + --surface-diff-delete-weaker: #fffcfb; + --surface-diff-delete-strong: #fdc3b7; + --surface-diff-delete-stronger: #fc533a; + --input-base: #fcfcfc; + --input-hover: #f8f8f8; + --input-active: #fcfdff; + --input-selected: #e0eaff; + --input-focus: #fcfdff; + --input-disabled: #ededed; + --text-base: #6f6f6f; + --text-weak: #8f8f8f; + --text-weaker: #c7c7c7; + --text-strong: #171717; + --text-invert-base: #f8f8f8; + --text-invert-weak: #f3f3f3; + --text-invert-weaker: #ededed; + --text-invert-strong: #fcfcfc; + --text-interactive-base: #034cff; + --text-on-brand-base: rgba(0, 0, 0, 0.574); + --text-on-interactive-base: #fcfcfc; + --text-on-interactive-weak: rgba(0, 0, 0, 0.574); + --text-on-success-base: #2dba26; + --text-on-critical-base: #ed4831; + --text-on-critical-weak: #fe806a; + --text-on-critical-strong: #601a0f; + --text-on-warning-base: rgba(0, 0, 0, 0.574); + --text-on-info-base: rgba(0, 0, 0, 0.574); + --text-diff-add-base: #3a8437; + --text-diff-delete-base: #ed4831; + --text-diff-delete-strong: #601a0f; + --text-diff-add-strong: #1d3e1c; + --text-on-info-weak: rgba(0, 0, 0, 0.453); + --text-on-info-strong: rgba(0, 0, 0, 0.915); + --text-on-warning-weak: rgba(0, 0, 0, 0.453); + --text-on-warning-strong: rgba(0, 0, 0, 0.915); + --text-on-success-weak: #96ec8e; + --text-on-success-strong: #044202; + --text-on-brand-weak: rgba(0, 0, 0, 0.453); + --text-on-brand-weaker: rgba(0, 0, 0, 0.232); + --text-on-brand-strong: rgba(0, 0, 0, 0.915); + --button-primary-base: #171717; + --button-secondary-base: #fcfcfc; + --button-secondary-hover: #f8f8f8; + --button-ghost-hover: rgba(0, 0, 0, 0.031); + --button-ghost-hover2: rgba(0, 0, 0, 0.051); + --border-base: rgba(0, 0, 0, 0.162); + --border-hover: rgba(0, 0, 0, 0.236); + --border-active: rgba(0, 0, 0, 0.46); + --border-selected: rgba(3, 76, 255, 0.99); + --border-disabled: rgba(0, 0, 0, 0.236); + --border-focus: rgba(0, 0, 0, 0.46); + --border-weak-base: #e5e5e5; + --border-strong-base: rgba(0, 0, 0, 0.151); + --border-strong-hover: rgba(0, 0, 0, 0.232); + --border-strong-active: rgba(0, 0, 0, 0.151); + --border-strong-selected: rgba(3, 76, 255, 0.31); + --border-strong-disabled: rgba(0, 0, 0, 0.118); + --border-strong-focus: rgba(0, 0, 0, 0.151); + --border-weak-hover: rgba(0, 0, 0, 0.118); + --border-weak-active: rgba(0, 0, 0, 0.151); + --border-weak-selected: rgba(3, 76, 255, 0.24); + --border-weak-disabled: rgba(0, 0, 0, 0.118); + --border-weak-focus: rgba(0, 0, 0, 0.151); + --border-weaker-base: #f0f0f0; + --border-weaker-hover: rgba(0, 0, 0, 0.075); + --border-weaker-active: rgba(0, 0, 0, 0.118); + --border-weaker-selected: rgba(3, 76, 255, 0.16); + --border-weaker-disabled: rgba(0, 0, 0, 0.034); + --border-weaker-focus: rgba(0, 0, 0, 0.118); + --border-interactive-base: #a3c1fd; + --border-interactive-hover: #7ea9ff; + --border-interactive-active: #034cff; + --border-interactive-selected: #034cff; + --border-interactive-disabled: #c7c7c7; + --border-interactive-focus: #034cff; + --border-success-base: #96ec8e; + --border-success-hover: #7add71; + --border-success-selected: #12c905; + --border-warning-base: #e8d479; + --border-warning-hover: #d8c158; + --border-warning-selected: #fbdd46; + --border-critical-base: #fdc3b7; + --border-critical-hover: #ffa796; + --border-critical-selected: #fc533a; + --border-info-base: #f4bdf8; + --border-info-hover: #e6a8ea; + --border-info-selected: #a753ae; + --border-color: #ffffff; + --icon-base: #8f8f8f; + --icon-hover: #6f6f6f; + --icon-active: #171717; + --icon-selected: #171717; + --icon-disabled: #c7c7c7; + --icon-focus: #171717; --icon-invert-base: #ffffff; - --icon-weak-base: var(--smoke-light-7); - --icon-weak-hover: var(--smoke-light-8); - --icon-weak-active: var(--smoke-light-9); - --icon-weak-selected: var(--smoke-light-10); - --icon-weak-disabled: var(--smoke-light-6); - --icon-weak-focus: var(--smoke-light-9); - --icon-strong-base: var(--smoke-light-12); + --icon-weak-base: #dbdbdb; + --icon-weak-hover: #c7c7c7; + --icon-weak-active: #8f8f8f; + --icon-weak-selected: #858585; + --icon-weak-disabled: #e2e2e2; + --icon-weak-focus: #8f8f8f; + --icon-strong-base: #171717; --icon-strong-hover: #151313; --icon-strong-active: #020202; --icon-strong-selected: #020202; - --icon-strong-disabled: var(--smoke-light-8); + --icon-strong-disabled: #c7c7c7; --icon-strong-focus: #020202; - --icon-brand-base: var(--smoke-light-12); - --icon-interactive-base: var(--cobalt-light-9); - --icon-success-base: var(--apple-light-7); - --icon-success-hover: var(--apple-light-8); - --icon-success-active: var(--apple-light-11); - --icon-warning-base: var(--amber-light-9); - --icon-warning-hover: var(--amber-light-8); - --icon-warning-active: var(--amber-light-11); - --icon-critical-base: var(--ember-light-10); - --icon-critical-hover: var(--ember-light-11); - --icon-critical-active: var(--ember-light-12); - --icon-info-base: var(--lilac-light-7); - --icon-info-hover: var(--lilac-light-8); - --icon-info-active: var(--lilac-light-11); - --icon-on-brand-base: var(--smoke-light-alpha-11); - --icon-on-brand-hover: var(--smoke-light-alpha-12); - --icon-on-brand-selected: var(--smoke-light-alpha-12); - --icon-on-interactive-base: var(--smoke-light-1); - --icon-agent-plan-base: var(--purple-light-9); - --icon-agent-docs-base: var(--amber-light-9); - --icon-agent-ask-base: var(--cyan-light-9); - --icon-agent-build-base: var(--cobalt-light-9); - --icon-on-success-base: var(--apple-light-alpha-9); - --icon-on-success-hover: var(--apple-light-alpha-10); - --icon-on-success-selected: var(--apple-light-alpha-11); - --icon-on-warning-base: var(--amber-lightalpha-9); - --icon-on-warning-hover: var(--amber-lightalpha-10); - --icon-on-warning-selected: var(--amber-lightalpha-11); - --icon-on-critical-base: var(--ember-light-alpha-9); - --icon-on-critical-hover: var(--ember-light-alpha-10); - --icon-on-critical-selected: var(--ember-light-alpha-11); - --icon-on-info-base: var(--lilac-light-9); - --icon-on-info-hover: var(--lilac-light-alpha-10); - --icon-on-info-selected: var(--lilac-light-alpha-11); - --icon-diff-add-base: var(--mint-light-11); - --icon-diff-add-hover: var(--mint-light-12); - --icon-diff-add-active: var(--mint-light-12); - --icon-diff-delete-base: var(--ember-light-10); - --icon-diff-delete-hover: var(--ember-light-11); + --icon-brand-base: #171717; + --icon-interactive-base: #034cff; + --icon-success-base: #7add71; + --icon-success-hover: #4cc944; + --icon-success-active: #078901; + --icon-warning-base: #ebb76e; + --icon-warning-hover: #da9e40; + --icon-warning-active: #95671b; + --icon-critical-base: #ed4831; + --icon-critical-hover: #ca2d17; + --icon-critical-active: #601a0f; + --icon-info-base: #e6a8ea; + --icon-info-hover: #d58cda; + --icon-info-active: #9b4da1; + --icon-on-brand-base: rgba(0, 0, 0, 0.574); + --icon-on-brand-hover: rgba(0, 0, 0, 0.915); + --icon-on-brand-selected: rgba(0, 0, 0, 0.915); + --icon-on-interactive-base: #fcfcfc; + --icon-agent-plan-base: #a753ae; + --icon-agent-docs-base: #fcb239; + --icon-agent-ask-base: #2090f5; + --icon-agent-build-base: #034cff; + --icon-on-success-base: rgba(18, 201, 5, 0.9); + --icon-on-success-hover: rgba(45, 186, 38, 0.9); + --icon-on-success-selected: rgba(7, 137, 1, 0.9); + --icon-on-warning-base: rgba(252, 178, 57, 0.9); + --icon-on-warning-hover: rgba(239, 167, 46, 0.9); + --icon-on-warning-selected: rgba(149, 103, 27, 0.9); + --icon-on-critical-base: rgba(252, 83, 58, 0.9); + --icon-on-critical-hover: rgba(237, 72, 49, 0.9); + --icon-on-critical-selected: rgba(202, 45, 23, 0.9); + --icon-on-info-base: #a753ae; + --icon-on-info-hover: rgba(155, 73, 162, 0.9); + --icon-on-info-selected: rgba(155, 77, 161, 0.9); + --icon-diff-add-base: #3a8437; + --icon-diff-add-hover: #1d3e1c; + --icon-diff-add-active: #1d3e1c; + --icon-diff-delete-base: #ed4831; + --icon-diff-delete-hover: #ca2d17; --icon-diff-modified-base: #ff8c00; --syntax-comment: var(--text-weak); --syntax-regexp: var(--text-base); @@ -301,12 +310,12 @@ --syntax-constant: #007b80; --syntax-punctuation: var(--text-base); --syntax-object: var(--text-strong); - --syntax-success: var(--apple-light-10); - --syntax-warning: var(--amber-light-10); - --syntax-critical: var(--ember-light-10); + --syntax-success: #2dba26; + --syntax-warning: #efa72e; + --syntax-critical: #ed4831; --syntax-info: #0092a8; - --syntax-diff-add: var(--mint-light-11); - --syntax-diff-delete: var(--ember-light-11); + --syntax-diff-add: #3a8437; + --syntax-diff-delete: #ca2d17; --syntax-diff-unknown: #ff0000; --markdown-heading: #d68c27; --markdown-text: #1a1a1a; @@ -322,15 +331,6 @@ --markdown-image: #3b7dd8; --markdown-image-text: #318795; --markdown-code-block: #1a1a1a; - --border-color: #ffffff; - --border-weaker-base: var(--smoke-light-alpha-3); - --border-weaker-hover: var(--smoke-light-alpha-4); - --border-weaker-active: var(--smoke-light-alpha-6); - --border-weaker-selected: var(--cobalt-light-alpha-4); - --border-weaker-disabled: var(--smoke-light-alpha-2); - --border-weaker-focus: var(--smoke-light-alpha-6); - --button-ghost-hover: var(--smoke-light-alpha-2); - --button-ghost-hover2: var(--smoke-light-alpha-3); --avatar-background-pink: #feeef8; --avatar-background-mint: #e1fbf4; --avatar-background-orange: #fff1e7; @@ -343,210 +343,220 @@ --avatar-text-purple: #8445bc; --avatar-text-cyan: #0894b3; --avatar-text-lime: #5d770d; + --text-stronger: #171717; @media (prefers-color-scheme: dark) { color-scheme: dark; --text-mix-blend-mode: plus-lighter; - /* OC-1 fallback variables (dark) */ - --background-base: var(--smoke-dark-1); - --background-weak: #1c1717; - --background-strong: #151313; - --background-stronger: #191515; - --surface-base: var(--smoke-dark-alpha-2); - --base: var(--smoke-dark-alpha-2); - --surface-base-hover: #e0b7b716; - --surface-base-active: var(--smoke-dark-alpha-3); - --surface-base-interactive-active: var(--cobalt-dark-alpha-2); - --base2: var(--smoke-dark-alpha-2); - --base3: var(--smoke-dark-alpha-2); - --surface-inset-base: #0e0b0b7f; - --surface-inset-base-hover: #0e0b0b7f; - --surface-inset-strong: #060505cc; - --surface-inset-strong-hover: #060505cc; - --surface-raised-base: var(--smoke-dark-alpha-3); - --surface-float-base: var(--smoke-dark-1); - --surface-float-base-hover: var(--smoke-dark-2); - --surface-raised-base-hover: var(--smoke-dark-alpha-4); - --surface-raised-base-active: var(--smoke-dark-alpha-5); - --surface-raised-strong: var(--smoke-dark-alpha-4); - --surface-raised-strong-hover: var(--smoke-dark-alpha-6); - --surface-raised-stronger: var(--smoke-dark-alpha-6); - --surface-raised-stronger-hover: var(--smoke-dark-alpha-7); - --surface-weak: var(--smoke-dark-alpha-4); - --surface-weaker: var(--smoke-dark-alpha-5); - --surface-strong: var(--smoke-dark-alpha-7); + /* OC-2 fallback variables (dark) */ + --background-base: #101010; + --background-weak: #1e1e1e; + --background-strong: #121212; + --background-stronger: #151515; + --surface-base: rgba(255, 255, 255, 0.031); + --base: rgba(255, 255, 255, 0.034); + --surface-base-hover: rgba(255, 255, 255, 0.039); + --surface-base-active: rgba(255, 255, 255, 0.059); + --surface-base-interactive-active: rgba(3, 76, 255, 0.125); + --base2: rgba(255, 255, 255, 0.034); + --base3: rgba(255, 255, 255, 0.034); + --surface-inset-base: rgba(0, 0, 0, 0.5); + --surface-inset-base-hover: rgba(0, 0, 0, 0.5); + --surface-inset-strong: rgba(0, 0, 0, 0.8); + --surface-inset-strong-hover: rgba(0, 0, 0, 0.8); + --surface-raised-base: rgba(255, 255, 255, 0.059); + --surface-float-base: #161616; + --surface-float-base-hover: #1c1c1c; + --surface-raised-base-hover: rgba(255, 255, 255, 0.078); + --surface-raised-base-active: rgba(255, 255, 255, 0.102); + --surface-raised-strong: rgba(255, 255, 255, 0.078); + --surface-raised-strong-hover: rgba(255, 255, 255, 0.129); + --surface-raised-stronger: rgba(255, 255, 255, 0.129); + --surface-raised-stronger-hover: rgba(255, 255, 255, 0.169); + --surface-weak: rgba(255, 255, 255, 0.078); + --surface-weaker: rgba(255, 255, 255, 0.102); + --surface-strong: rgba(255, 255, 255, 0.169); --surface-stronger-non-alpha: var(--surface-raised-stronger-non-alpha); - --surface-raised-stronger-non-alpha: var(--smoke-dark-3); - --surface-brand-base: var(--yuzu-light-9); - --surface-brand-hover: var(--yuzu-light-10); - --surface-interactive-base: var(--cobalt-dark-3); - --surface-interactive-hover: #0a1d4d; - --surface-interactive-weak: var(--cobalt-dark-2); - --surface-interactive-weak-hover: var(--cobalt-light-3); - --surface-success-base: var(--apple-light-3); - --surface-success-weak: var(--apple-light-2); - --surface-success-strong: var(--apple-light-9); - --surface-warning-base: var(--solaris-light-3); - --surface-warning-weak: var(--solaris-light-2); - --surface-warning-strong: var(--solaris-light-9); - --surface-critical-base: var(--ember-dark-3); - --surface-critical-weak: var(--ember-dark-2); - --surface-critical-strong: var(--ember-dark-9); - --surface-info-base: var(--lilac-light-3); - --surface-info-weak: var(--lilac-light-2); - --surface-info-strong: var(--lilac-light-9); - --surface-diff-unchanged-base: var(--smoke-dark-1); - --surface-diff-skip-base: var(--smoke-dark-alpha-1); - --surface-diff-hidden-base: var(--blue-dark-2); - --surface-diff-hidden-weak: var(--blue-dark-1); - --surface-diff-hidden-weaker: var(--blue-dark-3); - --surface-diff-hidden-strong: var(--blue-dark-5); - --surface-diff-hidden-stronger: var(--blue-dark-11); - --surface-diff-add-base: var(--mint-dark-3); - --surface-diff-add-weak: var(--mint-dark-4); - --surface-diff-add-weaker: var(--mint-dark-3); - --surface-diff-add-strong: var(--mint-dark-5); - --surface-diff-add-stronger: var(--mint-dark-11); - --surface-diff-delete-base: var(--ember-dark-3); - --surface-diff-delete-weak: var(--ember-dark-4); - --surface-diff-delete-weaker: var(--ember-dark-3); - --surface-diff-delete-strong: var(--ember-dark-5); - --surface-diff-delete-stronger: var(--ember-dark-11); - --input-base: var(--smoke-dark-2); - --input-hover: var(--smoke-dark-2); - --input-active: var(--cobalt-dark-1); - --input-selected: var(--cobalt-dark-2); - --input-focus: var(--cobalt-dark-1); - --input-disabled: var(--smoke-dark-4); - --text-base: var(--smoke-dark-alpha-11); - --text-weak: var(--smoke-dark-alpha-9); - --text-weaker: var(--smoke-dark-alpha-8); - --text-strong: var(--smoke-dark-alpha-12); - --text-invert-base: var(--smoke-dark-alpha-11); - --text-invert-weak: var(--smoke-dark-alpha-9); - --text-invert-weaker: var(--smoke-dark-alpha-8); - --text-invert-strong: var(--smoke-dark-alpha-12); - --text-interactive-base: var(--cobalt-dark-11); - --text-on-brand-base: var(--smoke-dark-alpha-11); - --text-on-interactive-base: var(--smoke-dark-12); - --text-on-interactive-weak: var(--smoke-dark-alpha-11); - --text-on-success-base: var(--apple-dark-9); - --text-on-critical-base: var(--ember-dark-9); - --text-on-critical-weak: var(--ember-dark-8); - --text-on-critical-strong: var(--ember-dark-12); - --text-on-warning-base: var(--smoke-dark-alpha-11); - --text-on-info-base: var(--smoke-dark-alpha-11); - --text-diff-add-base: var(--mint-dark-11); - --text-diff-delete-base: var(--ember-dark-9); - --text-diff-delete-strong: var(--ember-dark-12); - --text-diff-add-strong: var(--mint-dark-8); - --text-on-info-weak: var(--smoke-dark-alpha-9); - --text-on-info-strong: var(--smoke-dark-alpha-12); - --text-on-warning-weak: var(--smoke-dark-alpha-9); - --text-on-warning-strong: var(--smoke-dark-alpha-12); - --text-on-success-weak: var(--apple-dark-8); - --text-on-success-strong: var(--apple-dark-12); - --text-on-brand-weak: var(--smoke-dark-alpha-9); - --text-on-brand-weaker: var(--smoke-dark-alpha-8); - --text-on-brand-strong: var(--smoke-dark-alpha-12); - --button-primary-base: var(--smoke-dark-12); - --button-secondary-base: #231f1f; - --button-secondary-hover: #2a2727; - --border-base: var(--smoke-dark-alpha-7); - --border-hover: var(--smoke-dark-alpha-8); - --border-active: var(--smoke-dark-alpha-9); - --border-selected: var(--cobalt-dark-alpha-11); - --border-disabled: var(--smoke-dark-alpha-8); - --border-focus: var(--smoke-dark-alpha-9); - --border-weak-base: var(--smoke-dark-alpha-6); - --border-strong-base: var(--smoke-dark-alpha-8); - --border-strong-hover: var(--smoke-dark-alpha-7); - --border-strong-active: var(--smoke-dark-alpha-8); - --border-strong-selected: var(--cobalt-dark-alpha-6); - --border-strong-disabled: var(--smoke-dark-alpha-6); - --border-strong-focus: var(--smoke-dark-alpha-8); - --border-weak-hover: var(--smoke-dark-alpha-7); - --border-weak-active: var(--smoke-dark-alpha-8); - --border-weak-selected: var(--cobalt-dark-alpha-6); - --border-weak-disabled: var(--smoke-dark-alpha-6); - --border-weak-focus: var(--smoke-dark-alpha-8); - --border-interactive-base: var(--cobalt-light-7); - --border-interactive-hover: var(--cobalt-light-8); - --border-interactive-active: var(--cobalt-light-9); - --border-interactive-selected: var(--cobalt-light-9); - --border-interactive-disabled: var(--smoke-light-8); - --border-interactive-focus: var(--cobalt-light-9); - --border-success-base: var(--apple-light-6); - --border-success-hover: var(--apple-light-7); - --border-success-selected: var(--apple-light-9); - --border-warning-base: var(--solaris-light-6); - --border-warning-hover: var(--solaris-light-7); - --border-warning-selected: var(--solaris-light-9); - --border-critical-base: var(--ember-dark-5); - --border-critical-hover: var(--ember-dark-7); - --border-critical-selected: var(--ember-dark-9); - --border-info-base: var(--lilac-light-6); - --border-info-hover: var(--lilac-light-7); - --border-info-selected: var(--lilac-light-9); - --icon-base: var(--smoke-dark-9); - --icon-hover: var(--smoke-dark-10); - --icon-active: var(--smoke-dark-11); - --icon-selected: var(--smoke-dark-12); - --icon-disabled: var(--smoke-dark-7); - --icon-focus: var(--smoke-dark-12); - --icon-invert-base: var(--smoke-dark-1); - --icon-weak-base: var(--smoke-dark-6); - --icon-weak-hover: var(--smoke-light-7); - --icon-weak-active: var(--smoke-light-8); - --icon-weak-selected: var(--smoke-light-9); - --icon-weak-disabled: var(--smoke-light-4); - --icon-weak-focus: var(--smoke-light-9); - --icon-strong-base: var(--smoke-dark-12); + --surface-raised-stronger-non-alpha: #1c1c1c; + --surface-brand-base: #fab283; + --surface-brand-hover: #eda779; + --surface-interactive-base: #091f52; + --surface-interactive-hover: #091f52; + --surface-interactive-weak: #0b1730; + --surface-interactive-weak-hover: #ecf3ff; + --surface-success-base: #062d04; + --surface-success-weak: #0a1e08; + --surface-success-strong: #12c905; + --surface-warning-base: #fdf3cf; + --surface-warning-weak: #fdfaed; + --surface-warning-strong: #fcd53a; + --surface-critical-base: #42120b; + --surface-critical-weak: #28110c; + --surface-critical-strong: #fc533a; + --surface-info-base: #feecfe; + --surface-info-weak: #fdf7fe; + --surface-info-strong: #edb2f1; + --surface-diff-unchanged-base: #161616; + --surface-diff-skip-base: #00000000; + --surface-diff-hidden-base: #0c1928; + --surface-diff-hidden-weak: #09131d; + --surface-diff-hidden-weaker: #082542; + --surface-diff-hidden-strong: #073966; + --surface-diff-hidden-stronger: #8ec2fc; + --surface-diff-add-base: #1a2919; + --surface-diff-add-weak: #1f351e; + --surface-diff-add-weaker: #1a2919; + --surface-diff-add-strong: #264024; + --surface-diff-add-stronger: #9bcd97; + --surface-diff-delete-base: #42120b; + --surface-diff-delete-weak: #580f06; + --surface-diff-delete-weaker: #42120b; + --surface-diff-delete-strong: #6a1206; + --surface-diff-delete-stronger: #faa494; + --input-base: #1c1c1c; + --input-hover: #1c1c1c; + --input-active: #091123; + --input-selected: #0b1730; + --input-focus: #091123; + --input-disabled: #282828; + --text-base: rgba(255, 255, 255, 0.618); + --text-weak: rgba(255, 255, 255, 0.422); + --text-weaker: rgba(255, 255, 255, 0.284); + --text-strong: rgba(255, 255, 255, 0.936); + --text-invert-base: #a0a0a0; + --text-invert-weak: #707070; + --text-invert-weaker: #505050; + --text-invert-strong: #ededed; + --text-interactive-base: #9dbefe; + --text-on-brand-base: rgba(255, 255, 255, 0.603); + --text-on-interactive-base: #ededed; + --text-on-interactive-weak: rgba(255, 255, 255, 0.603); + --text-on-success-base: #12c905; + --text-on-critical-base: #fc533a; + --text-on-critical-weak: #b72d1a; + --text-on-critical-strong: #ffe0da; + --text-on-warning-base: rgba(255, 255, 255, 0.603); + --text-on-info-base: rgba(255, 255, 255, 0.603); + --text-diff-add-base: #9bcd97; + --text-diff-delete-base: #fc533a; + --text-diff-delete-strong: #ffe0da; + --text-diff-add-strong: #4a7348; + --text-on-info-weak: rgba(255, 255, 255, 0.404); + --text-on-info-strong: rgba(255, 255, 255, 0.928); + --text-on-warning-weak: rgba(255, 255, 255, 0.404); + --text-on-warning-strong: rgba(255, 255, 255, 0.928); + --text-on-success-weak: #127d0d; + --text-on-success-strong: #bafdb3; + --text-on-brand-weak: rgba(255, 255, 255, 0.404); + --text-on-brand-weaker: rgba(255, 255, 255, 0.266); + --text-on-brand-strong: rgba(255, 255, 255, 0.928); + --button-primary-base: #ededed; + --button-secondary-base: #1c1c1c; + --button-secondary-hover: rgba(255, 255, 255, 0.039); + --button-ghost-hover: rgba(255, 255, 255, 0.031); + --button-ghost-hover2: rgba(255, 255, 255, 0.059); + --border-base: rgba(255, 255, 255, 0.195); + --border-hover: rgba(255, 255, 255, 0.284); + --border-active: rgba(255, 255, 255, 0.418); + --border-selected: #9dbefe; + --border-disabled: rgba(255, 255, 255, 0.284); + --border-focus: rgba(255, 255, 255, 0.418); + --border-weak-base: #282828; + --border-strong-base: rgba(255, 255, 255, 0.266); + --border-strong-hover: rgba(255, 255, 255, 0.266); + --border-strong-active: rgba(255, 255, 255, 0.266); + --border-strong-selected: rgba(3, 76, 255, 0.62); + --border-strong-disabled: rgba(255, 255, 255, 0.138); + --border-strong-focus: rgba(255, 255, 255, 0.266); + --border-weak-hover: rgba(255, 255, 255, 0.181); + --border-weak-active: rgba(255, 255, 255, 0.266); + --border-weak-selected: rgba(3, 76, 255, 0.62); + --border-weak-disabled: rgba(255, 255, 255, 0.138); + --border-weak-focus: rgba(255, 255, 255, 0.266); + --border-weaker-base: #202020; + --border-weaker-hover: rgba(255, 255, 255, 0.084); + --border-weaker-active: rgba(255, 255, 255, 0.138); + --border-weaker-selected: rgba(3, 76, 255, 0.32); + --border-weaker-disabled: rgba(255, 255, 255, 0.034); + --border-weaker-focus: rgba(255, 255, 255, 0.138); + --border-interactive-base: #a3c1fd; + --border-interactive-hover: #7ea9ff; + --border-interactive-active: #034cff; + --border-interactive-selected: #034cff; + --border-interactive-disabled: #505050; + --border-interactive-focus: #034cff; + --border-success-base: #96ec8e; + --border-success-hover: #7add71; + --border-success-selected: #12c905; + --border-warning-base: #e9d282; + --border-warning-hover: #dac063; + --border-warning-selected: #fcd53a; + --border-critical-base: #6a1206; + --border-critical-hover: #952414; + --border-critical-selected: #fc533a; + --border-info-base: #eac5ec; + --border-info-hover: #dab1dd; + --border-info-selected: #edb2f1; + --border-color: #ffffff; + --icon-base: #7e7e7e; + --icon-hover: #a0a0a0; + --icon-active: #ededed; + --icon-selected: #ededed; + --icon-disabled: #3e3e3e; + --icon-focus: #ededed; + --icon-invert-base: #161616; + --icon-weak-base: #343434; + --icon-weak-hover: #d9d9d9; + --icon-weak-active: #c8c8c8; + --icon-weak-selected: #707070; + --icon-weak-disabled: #ededed; + --icon-weak-focus: #707070; + --icon-strong-base: #ededed; --icon-strong-hover: #f6f3f3; --icon-strong-active: #fcfcfc; --icon-strong-selected: #fdfcfc; - --icon-strong-disabled: var(--smoke-dark-8); + --icon-strong-disabled: #3e3e3e; --icon-strong-focus: #fdfcfc; - --icon-brand-base: var(--white); - --icon-interactive-base: var(--cobalt-dark-11); - --icon-success-base: var(--apple-dark-7); - --icon-success-hover: var(--apple-dark-8); - --icon-success-active: var(--apple-dark-11); - --icon-warning-base: var(--amber-dark-9); - --icon-warning-hover: var(--amber-dark-8); - --icon-warning-active: var(--amber-dark-11); - --icon-critical-base: var(--ember-dark-9); - --icon-critical-hover: var(--ember-dark-11); - --icon-critical-active: var(--ember-dark-12); - --icon-info-base: var(--lilac-dark-7); - --icon-info-hover: var(--lilac-dark-8); - --icon-info-active: var(--lilac-dark-11); - --icon-on-brand-base: var(--smoke-light-alpha-11); - --icon-on-brand-hover: var(--smoke-light-alpha-12); - --icon-on-brand-selected: var(--smoke-light-alpha-12); - --icon-on-interactive-base: var(--smoke-dark-12); - --icon-agent-plan-base: var(--purple-dark-9); - --icon-agent-docs-base: var(--amber-dark-9); - --icon-agent-ask-base: var(--cyan-dark-9); - --icon-agent-build-base: var(--cobalt-dark-11); - --icon-on-success-base: var(--apple-dark-alpha-9); - --icon-on-success-hover: var(--apple-dark-alpha-10); - --icon-on-success-selected: var(--apple-dark-alpha-11); - --icon-on-warning-base: var(--amber-darkalpha-9); - --icon-on-warning-hover: var(--amber-darkalpha-10); - --icon-on-warning-selected: var(--amber-darkalpha-11); - --icon-on-critical-base: var(--ember-dark-alpha-9); - --icon-on-critical-hover: var(--ember-dark-alpha-10); - --icon-on-critical-selected: var(--ember-dark-alpha-11); - --icon-on-info-base: var(--lilac-dark-9); - --icon-on-info-hover: var(--lilac-dark-alpha-10); - --icon-on-info-selected: var(--lilac-dark-alpha-11); - --icon-diff-add-base: var(--mint-dark-11); - --icon-diff-add-hover: var(--mint-dark-10); - --icon-diff-add-active: var(--mint-dark-11); - --icon-diff-delete-base: var(--ember-dark-9); - --icon-diff-delete-hover: var(--ember-dark-10); + --icon-brand-base: #ffffff; + --icon-interactive-base: #034cff; + --icon-success-base: #12c905; + --icon-success-hover: #35c02d; + --icon-success-active: #4de144; + --icon-warning-base: #fbb73c; + --icon-warning-hover: #885e08; + --icon-warning-active: #f1b13f; + --icon-critical-base: #fc533a; + --icon-critical-hover: #faa494; + --icon-critical-active: #ffe0da; + --icon-info-base: #68446b; + --icon-info-hover: #815484; + --icon-info-active: #dfa7e3; + --icon-on-brand-base: rgba(255, 255, 255, 0.603); + --icon-on-brand-hover: rgba(255, 255, 255, 0.928); + --icon-on-brand-selected: rgba(255, 255, 255, 0.928); + --icon-on-interactive-base: #ededed; + --icon-agent-plan-base: #edb2f1; + --icon-agent-docs-base: #fbb73c; + --icon-agent-ask-base: #2090f5; + --icon-agent-build-base: #9dbefe; + --icon-on-success-base: rgba(18, 201, 5, 0.9); + --icon-on-success-hover: rgba(53, 192, 45, 0.9); + --icon-on-success-selected: rgba(77, 225, 68, 0.9); + --icon-on-warning-base: rgba(251, 183, 60, 0.9); + --icon-on-warning-hover: rgba(245, 178, 56, 0.9); + --icon-on-warning-selected: rgba(241, 177, 63, 0.9); + --icon-on-critical-base: rgba(252, 83, 58, 0.9); + --icon-on-critical-hover: rgba(245, 79, 54, 0.9); + --icon-on-critical-selected: rgba(250, 164, 148, 0.9); + --icon-on-info-base: #edb2f1; + --icon-on-info-hover: rgba(231, 173, 235, 0.9); + --icon-on-info-selected: rgba(223, 167, 227, 0.9); + --icon-diff-add-base: #9bcd97; + --icon-diff-add-hover: #c3f9bf; + --icon-diff-add-active: #9bcd97; + --icon-diff-delete-base: #fc533a; + --icon-diff-delete-hover: #f54f36; --icon-diff-modified-base: #ffba92; --syntax-comment: var(--text-weak); --syntax-regexp: var(--text-base); @@ -560,12 +570,12 @@ --syntax-constant: #93e9f6; --syntax-punctuation: var(--text-weak); --syntax-object: var(--text-strong); - --syntax-success: var(--apple-dark-10); - --syntax-warning: var(--amber-dark-10); - --syntax-critical: var(--ember-dark-10); + --syntax-success: #35c02d; + --syntax-warning: #f5b238; + --syntax-critical: #f54f36; --syntax-info: #93e9f6; - --syntax-diff-add: var(--mint-dark-11); - --syntax-diff-delete: var(--ember-dark-11); + --syntax-diff-add: #9bcd97; + --syntax-diff-delete: #faa494; --syntax-diff-unknown: #ff0000; --markdown-heading: #9d7cd8; --markdown-text: #eeeeee; @@ -581,15 +591,6 @@ --markdown-image: #fab283; --markdown-image-text: #56b6c2; --markdown-code-block: #eeeeee; - --border-color: #ffffff; - --border-weaker-base: var(--smoke-dark-alpha-3); - --border-weaker-hover: var(--smoke-dark-alpha-4); - --border-weaker-active: var(--smoke-dark-alpha-6); - --border-weaker-selected: var(--cobalt-dark-alpha-3); - --border-weaker-disabled: var(--smoke-dark-alpha-2); - --border-weaker-focus: var(--smoke-dark-alpha-6); - --button-ghost-hover: var(--smoke-dark-alpha-2); - --button-ghost-hover2: var(--smoke-dark-alpha-3); --avatar-background-pink: #501b3f; --avatar-background-mint: #033a34; --avatar-background-orange: #5f2a06; @@ -602,5 +603,6 @@ --avatar-text-purple: #9d5bd2; --avatar-text-cyan: #369eff; --avatar-text-lime: #c4f042; + --text-stronger: rgba(255, 255, 255, 0.936); } } diff --git a/packages/ui/src/theme/color.ts b/packages/ui/src/theme/color.ts index f0e15211e9..89d9a653d7 100644 --- a/packages/ui/src/theme/color.ts +++ b/packages/ui/src/theme/color.ts @@ -1,16 +1,25 @@ import type { HexColor, OklchColor } from "./types" +function clamp(v: number, min: number, max: number) { + return Math.max(min, Math.min(max, v)) +} + +function hue(v: number) { + return ((v % 360) + 360) % 360 +} + export function hexToRgb(hex: HexColor): { r: number; g: number; b: number } { const h = hex.replace("#", "") const full = - h.length === 3 + h.length === 3 || h.length === 4 ? h .split("") .map((c) => c + c) .join("") : h + const rgb = full.length === 8 ? full.slice(0, 6) : full - const num = parseInt(full, 16) + const num = parseInt(rgb, 16) return { r: ((num >> 16) & 255) / 255, g: ((num >> 8) & 255) / 255, @@ -20,7 +29,7 @@ export function hexToRgb(hex: HexColor): { r: number; g: number; b: number } { export function rgbToHex(r: number, g: number, b: number): HexColor { const toHex = (v: number) => { - const clamped = Math.max(0, Math.min(1, v)) + const clamped = clamp(v, 0, 1) const int = Math.round(clamped * 255) return int.toString(16).padStart(2, "0") } @@ -91,8 +100,33 @@ export function hexToOklch(hex: HexColor): OklchColor { return rgbToOklch(r, g, b) } +export function fitOklch(oklch: OklchColor): OklchColor { + const base = { + l: clamp(oklch.l, 0, 1), + c: Math.max(0, oklch.c), + h: hue(oklch.h), + } + + const rgb = oklchToRgb(base) + if (rgb.r >= 0 && rgb.r <= 1 && rgb.g >= 0 && rgb.g <= 1 && rgb.b >= 0 && rgb.b <= 1) { + return base + } + + let c = base.c + for (let i = 0; i < 24; i++) { + c *= 0.9 + const next = { ...base, c } + const out = oklchToRgb(next) + if (out.r >= 0 && out.r <= 1 && out.g >= 0 && out.g <= 1 && out.b >= 0 && out.b <= 1) { + return next + } + } + + return { ...base, c: 0 } +} + export function oklchToHex(oklch: OklchColor): HexColor { - const { r, g, b } = oklchToRgb(oklch) + const { r, g, b } = oklchToRgb(fitOklch(oklch)) return rgbToHex(r, g, b) } @@ -101,12 +135,12 @@ export function generateScale(seed: HexColor, isDark: boolean): HexColor[] { const scale: HexColor[] = [] const lightSteps = isDark - ? [0.15, 0.18, 0.22, 0.26, 0.32, 0.38, 0.46, 0.56, base.l, base.l - 0.05, 0.75, 0.93] - : [0.99, 0.97, 0.94, 0.9, 0.85, 0.79, 0.72, 0.64, base.l, base.l + 0.05, 0.45, 0.25] + ? [0.182, 0.21, 0.261, 0.302, 0.341, 0.387, 0.443, 0.514, base.l, Math.max(0, base.l - 0.017), 0.8, 0.93] + : [0.993, 0.983, 0.962, 0.936, 0.906, 0.866, 0.811, 0.74, base.l, Math.max(0, base.l - 0.036), 0.548, 0.33] const chromaMultipliers = isDark - ? [0.15, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.85, 1, 1, 0.9, 0.6] - : [0.1, 0.15, 0.25, 0.35, 0.45, 0.55, 0.7, 0.85, 1, 1, 0.95, 0.85] + ? [0.205, 0.275, 0.46, 0.62, 0.71, 0.79, 0.87, 0.97, 1.04, 1.03, 1, 0.58] + : [0.045, 0.128, 0.34, 0.5, 0.61, 0.69, 0.77, 0.89, 1, 1, 0.97, 0.56] for (let i = 0; i < 12; i++) { scale.push( @@ -127,8 +161,8 @@ export function generateNeutralScale(seed: HexColor, isDark: boolean): HexColor[ const neutralChroma = Math.min(base.c, 0.02) const lightSteps = isDark - ? [0.13, 0.16, 0.2, 0.24, 0.28, 0.33, 0.4, 0.52, 0.58, 0.66, 0.82, 0.96] - : [0.995, 0.98, 0.96, 0.94, 0.91, 0.88, 0.84, 0.78, 0.62, 0.56, 0.46, 0.2] + ? [0.2, 0.226, 0.256, 0.277, 0.301, 0.325, 0.364, 0.431, base.l, 0.593, 0.706, 0.946] + : [0.991, 0.979, 0.964, 0.946, 0.931, 0.913, 0.891, 0.83, base.l, 0.617, 0.542, 0.205] for (let i = 0; i < 12; i++) { scale.push( @@ -164,19 +198,39 @@ export function generateAlphaScale(scale: HexColor[], isDark: boolean): HexColor export function mixColors(color1: HexColor, color2: HexColor, amount: number): HexColor { const c1 = hexToOklch(color1) const c2 = hexToOklch(color2) + const delta = ((((c2.h - c1.h) % 360) + 540) % 360) - 180 return oklchToHex({ l: c1.l + (c2.l - c1.l) * amount, c: c1.c + (c2.c - c1.c) * amount, - h: c1.h + (c2.h - c1.h) * amount, + h: c1.h + delta * amount, }) } +export function shift(color: HexColor, value: { l?: number; c?: number; h?: number }): HexColor { + const base = hexToOklch(color) + return oklchToHex({ + l: base.l + (value.l ?? 0), + c: base.c * (value.c ?? 1), + h: base.h + (value.h ?? 0), + }) +} + +export function blend(color: HexColor, background: HexColor, alpha: number): HexColor { + const fg = hexToRgb(color) + const bg = hexToRgb(background) + return rgbToHex( + fg.r * alpha + bg.r * (1 - alpha), + fg.g * alpha + bg.g * (1 - alpha), + fg.b * alpha + bg.b * (1 - alpha), + ) +} + export function lighten(color: HexColor, amount: number): HexColor { const oklch = hexToOklch(color) return oklchToHex({ ...oklch, - l: Math.min(1, oklch.l + amount), + l: clamp(oklch.l + amount, 0, 1), }) } @@ -184,7 +238,7 @@ export function darken(color: HexColor, amount: number): HexColor { const oklch = hexToOklch(color) return oklchToHex({ ...oklch, - l: Math.max(0, oklch.l - amount), + l: clamp(oklch.l - amount, 0, 1), }) } diff --git a/packages/ui/src/theme/context.tsx b/packages/ui/src/theme/context.tsx index c1c1637d67..cda967697c 100644 --- a/packages/ui/src/theme/context.tsx +++ b/packages/ui/src/theme/context.tsx @@ -16,6 +16,15 @@ const STORAGE_KEYS = { const THEME_STYLE_ID = "oc-theme" +function normalize(id: string | null | undefined) { + return id === "oc-1" ? "oc-2" : id +} + +function clear() { + localStorage.removeItem(STORAGE_KEYS.THEME_CSS_LIGHT) + localStorage.removeItem(STORAGE_KEYS.THEME_CSS_DARK) +} + function ensureThemeStyleElement(): HTMLStyleElement { const existing = document.getElementById(THEME_STYLE_ID) as HTMLStyleElement | null if (existing) return existing @@ -35,7 +44,7 @@ function applyThemeCss(theme: DesktopTheme, themeId: string, mode: "light" | "da const tokens = resolveThemeVariant(variant, isDark) const css = themeToCss(tokens) - if (themeId !== "oc-1") { + if (themeId !== "oc-2") { try { localStorage.setItem(isDark ? STORAGE_KEYS.THEME_CSS_DARK : STORAGE_KEYS.THEME_CSS_LIGHT, css) } catch {} @@ -54,7 +63,7 @@ function applyThemeCss(theme: DesktopTheme, themeId: string, mode: "light" | "da } function cacheThemeVariants(theme: DesktopTheme, themeId: string) { - if (themeId === "oc-1") return + if (themeId === "oc-2") return for (const mode of ["light", "dark"] as const) { const isDark = mode === "dark" const variant = isDark ? theme.dark : theme.light @@ -71,7 +80,7 @@ export const { use: useTheme, provider: ThemeProvider } = createSimpleContext({ init: (props: { defaultTheme?: string }) => { const [store, setStore] = createStore({ themes: DEFAULT_THEMES as Record<string, DesktopTheme>, - themeId: props.defaultTheme ?? "oc-1", + themeId: normalize(props.defaultTheme) ?? "oc-2", colorScheme: "system" as ColorScheme, mode: getSystemMode(), previewThemeId: null as string | null, @@ -89,9 +98,14 @@ export const { use: useTheme, provider: ThemeProvider } = createSimpleContext({ onCleanup(() => mediaQuery.removeEventListener("change", handler)) const savedTheme = localStorage.getItem(STORAGE_KEYS.THEME_ID) + const themeId = normalize(savedTheme) const savedScheme = localStorage.getItem(STORAGE_KEYS.COLOR_SCHEME) as ColorScheme | null - if (savedTheme && store.themes[savedTheme]) { - setStore("themeId", savedTheme) + if (themeId && store.themes[themeId]) { + setStore("themeId", themeId) + } + if (savedTheme && themeId && savedTheme !== themeId) { + localStorage.setItem(STORAGE_KEYS.THEME_ID, themeId) + clear() } if (savedScheme) { setStore("colorScheme", savedScheme) @@ -113,14 +127,23 @@ export const { use: useTheme, provider: ThemeProvider } = createSimpleContext({ }) const setTheme = (id: string) => { - const theme = store.themes[id] + const next = normalize(id) + if (!next) { + console.warn(`Theme "${id}" not found`) + return + } + const theme = store.themes[next] if (!theme) { console.warn(`Theme "${id}" not found`) return } - setStore("themeId", id) - localStorage.setItem(STORAGE_KEYS.THEME_ID, id) - cacheThemeVariants(theme, id) + setStore("themeId", next) + localStorage.setItem(STORAGE_KEYS.THEME_ID, next) + if (next === "oc-2") { + clear() + return + } + cacheThemeVariants(theme, next) } const setColorScheme = (scheme: ColorScheme) => { @@ -138,15 +161,17 @@ export const { use: useTheme, provider: ThemeProvider } = createSimpleContext({ setColorScheme, registerTheme: (theme: DesktopTheme) => setStore("themes", theme.id, theme), previewTheme: (id: string) => { - const theme = store.themes[id] + const next = normalize(id) + if (!next) return + const theme = store.themes[next] if (!theme) return - setStore("previewThemeId", id) + setStore("previewThemeId", next) const previewMode = store.previewScheme ? store.previewScheme === "system" ? getSystemMode() : store.previewScheme : store.mode - applyThemeCss(theme, id, previewMode) + applyThemeCss(theme, next, previewMode) }, previewColorScheme: (scheme: ColorScheme) => { setStore("previewScheme", scheme) diff --git a/packages/ui/src/theme/default-themes.ts b/packages/ui/src/theme/default-themes.ts index 52b2b42eba..b3cfb340c1 100644 --- a/packages/ui/src/theme/default-themes.ts +++ b/packages/ui/src/theme/default-themes.ts @@ -1,5 +1,4 @@ import type { DesktopTheme } from "./types" -import oc1ThemeJson from "./themes/oc-1.json" import oc2ThemeJson from "./themes/oc-2.json" import tokyoThemeJson from "./themes/tokyonight.json" import draculaThemeJson from "./themes/dracula.json" @@ -16,7 +15,6 @@ import carbonfoxThemeJson from "./themes/carbonfox.json" import gruvboxThemeJson from "./themes/gruvbox.json" import auraThemeJson from "./themes/aura.json" -export const oc1Theme = oc1ThemeJson as DesktopTheme export const oc2Theme = oc2ThemeJson as DesktopTheme export const tokyonightTheme = tokyoThemeJson as DesktopTheme export const draculaTheme = draculaThemeJson as DesktopTheme @@ -34,7 +32,6 @@ export const gruvboxTheme = gruvboxThemeJson as DesktopTheme export const auraTheme = auraThemeJson as DesktopTheme export const DEFAULT_THEMES: Record<string, DesktopTheme> = { - "oc-1": oc1Theme, "oc-2": oc2Theme, aura: auraTheme, ayu: ayuTheme, diff --git a/packages/ui/src/theme/desktop-theme.schema.json b/packages/ui/src/theme/desktop-theme.schema.json index b60a8f37ca..d4f1ffd21f 100644 --- a/packages/ui/src/theme/desktop-theme.schema.json +++ b/packages/ui/src/theme/desktop-theme.schema.json @@ -36,12 +36,13 @@ }, "ColorValue": { "type": "string", - "pattern": "^(#([0-9a-fA-F]{3}|[0-9a-fA-F]{4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})|var\(--[a-z0-9-]+\))$", + "pattern": "^(#([0-9a-fA-F]{3}|[0-9a-fA-F]{4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})|var\\(--[a-z0-9-]+\\))$", "description": "Either a hex color value (#rgb/#rgba/#rrggbb/#rrggbbaa) or a CSS variable reference" }, "ThemeSeedColors": { "type": "object", - "description": "The minimum set of colors needed to generate a theme", + "description": "The legacy semantic seed set used to generate a theme", + "additionalProperties": false, "required": ["neutral", "primary", "success", "warning", "error", "info", "interactive", "diffAdd", "diffDelete"], "properties": { "neutral": { @@ -82,14 +83,70 @@ } } }, + "ThemePaletteColors": { + "type": "object", + "description": "A compact semantic palette used to derive the full theme programmatically", + "additionalProperties": false, + "required": ["neutral", "primary", "success", "warning", "error", "info"], + "properties": { + "neutral": { + "$ref": "#/definitions/HexColor", + "description": "Base neutral color for generating the gray scale" + }, + "ink": { + "$ref": "#/definitions/HexColor", + "description": "Optional foreground or chrome color used to derive text and border tones" + }, + "primary": { + "$ref": "#/definitions/HexColor", + "description": "Primary brand color used for brand surfaces and strong emphasis" + }, + "success": { + "$ref": "#/definitions/HexColor", + "description": "Success state color" + }, + "warning": { + "$ref": "#/definitions/HexColor", + "description": "Warning state color" + }, + "error": { + "$ref": "#/definitions/HexColor", + "description": "Error or critical state color" + }, + "info": { + "$ref": "#/definitions/HexColor", + "description": "Informational state color" + }, + "accent": { + "$ref": "#/definitions/HexColor", + "description": "Optional extra expressive accent for syntax and rich content" + }, + "interactive": { + "$ref": "#/definitions/HexColor", + "description": "Optional dedicated interactive color; falls back to primary" + }, + "diffAdd": { + "$ref": "#/definitions/HexColor", + "description": "Optional diff-add seed; falls back to a softened success color" + }, + "diffDelete": { + "$ref": "#/definitions/HexColor", + "description": "Optional diff-delete seed; falls back to error" + } + } + }, "ThemeVariant": { "type": "object", - "description": "A theme variant (light or dark) with seed colors and optional overrides", - "required": ["seeds"], + "description": "A theme variant (light or dark) with either a compact palette or legacy seeds and optional overrides", + "oneOf": [{ "required": ["seeds"] }, { "required": ["palette"] }], "properties": { "seeds": { "$ref": "#/definitions/ThemeSeedColors", - "description": "Seed colors used to generate the full palette" + "description": "Legacy seed colors used to generate the full palette" + }, + "palette": { + "$ref": "#/definitions/ThemePaletteColors", + "description": "Compact palette used to derive the full token set" }, "overrides": { "type": "object", diff --git a/packages/ui/src/theme/index.ts b/packages/ui/src/theme/index.ts index d2c60179ec..bfd55e60b8 100644 --- a/packages/ui/src/theme/index.ts +++ b/packages/ui/src/theme/index.ts @@ -1,5 +1,6 @@ export type { DesktopTheme, + ThemePaletteColors, ThemeSeedColors, ThemeVariant, HexColor, @@ -19,7 +20,10 @@ export { generateScale, generateNeutralScale, generateAlphaScale, + fitOklch, + blend, mixColors, + shift, lighten, darken, withAlpha, @@ -31,7 +35,6 @@ export { ThemeProvider, useTheme, type ColorScheme } from "./context" export { DEFAULT_THEMES, - oc1Theme, oc2Theme, tokyonightTheme, draculaTheme, diff --git a/packages/ui/src/theme/loader.ts b/packages/ui/src/theme/loader.ts index 0f61076a00..4d48000daf 100644 --- a/packages/ui/src/theme/loader.ts +++ b/packages/ui/src/theme/loader.ts @@ -27,7 +27,7 @@ export function applyTheme(theme: DesktopTheme, themeId?: string): void { } function buildThemeCss(light: ResolvedTheme, dark: ResolvedTheme, themeId: string): string { - const isDefaultTheme = themeId === "oc-1" + const isDefaultTheme = themeId === "oc-2" const lightCss = themeToCss(light) const darkCss = themeToCss(dark) diff --git a/packages/ui/src/theme/resolve.ts b/packages/ui/src/theme/resolve.ts index f098e8028a..722648dabc 100644 --- a/packages/ui/src/theme/resolve.ts +++ b/packages/ui/src/theme/resolve.ts @@ -1,27 +1,131 @@ import type { ColorValue, DesktopTheme, HexColor, ResolvedTheme, ThemeVariant } from "./types" -import { generateNeutralScale, generateScale, hexToOklch, oklchToHex, withAlpha } from "./color" +import { blend, generateNeutralScale, generateScale, hexToOklch, oklchToHex, shift, withAlpha } from "./color" export function resolveThemeVariant(variant: ThemeVariant, isDark: boolean): ResolvedTheme { - const { seeds, overrides = {} } = variant + const colors = getColors(variant) + const { overrides = {} } = variant - const neutral = generateNeutralScale(seeds.neutral, isDark) - const primary = generateScale(seeds.primary, isDark) - const success = generateScale(seeds.success, isDark) - const warning = generateScale(seeds.warning, isDark) - const error = generateScale(seeds.error, isDark) - const info = generateScale(seeds.info, isDark) - const interactive = generateScale(seeds.interactive, isDark) - const diffAdd = generateScale(seeds.diffAdd, isDark) - const diffDelete = generateScale(seeds.diffDelete, isDark) + const neutral = generateNeutralScale(colors.neutral, isDark) + const primary = generateScale(colors.primary, isDark) + const accent = generateScale(colors.accent, isDark) + const success = generateScale(colors.success, isDark) + const warning = generateScale(colors.warning, isDark) + const error = generateScale(colors.error, isDark) + const info = generateScale(colors.info, isDark) + const interactive = generateScale(colors.interactive, isDark) + const hasInk = colors.compact && Boolean(colors.ink) + const noInk = colors.compact && !hasInk + const shadow = noInk && !isDark ? generateNeutralScale(colors.neutral, true) : neutral + const amber = generateScale( + shift(colors.warning, isDark ? { h: -16, l: -0.058, c: 1.14 } : { h: -22, l: -0.082, c: 0.94 }), + isDark, + ) + const blue = generateScale(shift(colors.interactive, { h: -12, l: 0.128, c: 1.12 }), isDark) + const brandl = noInk && isDark ? generateScale(colors.primary, false) : primary + const successl = noInk && isDark ? generateScale(colors.success, false) : success + const warningl = noInk && isDark ? generateScale(colors.warning, false) : warning + const infol = noInk && isDark ? generateScale(colors.info, false) : info + const interl = noInk && isDark ? generateScale(colors.interactive, false) : interactive + const diffAdd = generateScale( + colors.diffAdd ?? + (noInk + ? shift(colors.success, { c: isDark ? 0.54 : 0.6, l: isDark ? 0.22 : 0.16 }) + : shift(colors.success, { c: isDark ? 0.7 : 0.55, l: isDark ? -0.18 : 0.14 })), + isDark, + ) + const diffDelete = generateScale( + colors.diffDelete ?? + (noInk ? colors.error : shift(colors.error, { c: isDark ? 0.82 : 0.7, l: isDark ? -0.08 : 0.08 })), + isDark, + ) + const ink = colors.ink ?? colors.neutral + const backgroundOverride = overrides["background-base"] + const backgroundHex = getHex(backgroundOverride) + const overlay = noInk || (Boolean(backgroundOverride) && !backgroundHex) + const content = (seed: HexColor, scale: HexColor[]) => { + const value = isDark ? seed : hexToOklch(seed).l > 0.82 ? scale[10] : seed + return shift(value, { c: isDark ? 1.16 : 1.1 }) + } + const modified = () => { + if (!colors.compact) return isDark ? "#ffba92" : "#FF8C00" + if (!hasInk) return isDark ? "#ffba92" : "#FF8C00" + const warningHue = hexToOklch(colors.warning).h + const deleteHue = hexToOklch(colors.diffDelete ?? colors.error).h + const delta = Math.abs(((((deleteHue - warningHue) % 360) + 540) % 360) - 180) + if (delta < 48) return isDark ? "#ffba92" : "#FF8C00" + return content(colors.warning, warning) + } + const surface = ( + seed: HexColor, + alpha: { base: number; weak: number; weaker: number; strong: number; stronger: number }, + ) => { + const base = alphaTone(seed, alpha.base) + return { + base, + weak: alphaTone(seed, alpha.weak), + weaker: alphaTone(seed, alpha.weaker), + strong: alphaTone(seed, alpha.strong), + stronger: alphaTone(seed, alpha.stronger), + } + } + const compactBackground = + colors.compact && !hasInk + ? isDark + ? { + base: shift(blend(colors.neutral, "#000000", 0.145), { c: 0 }), + weak: shift(blend(colors.neutral, "#000000", 0.27), { c: 0 }), + strong: shift(blend(colors.neutral, "#000000", 0.165), { c: 0 }), + stronger: shift(blend(colors.neutral, "#000000", 0.19), { c: 0 }), + } + : { + base: blend(colors.neutral, "#ffffff", 0.066), + weak: blend(colors.neutral, "#ffffff", 0.11), + strong: blend(colors.neutral, "#ffffff", 0.024), + stronger: blend(colors.neutral, "#ffffff", 0.024), + } + : undefined + const compactInkBackground = + colors.compact && hasInk && isDark + ? { + base: neutral[2], + weak: neutral[3], + strong: neutral[1], + stronger: neutral[2], + } + : undefined - const neutralAlpha = generateNeutralAlphaScale(neutral, isDark) + const background = backgroundHex ?? compactInkBackground?.base ?? compactBackground?.base ?? neutral[0] + const alphaTone = (color: HexColor, alpha: number) => + overlay ? (withAlpha(color, alpha) as ColorValue) : blend(color, background, alpha) + const borderTone = (light: number, dark: number) => + alphaTone( + ink, + isDark ? Math.min(1, dark + 0.024 + (colors.compact && hasInk ? 0.08 : 0)) : Math.min(1, light + 0.024), + ) + const diffHiddenSurface = noInk + ? { + base: blue[isDark ? 1 : 2], + weak: blue[isDark ? 0 : 1], + weaker: blue[isDark ? 2 : 0], + strong: blue[4], + stronger: blue[isDark ? 10 : 8], + } + : surface( + isDark ? shift(colors.interactive, { c: 0.55, l: 0 }) : shift(colors.interactive, { c: 0.45, l: 0.08 }), + isDark + ? { base: 0.14, weak: 0.08, weaker: 0.18, strong: 0.26, stronger: 0.42 } + : { base: 0.12, weak: 0.08, weaker: 0.16, strong: 0.24, stronger: 0.36 }, + ) + + const neutralAlpha = noInk ? generateNeutralOverlayScale(neutral, isDark) : generateNeutralAlphaScale(neutral, isDark) const tokens: ResolvedTheme = {} - tokens["background-base"] = neutral[0] - tokens["background-weak"] = neutral[2] - tokens["background-strong"] = neutral[0] - tokens["background-stronger"] = isDark ? neutral[1] : "#fcfcfc" + tokens["background-base"] = compactInkBackground?.base ?? compactBackground?.base ?? neutral[0] + tokens["background-weak"] = compactInkBackground?.weak ?? compactBackground?.weak ?? neutral[2] + tokens["background-strong"] = compactInkBackground?.strong ?? compactBackground?.strong ?? neutral[0] + tokens["background-stronger"] = + compactInkBackground?.stronger ?? compactBackground?.stronger ?? (isDark ? neutral[1] : "#fcfcfc") tokens["surface-base"] = neutralAlpha[1] tokens["base"] = neutralAlpha[1] @@ -37,8 +141,8 @@ export function resolveThemeVariant(variant: ThemeVariant, isDark: boolean): Res : (withAlpha(neutral[3], 0.09) as ColorValue) tokens["surface-inset-strong-hover"] = tokens["surface-inset-strong"] tokens["surface-raised-base"] = neutralAlpha[0] - tokens["surface-float-base"] = isDark ? neutral[0] : neutral[11] - tokens["surface-float-base-hover"] = isDark ? neutral[1] : neutral[10] + tokens["surface-float-base"] = isDark ? neutral[0] : noInk ? shadow[0] : neutral[11] + tokens["surface-float-base-hover"] = isDark ? neutral[1] : noInk ? shadow[1] : neutral[10] tokens["surface-raised-base-hover"] = neutralAlpha[1] tokens["surface-raised-base-active"] = neutralAlpha[2] tokens["surface-raised-strong"] = isDark ? neutralAlpha[3] : neutral[0] @@ -50,34 +154,34 @@ export function resolveThemeVariant(variant: ThemeVariant, isDark: boolean): Res tokens["surface-strong"] = isDark ? neutralAlpha[6] : "#ffffff" tokens["surface-raised-stronger-non-alpha"] = isDark ? neutral[2] : "#ffffff" - tokens["surface-brand-base"] = primary[8] - tokens["surface-brand-hover"] = primary[9] + tokens["surface-brand-base"] = brandl[8] + tokens["surface-brand-hover"] = brandl[9] - tokens["surface-interactive-base"] = interactive[2] - tokens["surface-interactive-hover"] = interactive[3] - tokens["surface-interactive-weak"] = interactive[1] - tokens["surface-interactive-weak-hover"] = interactive[2] + tokens["surface-interactive-base"] = interactive[isDark ? 4 : 3] + tokens["surface-interactive-hover"] = interactive[isDark ? 5 : 4] + tokens["surface-interactive-weak"] = interactive[isDark ? 3 : 2] + tokens["surface-interactive-weak-hover"] = noInk && isDark ? interl[4] : interactive[isDark ? 4 : 3] - tokens["surface-success-base"] = success[2] - tokens["surface-success-weak"] = success[1] - tokens["surface-success-strong"] = success[8] - tokens["surface-warning-base"] = warning[2] - tokens["surface-warning-weak"] = warning[1] - tokens["surface-warning-strong"] = warning[8] - tokens["surface-critical-base"] = error[2] - tokens["surface-critical-weak"] = error[1] - tokens["surface-critical-strong"] = error[8] - tokens["surface-info-base"] = info[2] - tokens["surface-info-weak"] = info[1] - tokens["surface-info-strong"] = info[8] + tokens["surface-success-base"] = success[isDark ? 4 : 3] + tokens["surface-success-weak"] = success[isDark ? 3 : 2] + tokens["surface-success-strong"] = success[9] + tokens["surface-warning-base"] = (noInk && isDark ? warningl : warning)[isDark ? 4 : 3] + tokens["surface-warning-weak"] = (noInk && isDark ? warningl : warning)[isDark ? 3 : 2] + tokens["surface-warning-strong"] = (noInk && isDark ? warningl : warning)[9] + tokens["surface-critical-base"] = error[isDark ? 4 : 3] + tokens["surface-critical-weak"] = error[isDark ? 3 : 2] + tokens["surface-critical-strong"] = error[9] + tokens["surface-info-base"] = (noInk && isDark ? infol : info)[isDark ? 4 : 3] + tokens["surface-info-weak"] = (noInk && isDark ? infol : info)[isDark ? 3 : 2] + tokens["surface-info-strong"] = (noInk && isDark ? infol : info)[9] tokens["surface-diff-unchanged-base"] = isDark ? neutral[0] : "#ffffff00" tokens["surface-diff-skip-base"] = isDark ? neutralAlpha[0] : neutral[1] - tokens["surface-diff-hidden-base"] = interactive[isDark ? 1 : 2] - tokens["surface-diff-hidden-weak"] = interactive[isDark ? 0 : 1] - tokens["surface-diff-hidden-weaker"] = interactive[isDark ? 2 : 0] - tokens["surface-diff-hidden-strong"] = interactive[4] - tokens["surface-diff-hidden-stronger"] = interactive[isDark ? 10 : 8] + tokens["surface-diff-hidden-base"] = diffHiddenSurface.base + tokens["surface-diff-hidden-weak"] = diffHiddenSurface.weak + tokens["surface-diff-hidden-weaker"] = diffHiddenSurface.weaker + tokens["surface-diff-hidden-strong"] = diffHiddenSurface.strong + tokens["surface-diff-hidden-stronger"] = diffHiddenSurface.stronger tokens["surface-diff-add-base"] = diffAdd[2] tokens["surface-diff-add-weak"] = diffAdd[isDark ? 3 : 1] tokens["surface-diff-add-weaker"] = diffAdd[isDark ? 2 : 0] @@ -96,10 +200,36 @@ export function resolveThemeVariant(variant: ThemeVariant, isDark: boolean): Res tokens["input-focus"] = interactive[0] tokens["input-disabled"] = neutral[3] - tokens["text-base"] = neutral[10] - tokens["text-weak"] = neutral[8] - tokens["text-weaker"] = neutral[7] - tokens["text-strong"] = neutral[11] + tokens["text-base"] = hasInk ? ink : noInk ? (isDark ? neutralAlpha[10] : neutral[10]) : neutral[10] + tokens["text-weak"] = hasInk + ? shift(ink, { l: isDark ? -0.18 : 0.16, c: 0.88 }) + : noInk + ? isDark + ? neutralAlpha[8] + : neutral[8] + : neutral[8] + tokens["text-weaker"] = hasInk + ? shift(ink, { l: isDark ? -0.3 : 0.26, c: isDark ? 0.74 : 0.68 }) + : noInk + ? isDark + ? neutralAlpha[7] + : neutral[7] + : neutral[7] + tokens["text-strong"] = hasInk + ? isDark && colors.compact + ? blend("#ffffff", ink, 0.82) + : shift(ink, { l: isDark ? 0.06 : -0.09, c: 1 }) + : noInk + ? isDark + ? neutralAlpha[11] + : neutral[11] + : neutral[11] + if (noInk && isDark) { + tokens["text-base"] = withAlpha("#ffffff", 0.618) as ColorValue + tokens["text-weak"] = withAlpha("#ffffff", 0.422) as ColorValue + tokens["text-weaker"] = withAlpha("#ffffff", 0.284) as ColorValue + tokens["text-strong"] = withAlpha("#ffffff", 0.936) as ColorValue + } tokens["text-invert-base"] = isDark ? neutral[10] : neutral[1] tokens["text-invert-weak"] = isDark ? neutral[8] : neutral[2] tokens["text-invert-weaker"] = isDark ? neutral[7] : neutral[3] @@ -128,84 +258,166 @@ export function resolveThemeVariant(variant: ThemeVariant, isDark: boolean): Res tokens["text-on-brand-weaker"] = neutralAlpha[7] tokens["text-on-brand-strong"] = neutralAlpha[11] - tokens["button-secondary-base"] = isDark ? neutral[2] : neutral[0] - tokens["button-secondary-hover"] = isDark ? neutral[3] : neutral[1] + tokens["button-primary-base"] = neutral[11] + tokens["button-secondary-base"] = noInk ? (isDark ? neutral[1] : neutral[0]) : isDark ? neutral[2] : neutral[0] + tokens["button-secondary-hover"] = noInk ? (isDark ? neutral[1] : neutral[1]) : isDark ? neutral[3] : neutral[1] tokens["button-ghost-hover"] = neutralAlpha[1] tokens["button-ghost-hover2"] = neutralAlpha[2] - tokens["border-base"] = neutralAlpha[6] - tokens["border-hover"] = neutralAlpha[7] - tokens["border-active"] = neutralAlpha[8] - tokens["border-selected"] = withAlpha(interactive[8], isDark ? 0.9 : 0.99) as ColorValue - tokens["border-disabled"] = neutralAlpha[7] - tokens["border-focus"] = neutralAlpha[8] - tokens["border-weak-base"] = neutralAlpha[isDark ? 5 : 4] - tokens["border-strong-base"] = neutralAlpha[isDark ? 7 : 6] - tokens["border-strong-hover"] = neutralAlpha[7] - tokens["border-strong-active"] = neutralAlpha[isDark ? 7 : 6] - tokens["border-strong-selected"] = withAlpha(interactive[5], 0.6) as ColorValue - tokens["border-strong-disabled"] = neutralAlpha[5] - tokens["border-strong-focus"] = neutralAlpha[isDark ? 7 : 6] - tokens["border-weak-hover"] = neutralAlpha[isDark ? 6 : 5] - tokens["border-weak-active"] = neutralAlpha[isDark ? 7 : 6] - tokens["border-weak-selected"] = withAlpha(interactive[4], isDark ? 0.6 : 0.5) as ColorValue - tokens["border-weak-disabled"] = neutralAlpha[5] - tokens["border-weak-focus"] = neutralAlpha[isDark ? 7 : 6] - tokens["border-weaker-base"] = neutralAlpha[2] - tokens["border-weaker-hover"] = neutralAlpha[3] - tokens["border-weaker-active"] = neutralAlpha[5] - tokens["border-weaker-selected"] = withAlpha(interactive[3], isDark ? 0.3 : 0.4) as ColorValue - tokens["border-weaker-disabled"] = neutralAlpha[1] - tokens["border-weaker-focus"] = neutralAlpha[5] + if (noInk) { + const tone = (alpha: number) => alphaTone((isDark ? "#ffffff" : "#000000") as HexColor, alpha) + if (isDark) { + tokens["surface-base"] = tone(0.031) + tokens["surface-base-hover"] = tone(0.039) + tokens["surface-base-active"] = tone(0.059) + tokens["surface-raised-base"] = tone(0.059) + tokens["surface-raised-base-hover"] = tone(0.078) + tokens["surface-raised-base-active"] = tone(0.102) + tokens["surface-raised-strong"] = tone(0.078) + tokens["surface-raised-strong-hover"] = tone(0.129) + tokens["surface-raised-stronger"] = tone(0.129) + tokens["surface-raised-stronger-hover"] = tone(0.169) + tokens["surface-weak"] = tone(0.078) + tokens["surface-weaker"] = tone(0.102) + tokens["surface-strong"] = tone(0.169) + tokens["surface-raised-stronger-non-alpha"] = neutral[1] + tokens["surface-inset-base"] = withAlpha("#000000", 0.5) as ColorValue + tokens["surface-inset-base-hover"] = tokens["surface-inset-base"] + tokens["surface-inset-strong"] = withAlpha("#000000", 0.8) as ColorValue + tokens["surface-inset-strong-hover"] = tokens["surface-inset-strong"] + tokens["button-secondary-hover"] = tone(0.039) + tokens["button-ghost-hover"] = tone(0.031) + tokens["button-ghost-hover2"] = tone(0.059) + tokens["input-base"] = neutral[1] + tokens["input-hover"] = neutral[1] + tokens["input-selected"] = interactive[1] + tokens["surface-diff-skip-base"] = "#00000000" + } - tokens["border-interactive-base"] = interactive[6] - tokens["border-interactive-hover"] = interactive[7] - tokens["border-interactive-active"] = interactive[8] - tokens["border-interactive-selected"] = interactive[8] + if (!isDark) { + tokens["surface-base"] = tone(0.031) + tokens["surface-base-hover"] = tone(0.059) + tokens["surface-base-active"] = tone(0.051) + tokens["surface-raised-base"] = tone(0.031) + tokens["surface-raised-base-hover"] = tone(0.051) + tokens["surface-raised-base-active"] = tone(0.09) + tokens["surface-raised-strong"] = neutral[0] + tokens["surface-raised-strong-hover"] = "#ffffff" + tokens["surface-raised-stronger"] = "#ffffff" + tokens["surface-raised-stronger-hover"] = "#ffffff" + tokens["surface-weak"] = tone(0.051) + tokens["surface-weaker"] = tone(0.071) + tokens["surface-strong"] = "#ffffff" + tokens["surface-raised-stronger-non-alpha"] = "#ffffff" + tokens["surface-inset-strong"] = tone(0.09) + tokens["surface-inset-strong-hover"] = tokens["surface-inset-strong"] + tokens["button-secondary-hover"] = blend("#ffffff", background, 0.04) + tokens["button-ghost-hover"] = tone(0.031) + tokens["button-ghost-hover2"] = tone(0.051) + tokens["input-base"] = neutral[0] + tokens["input-hover"] = neutral[1] + } + + tokens["surface-base-interactive-active"] = withAlpha(colors.interactive, isDark ? 0.125 : 0.09) as ColorValue + } + + tokens["border-base"] = hasInk ? borderTone(0.22, 0.16) : neutralAlpha[6] + tokens["border-hover"] = hasInk ? borderTone(0.28, 0.2) : neutralAlpha[7] + tokens["border-active"] = hasInk ? borderTone(0.34, 0.24) : neutralAlpha[8] + tokens["border-selected"] = noInk + ? isDark + ? interactive[10] + : (withAlpha(colors.interactive, 0.99) as ColorValue) + : (withAlpha(interactive[8], isDark ? 0.9 : 0.99) as ColorValue) + tokens["border-disabled"] = hasInk ? borderTone(0.18, 0.12) : neutralAlpha[7] + tokens["border-focus"] = hasInk ? borderTone(0.34, 0.24) : neutralAlpha[8] + tokens["border-weak-base"] = hasInk + ? borderTone(0.1, 0.08) + : noInk + ? isDark + ? neutral[3] + : blend(neutral[4], neutral[5], 0.5) + : neutralAlpha[isDark ? 5 : 4] + tokens["border-strong-base"] = hasInk ? borderTone(0.34, 0.24) : neutralAlpha[isDark ? 7 : 6] + tokens["border-strong-hover"] = hasInk ? borderTone(0.4, 0.28) : neutralAlpha[7] + tokens["border-strong-active"] = hasInk ? borderTone(0.46, 0.32) : neutralAlpha[isDark ? 7 : 6] + tokens["border-strong-selected"] = noInk + ? (withAlpha(colors.interactive, isDark ? 0.62 : 0.31) as ColorValue) + : (withAlpha(interactive[5], 0.6) as ColorValue) + tokens["border-strong-disabled"] = hasInk ? borderTone(0.14, 0.1) : neutralAlpha[5] + tokens["border-strong-focus"] = hasInk ? borderTone(0.46, 0.32) : neutralAlpha[isDark ? 7 : 6] + tokens["border-weak-hover"] = hasInk ? borderTone(0.16, 0.12) : neutralAlpha[isDark ? 6 : 5] + tokens["border-weak-active"] = hasInk ? borderTone(0.22, 0.16) : neutralAlpha[isDark ? 7 : 6] + tokens["border-weak-selected"] = noInk + ? (withAlpha(colors.interactive, isDark ? 0.62 : 0.24) as ColorValue) + : (withAlpha(interactive[4], isDark ? 0.6 : 0.5) as ColorValue) + tokens["border-weak-disabled"] = hasInk ? borderTone(0.08, 0.06) : neutralAlpha[5] + tokens["border-weak-focus"] = hasInk ? borderTone(0.22, 0.16) : neutralAlpha[isDark ? 7 : 6] + tokens["border-weaker-base"] = hasInk + ? borderTone(0.06, 0.04) + : noInk + ? isDark + ? blend(neutral[1], neutral[2], 0.5) + : blend(neutral[2], neutral[3], 0.5) + : neutralAlpha[2] + + if (noInk) { + const line = (l: number, d: number) => alphaTone((isDark ? "#ffffff" : "#000000") as HexColor, isDark ? d : l) + tokens["border-base"] = line(0.162, 0.195) + tokens["border-hover"] = line(0.236, 0.284) + tokens["border-active"] = line(0.46, 0.418) + tokens["border-disabled"] = tokens["border-hover"] + tokens["border-focus"] = tokens["border-active"] + } + + tokens["border-interactive-base"] = (noInk && isDark ? interl : interactive)[6] + tokens["border-interactive-hover"] = (noInk && isDark ? interl : interactive)[7] + tokens["border-interactive-active"] = (noInk && isDark ? interl : interactive)[8] + tokens["border-interactive-selected"] = (noInk && isDark ? interl : interactive)[8] tokens["border-interactive-disabled"] = neutral[7] - tokens["border-interactive-focus"] = interactive[8] + tokens["border-interactive-focus"] = (noInk && isDark ? interl : interactive)[8] - tokens["border-success-base"] = success[5] - tokens["border-success-hover"] = success[6] - tokens["border-success-selected"] = success[8] - tokens["border-warning-base"] = warning[5] - tokens["border-warning-hover"] = warning[6] - tokens["border-warning-selected"] = warning[8] + tokens["border-success-base"] = (noInk && isDark ? successl : success)[5] + tokens["border-success-hover"] = (noInk && isDark ? successl : success)[6] + tokens["border-success-selected"] = (noInk && isDark ? successl : success)[8] + tokens["border-warning-base"] = (noInk && isDark ? warningl : warning)[5] + tokens["border-warning-hover"] = (noInk && isDark ? warningl : warning)[6] + tokens["border-warning-selected"] = (noInk && isDark ? warningl : warning)[8] tokens["border-critical-base"] = error[isDark ? 4 : 5] tokens["border-critical-hover"] = error[6] tokens["border-critical-selected"] = error[8] - tokens["border-info-base"] = info[5] - tokens["border-info-hover"] = info[6] - tokens["border-info-selected"] = info[8] + tokens["border-info-base"] = (noInk && isDark ? infol : info)[5] + tokens["border-info-hover"] = (noInk && isDark ? infol : info)[6] + tokens["border-info-selected"] = (noInk && isDark ? infol : info)[8] tokens["border-color"] = "#ffffff" - tokens["icon-base"] = neutral[8] - tokens["icon-hover"] = neutral[isDark ? 9 : 10] - tokens["icon-active"] = neutral[isDark ? 10 : 11] - tokens["icon-selected"] = neutral[11] + tokens["icon-base"] = hasInk && !isDark ? tokens["text-weak"] : neutral[isDark ? 9 : 8] + tokens["icon-hover"] = hasInk && !isDark ? tokens["text-base"] : neutral[10] + tokens["icon-active"] = hasInk && !isDark ? tokens["text-strong"] : neutral[11] + tokens["icon-selected"] = hasInk && !isDark ? tokens["text-strong"] : neutral[11] tokens["icon-disabled"] = neutral[isDark ? 6 : 7] - tokens["icon-focus"] = neutral[11] + tokens["icon-focus"] = hasInk && !isDark ? tokens["text-strong"] : neutral[11] tokens["icon-invert-base"] = isDark ? neutral[0] : "#ffffff" tokens["icon-weak-base"] = neutral[isDark ? 5 : 6] - tokens["icon-weak-hover"] = neutral[6] - tokens["icon-weak-active"] = neutral[7] - tokens["icon-weak-selected"] = neutral[8] - tokens["icon-weak-disabled"] = neutral[isDark ? 3 : 5] + tokens["icon-weak-hover"] = noInk && isDark ? blend(neutral[11], neutral[10], 0.74) : neutral[isDark ? 11 : 7] + tokens["icon-weak-active"] = noInk && isDark ? blend(neutral[11], neutral[10], 0.52) : neutral[8] + tokens["icon-weak-selected"] = neutral[isDark ? 8 : 9] + tokens["icon-weak-disabled"] = noInk && isDark ? neutral[11] : neutral[isDark ? 3 : 5] tokens["icon-weak-focus"] = neutral[8] tokens["icon-strong-base"] = neutral[11] tokens["icon-strong-hover"] = isDark ? "#f6f3f3" : "#151313" tokens["icon-strong-active"] = isDark ? "#fcfcfc" : "#020202" tokens["icon-strong-selected"] = isDark ? "#fdfcfc" : "#020202" - tokens["icon-strong-disabled"] = neutral[7] + tokens["icon-strong-disabled"] = noInk && isDark ? neutral[6] : neutral[7] tokens["icon-strong-focus"] = isDark ? "#fdfcfc" : "#020202" tokens["icon-brand-base"] = isDark ? "#ffffff" : neutral[11] tokens["icon-interactive-base"] = interactive[8] - tokens["icon-success-base"] = success[isDark ? 6 : 6] - tokens["icon-success-hover"] = success[7] + tokens["icon-success-base"] = success[isDark ? 8 : 6] + tokens["icon-success-hover"] = success[isDark ? 9 : 7] tokens["icon-success-active"] = success[10] - tokens["icon-warning-base"] = warning[6] - tokens["icon-warning-hover"] = warning[7] - tokens["icon-warning-active"] = warning[10] + tokens["icon-warning-base"] = amber[isDark ? 8 : 6] + tokens["icon-warning-hover"] = amber[7] + tokens["icon-warning-active"] = amber[10] tokens["icon-critical-base"] = error[isDark ? 8 : 9] tokens["icon-critical-hover"] = error[10] tokens["icon-critical-active"] = error[11] @@ -218,16 +430,16 @@ export function resolveThemeVariant(variant: ThemeVariant, isDark: boolean): Res tokens["icon-on-interactive-base"] = isDark ? neutral[11] : neutral[0] tokens["icon-agent-plan-base"] = info[8] - tokens["icon-agent-docs-base"] = warning[8] - tokens["icon-agent-ask-base"] = interactive[8] + tokens["icon-agent-docs-base"] = amber[8] + tokens["icon-agent-ask-base"] = blue[8] tokens["icon-agent-build-base"] = interactive[isDark ? 10 : 8] tokens["icon-on-success-base"] = withAlpha(success[8], 0.9) as ColorValue tokens["icon-on-success-hover"] = withAlpha(success[9], 0.9) as ColorValue tokens["icon-on-success-selected"] = withAlpha(success[10], 0.9) as ColorValue - tokens["icon-on-warning-base"] = withAlpha(warning[8], 0.9) as ColorValue - tokens["icon-on-warning-hover"] = withAlpha(warning[9], 0.9) as ColorValue - tokens["icon-on-warning-selected"] = withAlpha(warning[10], 0.9) as ColorValue + tokens["icon-on-warning-base"] = withAlpha(amber[8], 0.9) as ColorValue + tokens["icon-on-warning-hover"] = withAlpha(amber[9], 0.9) as ColorValue + tokens["icon-on-warning-selected"] = withAlpha(amber[10], 0.9) as ColorValue tokens["icon-on-critical-base"] = withAlpha(error[8], 0.9) as ColorValue tokens["icon-on-critical-hover"] = withAlpha(error[9], 0.9) as ColorValue tokens["icon-on-critical-selected"] = withAlpha(error[10], 0.9) as ColorValue @@ -240,42 +452,120 @@ export function resolveThemeVariant(variant: ThemeVariant, isDark: boolean): Res tokens["icon-diff-add-active"] = diffAdd[isDark ? 10 : 11] tokens["icon-diff-delete-base"] = diffDelete[isDark ? 8 : 9] tokens["icon-diff-delete-hover"] = diffDelete[isDark ? 9 : 10] - tokens["icon-diff-modified-base"] = isDark ? "#ffba92" : "#FF8C00" + tokens["icon-diff-modified-base"] = modified() - tokens["syntax-comment"] = "var(--text-weak)" - tokens["syntax-regexp"] = "var(--text-base)" - tokens["syntax-string"] = isDark ? "#00ceb9" : "#006656" - tokens["syntax-keyword"] = "var(--text-weak)" - tokens["syntax-primitive"] = isDark ? "#ffba92" : "#fb4804" - tokens["syntax-operator"] = isDark ? "var(--text-weak)" : "var(--text-base)" - tokens["syntax-variable"] = "var(--text-strong)" - tokens["syntax-property"] = isDark ? "#ff9ae2" : "#ed6dc8" - tokens["syntax-type"] = isDark ? "#ecf58c" : "#596600" - tokens["syntax-constant"] = isDark ? "#93e9f6" : "#007b80" - tokens["syntax-punctuation"] = isDark ? "var(--text-weak)" : "var(--text-base)" - tokens["syntax-object"] = "var(--text-strong)" - tokens["syntax-success"] = success[9] - tokens["syntax-warning"] = warning[9] - tokens["syntax-critical"] = error[isDark ? 9 : 9] - tokens["syntax-info"] = isDark ? "#93e9f6" : "#0092a8" - tokens["syntax-diff-add"] = diffAdd[10] - tokens["syntax-diff-delete"] = diffDelete[10] - tokens["syntax-diff-unknown"] = "#ff0000" + if (colors.compact) { + if (!hasInk) { + tokens["syntax-comment"] = "var(--text-weak)" + tokens["syntax-regexp"] = "var(--text-base)" + tokens["syntax-string"] = isDark ? "#00ceb9" : "#006656" + tokens["syntax-keyword"] = "var(--text-weak)" + tokens["syntax-primitive"] = isDark ? "#ffba92" : "#fb4804" + tokens["syntax-operator"] = isDark ? "var(--text-weak)" : "var(--text-base)" + tokens["syntax-variable"] = "var(--text-strong)" + tokens["syntax-property"] = isDark ? "#ff9ae2" : "#ed6dc8" + tokens["syntax-type"] = isDark ? "#ecf58c" : "#596600" + tokens["syntax-constant"] = isDark ? "#93e9f6" : "#007b80" + tokens["syntax-punctuation"] = isDark ? "var(--text-weak)" : "var(--text-base)" + tokens["syntax-object"] = "var(--text-strong)" + tokens["syntax-success"] = success[9] + tokens["syntax-warning"] = amber[9] + tokens["syntax-critical"] = error[9] + tokens["syntax-info"] = isDark ? "#93e9f6" : "#0092a8" + tokens["syntax-diff-add"] = diffAdd[10] + tokens["syntax-diff-delete"] = diffDelete[10] + tokens["syntax-diff-unknown"] = "#ff0000" - tokens["markdown-heading"] = isDark ? "#9d7cd8" : "#d68c27" - tokens["markdown-text"] = isDark ? "#eeeeee" : "#1a1a1a" - tokens["markdown-link"] = isDark ? "#fab283" : "#3b7dd8" - tokens["markdown-link-text"] = isDark ? "#56b6c2" : "#318795" - tokens["markdown-code"] = isDark ? "#7fd88f" : "#3d9a57" - tokens["markdown-block-quote"] = isDark ? "#e5c07b" : "#b0851f" - tokens["markdown-emph"] = isDark ? "#e5c07b" : "#b0851f" - tokens["markdown-strong"] = isDark ? "#f5a742" : "#d68c27" - tokens["markdown-horizontal-rule"] = isDark ? "#808080" : "#8a8a8a" - tokens["markdown-list-item"] = isDark ? "#fab283" : "#3b7dd8" - tokens["markdown-list-enumeration"] = isDark ? "#56b6c2" : "#318795" - tokens["markdown-image"] = isDark ? "#fab283" : "#3b7dd8" - tokens["markdown-image-text"] = isDark ? "#56b6c2" : "#318795" - tokens["markdown-code-block"] = isDark ? "#eeeeee" : "#1a1a1a" + tokens["markdown-heading"] = isDark ? "#9d7cd8" : "#d68c27" + tokens["markdown-text"] = isDark ? "#eeeeee" : "#1a1a1a" + tokens["markdown-link"] = isDark ? "#fab283" : "#3b7dd8" + tokens["markdown-link-text"] = isDark ? "#56b6c2" : "#318795" + tokens["markdown-code"] = isDark ? "#7fd88f" : "#3d9a57" + tokens["markdown-block-quote"] = isDark ? "#e5c07b" : "#b0851f" + tokens["markdown-emph"] = isDark ? "#e5c07b" : "#b0851f" + tokens["markdown-strong"] = isDark ? "#f5a742" : "#d68c27" + tokens["markdown-horizontal-rule"] = isDark ? "#808080" : "#8a8a8a" + tokens["markdown-list-item"] = isDark ? "#fab283" : "#3b7dd8" + tokens["markdown-list-enumeration"] = isDark ? "#56b6c2" : "#318795" + tokens["markdown-image"] = isDark ? "#fab283" : "#3b7dd8" + tokens["markdown-image-text"] = isDark ? "#56b6c2" : "#318795" + tokens["markdown-code-block"] = isDark ? "#eeeeee" : "#1a1a1a" + } + + if (hasInk) { + tokens["syntax-comment"] = "var(--text-weak)" + tokens["syntax-regexp"] = "var(--text-base)" + tokens["syntax-string"] = content(colors.success, success) + tokens["syntax-keyword"] = "var(--text-weak)" + tokens["syntax-primitive"] = content(colors.accent, accent) + tokens["syntax-operator"] = isDark ? "var(--text-weak)" : "var(--text-base)" + tokens["syntax-variable"] = "var(--text-strong)" + tokens["syntax-property"] = content(colors.primary, primary) + tokens["syntax-type"] = content(colors.warning, warning) + tokens["syntax-constant"] = content(colors.info, info) + tokens["syntax-punctuation"] = isDark ? "var(--text-weak)" : "var(--text-base)" + tokens["syntax-object"] = "var(--text-strong)" + tokens["syntax-success"] = success[9] + tokens["syntax-warning"] = amber[9] + tokens["syntax-critical"] = error[9] + tokens["syntax-info"] = content(colors.info, info) + tokens["syntax-diff-add"] = diffAdd[10] + tokens["syntax-diff-delete"] = diffDelete[10] + tokens["syntax-diff-unknown"] = "#ff0000" + + tokens["markdown-heading"] = content(colors.primary, primary) + tokens["markdown-text"] = tokens["text-base"] + tokens["markdown-link"] = content(colors.interactive, interactive) + tokens["markdown-link-text"] = content(colors.info, info) + tokens["markdown-code"] = content(colors.success, success) + tokens["markdown-block-quote"] = content(colors.warning, warning) + tokens["markdown-emph"] = content(colors.warning, warning) + tokens["markdown-strong"] = content(colors.accent, accent) + tokens["markdown-horizontal-rule"] = tokens["border-base"] + tokens["markdown-list-item"] = content(colors.interactive, interactive) + tokens["markdown-list-enumeration"] = content(colors.info, info) + tokens["markdown-image"] = content(colors.interactive, interactive) + tokens["markdown-image-text"] = content(colors.info, info) + tokens["markdown-code-block"] = tokens["text-base"] + } + } + + if (!colors.compact) { + tokens["syntax-comment"] = "var(--text-weak)" + tokens["syntax-regexp"] = "var(--text-base)" + tokens["syntax-string"] = isDark ? "#00ceb9" : "#006656" + tokens["syntax-keyword"] = "var(--text-weak)" + tokens["syntax-primitive"] = isDark ? "#ffba92" : "#fb4804" + tokens["syntax-operator"] = isDark ? "var(--text-weak)" : "var(--text-base)" + tokens["syntax-variable"] = "var(--text-strong)" + tokens["syntax-property"] = isDark ? "#ff9ae2" : "#ed6dc8" + tokens["syntax-type"] = isDark ? "#ecf58c" : "#596600" + tokens["syntax-constant"] = isDark ? "#93e9f6" : "#007b80" + tokens["syntax-punctuation"] = isDark ? "var(--text-weak)" : "var(--text-base)" + tokens["syntax-object"] = "var(--text-strong)" + tokens["syntax-success"] = success[9] + tokens["syntax-warning"] = amber[9] + tokens["syntax-critical"] = error[9] + tokens["syntax-info"] = isDark ? "#93e9f6" : "#0092a8" + tokens["syntax-diff-add"] = diffAdd[10] + tokens["syntax-diff-delete"] = diffDelete[10] + tokens["syntax-diff-unknown"] = "#ff0000" + + tokens["markdown-heading"] = isDark ? "#9d7cd8" : "#d68c27" + tokens["markdown-text"] = isDark ? "#eeeeee" : "#1a1a1a" + tokens["markdown-link"] = isDark ? "#fab283" : "#3b7dd8" + tokens["markdown-link-text"] = isDark ? "#56b6c2" : "#318795" + tokens["markdown-code"] = isDark ? "#7fd88f" : "#3d9a57" + tokens["markdown-block-quote"] = isDark ? "#e5c07b" : "#b0851f" + tokens["markdown-emph"] = isDark ? "#e5c07b" : "#b0851f" + tokens["markdown-strong"] = isDark ? "#f5a742" : "#d68c27" + tokens["markdown-horizontal-rule"] = isDark ? "#808080" : "#8a8a8a" + tokens["markdown-list-item"] = isDark ? "#fab283" : "#3b7dd8" + tokens["markdown-list-enumeration"] = isDark ? "#56b6c2" : "#318795" + tokens["markdown-image"] = isDark ? "#fab283" : "#3b7dd8" + tokens["markdown-image-text"] = isDark ? "#56b6c2" : "#318795" + tokens["markdown-code-block"] = isDark ? "#eeeeee" : "#1a1a1a" + } tokens["avatar-background-pink"] = isDark ? "#501b3f" : "#feeef8" tokens["avatar-background-mint"] = isDark ? "#033a34" : "#e1fbf4" @@ -294,13 +584,101 @@ export function resolveThemeVariant(variant: ThemeVariant, isDark: boolean): Res tokens[key] = value } + if (hasInk && "text-weak" in overrides && !("text-weaker" in overrides)) { + const weak = tokens["text-weak"] + if (weak.startsWith("#")) { + tokens["text-weaker"] = shift(weak as HexColor, { l: isDark ? -0.12 : 0.12, c: 0.75 }) + } else { + tokens["text-weaker"] = weak + } + } + + if (colors.compact && hasInk) { + if (!("markdown-text" in overrides)) { + tokens["markdown-text"] = tokens["text-base"] + } + if (!("markdown-code-block" in overrides)) { + tokens["markdown-code-block"] = tokens["text-base"] + } + } + + if (!("text-stronger" in overrides)) { + tokens["text-stronger"] = tokens["text-strong"] + } + return tokens } +interface ThemeColors { + compact: boolean + neutral: HexColor + ink?: HexColor + primary: HexColor + accent: HexColor + success: HexColor + warning: HexColor + error: HexColor + info: HexColor + interactive: HexColor + diffAdd?: HexColor + diffDelete?: HexColor +} + +function getColors(variant: ThemeVariant): ThemeColors { + const input = variant as { palette?: unknown; seeds?: unknown } + if (input.palette && input.seeds) { + throw new Error("Theme variant cannot define both `palette` and `seeds`") + } + + if (variant.palette) { + return { + compact: true, + neutral: variant.palette.neutral, + ink: variant.palette.ink, + primary: variant.palette.primary, + accent: variant.palette.accent ?? variant.palette.info, + success: variant.palette.success, + warning: variant.palette.warning, + error: variant.palette.error, + info: variant.palette.info, + interactive: variant.palette.interactive ?? variant.palette.primary, + diffAdd: variant.palette.diffAdd, + diffDelete: variant.palette.diffDelete, + } + } + + if (variant.seeds) { + return { + compact: false, + neutral: variant.seeds.neutral, + ink: undefined, + primary: variant.seeds.primary, + accent: variant.seeds.info, + success: variant.seeds.success, + warning: variant.seeds.warning, + error: variant.seeds.error, + info: variant.seeds.info, + interactive: variant.seeds.interactive, + diffAdd: variant.seeds.diffAdd, + diffDelete: variant.seeds.diffDelete, + } + } + + throw new Error("Theme variant requires `palette` or `seeds`") +} + +function generateNeutralOverlayScale(neutralScale: HexColor[], isDark: boolean): ColorValue[] { + const alphas = isDark + ? [0, 0.034, 0.063, 0.084, 0.109, 0.138, 0.181, 0.266, 0.404, 0.468, 0.603, 0.928] + : [0.014, 0.034, 0.055, 0.075, 0.096, 0.118, 0.151, 0.232, 0.453, 0.492, 0.574, 0.915] + const color = (isDark ? "#ffffff" : "#000000") as HexColor + return alphas.map((alpha) => withAlpha(color, alpha) as ColorValue) +} + function generateNeutralAlphaScale(neutralScale: HexColor[], isDark: boolean): HexColor[] { const alphas = isDark - ? [0.02, 0.04, 0.08, 0.12, 0.16, 0.2, 0.26, 0.36, 0.44, 0.52, 0.72, 0.94] - : [0.01, 0.03, 0.06, 0.09, 0.12, 0.15, 0.2, 0.27, 0.46, 0.61, 0.5, 0.87] + ? [0.024, 0.048, 0.088, 0.128, 0.17, 0.215, 0.275, 0.38, 0.46, 0.54, 0.74, 0.95] + : [0.014, 0.034, 0.066, 0.098, 0.128, 0.158, 0.208, 0.282, 0.47, 0.625, 0.515, 0.88] return neutralScale.map((hex, i) => { const baseOklch = hexToOklch(hex) @@ -312,6 +690,11 @@ function generateNeutralAlphaScale(neutralScale: HexColor[], isDark: boolean): H }) } +function getHex(value: ColorValue | undefined): HexColor | undefined { + if (!value?.startsWith("#")) return + return value as HexColor +} + export function resolveTheme(theme: DesktopTheme): { light: ResolvedTheme; dark: ResolvedTheme } { return { light: resolveThemeVariant(theme.light, false), diff --git a/packages/ui/src/theme/themes/aura.json b/packages/ui/src/theme/themes/aura.json index 874939fd4d..e65eb4b0aa 100644 --- a/packages/ui/src/theme/themes/aura.json +++ b/packages/ui/src/theme/themes/aura.json @@ -3,129 +3,37 @@ "name": "Aura", "id": "aura", "light": { - "seeds": { + "palette": { "neutral": "#f5f0ff", + "ink": "#2d2640", "primary": "#a277ff", + "accent": "#d94f4f", "success": "#40bf7a", "warning": "#d9a24a", "error": "#d94f4f", "info": "#5bb8d9", - "interactive": "#a277ff", "diffAdd": "#b3e6cc", "diffDelete": "#f5b3b3" }, "overrides": { - "background-base": "#f5f0ff", - "background-weak": "#efe8fc", - "background-strong": "#faf7ff", - "background-stronger": "#fdfcff", - "border-weak-base": "#e0d6f2", - "border-weak-hover": "#d5c9eb", - "border-weak-active": "#cbbee3", - "border-weak-selected": "#c0b3dc", - "border-weak-disabled": "#f9f6ff", - "border-weak-focus": "#c5b8df", - "border-base": "#b5a6d4", - "border-hover": "#aa99cc", - "border-active": "#9f8dc4", - "border-selected": "#9480bc", - "border-disabled": "#ede7f9", - "border-focus": "#a593c8", - "border-strong-base": "#8068a8", - "border-strong-hover": "#735a9c", - "border-strong-active": "#664d90", - "border-strong-selected": "#5a4184", - "border-strong-disabled": "#d4c8ed", - "border-strong-focus": "#6d5396", - "surface-diff-add-base": "#e8f5ed", - "surface-diff-delete-base": "#fae8e8", - "surface-diff-hidden-base": "#e8e4f5", - "text-base": "#2d2640", - "text-weak": "#5c5270", - "text-strong": "#15101f", - "syntax-string": "#40bf7a", - "syntax-primitive": "#d94f4f", - "syntax-property": "#a277ff", - "syntax-type": "#d9a24a", - "syntax-constant": "#5bb8d9", - "syntax-info": "#5bb8d9", - "markdown-heading": "#a277ff", - "markdown-text": "#2d2640", - "markdown-link": "#c17ac8", - "markdown-link-text": "#a277ff", - "markdown-code": "#40bf7a", - "markdown-block-quote": "#6d6d6d", - "markdown-emph": "#d9a24a", - "markdown-strong": "#a277ff", - "markdown-horizontal-rule": "#d4c8ed", - "markdown-list-item": "#a277ff", - "markdown-list-enumeration": "#a277ff", - "markdown-image": "#c17ac8", - "markdown-image-text": "#a277ff", - "markdown-code-block": "#5bb8d9" + "syntax-keyword": "#7b5ae0" } }, "dark": { - "seeds": { + "palette": { "neutral": "#15141b", + "ink": "#edecee", "primary": "#a277ff", + "accent": "#ff6767", "success": "#61ffca", "warning": "#ffca85", "error": "#ff6767", "info": "#82e2ff", - "interactive": "#a277ff", "diffAdd": "#61ffca", "diffDelete": "#ff6767" }, "overrides": { - "background-base": "#15141b", - "background-weak": "#1a1921", - "background-strong": "#121118", - "background-stronger": "#0f0e14", - "border-weak-base": "#2d2b38", - "border-weak-hover": "#332f42", - "border-weak-active": "#38354c", - "border-weak-selected": "#3e3a56", - "border-weak-disabled": "#1a1921", - "border-weak-focus": "#363350", - "border-base": "#433f5a", - "border-hover": "#4a4565", - "border-active": "#514c70", - "border-selected": "#58527b", - "border-disabled": "#1f1e28", - "border-focus": "#4e496c", - "border-strong-base": "#635c8a", - "border-strong-hover": "#6d6597", - "border-strong-active": "#776fa4", - "border-strong-selected": "#8179b1", - "border-strong-disabled": "#2a283a", - "border-strong-focus": "#716a9e", - "surface-diff-add-base": "#162620", - "surface-diff-delete-base": "#26161a", - "surface-diff-hidden-base": "#1e1d2a", - "text-base": "#edecee", - "text-weak": "#6d6d6d", - "text-strong": "#ffffff", - "syntax-string": "#61ffca", - "syntax-primitive": "#ff6767", - "syntax-property": "#a277ff", - "syntax-type": "#ffca85", - "syntax-constant": "#82e2ff", - "syntax-info": "#82e2ff", - "markdown-heading": "#a277ff", - "markdown-text": "#edecee", - "markdown-link": "#f694ff", - "markdown-link-text": "#a277ff", - "markdown-code": "#61ffca", - "markdown-block-quote": "#6d6d6d", - "markdown-emph": "#ffca85", - "markdown-strong": "#a277ff", - "markdown-horizontal-rule": "#2d2b38", - "markdown-list-item": "#a277ff", - "markdown-list-enumeration": "#a277ff", - "markdown-image": "#f694ff", - "markdown-image-text": "#a277ff", - "markdown-code-block": "#edecee" + "syntax-keyword": "#a277ff" } } } diff --git a/packages/ui/src/theme/themes/ayu.json b/packages/ui/src/theme/themes/ayu.json index eac9e0491f..f459489035 100644 --- a/packages/ui/src/theme/themes/ayu.json +++ b/packages/ui/src/theme/themes/ayu.json @@ -3,131 +3,37 @@ "name": "Ayu", "id": "ayu", "light": { - "seeds": { + "palette": { "neutral": "#fdfaf4", + "ink": "#4f5964", "primary": "#4aa8c8", + "accent": "#ef7d71", "success": "#5fb978", "warning": "#ea9f41", "error": "#e6656a", "info": "#2f9bce", - "interactive": "#4aa8c8", "diffAdd": "#b1d780", "diffDelete": "#e6656a" }, "overrides": { - "background-base": "#fdfaf4", - "background-weak": "#fcf9f3", - "background-strong": "#fbf8f2", - "background-stronger": "#faf7f1", - "surface-raised-base-hover": "#f4f0e9", - "border-weak-base": "#e6ddcf", - "border-weak-hover": "#dcd3c5", - "border-weak-active": "#d1c9ba", - "border-weak-selected": "#c6bfaf", - "border-weak-disabled": "#f7f0e6", - "border-weak-focus": "#cbc4b6", - "border-base": "#bfb3a3", - "border-hover": "#b4a898", - "border-active": "#a99e8e", - "border-selected": "#9e9383", - "border-disabled": "#efe5d8", - "border-focus": "#b09f8f", - "border-strong-base": "#837765", - "border-strong-hover": "#7a6f5f", - "border-strong-active": "#716655", - "border-strong-selected": "#685e4e", - "border-strong-disabled": "#d8cabc", - "border-strong-focus": "#766b5c", - "surface-diff-add-base": "#eef5e4", - "surface-diff-delete-base": "#fde5e5", - "surface-diff-hidden-base": "#e3edf3", - "text-base": "#4f5964", - "text-weak": "#77818d", - "text-strong": "#1b232b", - "syntax-string": "#7fad00", - "syntax-primitive": "#ef7d71", - "syntax-property": "#4aa8c8", - "syntax-type": "#ed982e", - "syntax-constant": "#2f9bce", - "syntax-info": "#2f9bce", - "markdown-heading": "#4aa8c8", - "markdown-text": "#4f5964", - "markdown-link": "#4aa8c8", - "markdown-link-text": "#2f9bce", - "markdown-code": "#7fad00", - "markdown-block-quote": "#ed982e", - "markdown-emph": "#ed982e", - "markdown-strong": "#f07f72", - "markdown-horizontal-rule": "#d7cec0", - "markdown-list-item": "#4aa8c8", - "markdown-list-enumeration": "#2f9bce", - "markdown-image": "#4aa8c8", - "markdown-image-text": "#2f9bce", - "markdown-code-block": "#4aa8c8" + "syntax-keyword": "#ea9f41" } }, "dark": { - "seeds": { + "palette": { "neutral": "#0f1419", + "ink": "#d6dae0", "primary": "#3fb7e3", + "accent": "#f2856f", "success": "#78d05c", "warning": "#e4a75c", "error": "#f58572", "info": "#66c6f1", - "interactive": "#3fb7e3", "diffAdd": "#59c57c", "diffDelete": "#f58572" }, "overrides": { - "background-base": "#0f1419", - "background-weak": "#18222c", - "background-strong": "#0b1015", - "background-stronger": "#080c10", - "surface-raised-base-hover": "#0f1419", - "border-weak-base": "#2b3440", - "border-weak-hover": "#323c49", - "border-weak-active": "#394454", - "border-weak-selected": "#415063", - "border-weak-disabled": "#0a0e12", - "border-weak-focus": "#374453", - "border-base": "#475367", - "border-hover": "#515f75", - "border-active": "#5d6b83", - "border-selected": "#687795", - "border-disabled": "#11161d", - "border-focus": "#56647c", - "border-strong-base": "#73819b", - "border-strong-hover": "#7f8da8", - "border-strong-active": "#8b99b5", - "border-strong-selected": "#98a6c3", - "border-strong-disabled": "#1b222c", - "border-strong-focus": "#8391ad", - "surface-diff-add-base": "#132f27", - "surface-diff-delete-base": "#361d20", - "surface-diff-hidden-base": "#1b2632", - "text-base": "#d6dae0", - "text-weak": "#a3adba", - "text-strong": "#fbfbfd", - "syntax-string": "#b1c74a", - "syntax-primitive": "#f2856f", - "syntax-property": "#3fb7e3", - "syntax-type": "#e4a75c", - "syntax-constant": "#66c6f1", - "syntax-info": "#66c6f1", - "markdown-heading": "#3fb7e3", - "markdown-text": "#d6dae0", - "markdown-link": "#3fb7e3", - "markdown-link-text": "#66c6f1", - "markdown-code": "#b1c74a", - "markdown-block-quote": "#e4a75c", - "markdown-emph": "#e4a75c", - "markdown-strong": "#f2856f", - "markdown-horizontal-rule": "#2b3542", - "markdown-list-item": "#3fb7e3", - "markdown-list-enumeration": "#66c6f1", - "markdown-image": "#3fb7e3", - "markdown-image-text": "#66c6f1", - "markdown-code-block": "#d6dae0" + "syntax-keyword": "#ffad66" } } } diff --git a/packages/ui/src/theme/themes/carbonfox.json b/packages/ui/src/theme/themes/carbonfox.json index e2fa20d803..54e55cdeae 100644 --- a/packages/ui/src/theme/themes/carbonfox.json +++ b/packages/ui/src/theme/themes/carbonfox.json @@ -3,9 +3,11 @@ "name": "Carbonfox", "id": "carbonfox", "light": { - "seeds": { + "palette": { "neutral": "#8e8e8e", + "ink": "#161616", "primary": "#0072c3", + "accent": "#da1e28", "success": "#198038", "warning": "#f1c21b", "error": "#da1e28", @@ -15,44 +17,15 @@ "diffDelete": "#da1e28" }, "overrides": { - "background-base": "#ffffff", - "background-weak": "#f4f4f4", - "background-strong": "#e8e8e8", - "background-stronger": "#dcdcdc", - "surface-raised-strong": "#ffffff", - "surface-raised-stronger": "#ffffff", - "surface-float-base": "#161616", - "surface-float-base-hover": "#262626", - "text-base": "#161616", - "text-weak": "#525252", - "text-strong": "#000000", - "syntax-string": "#198038", - "syntax-primitive": "#da1e28", - "syntax-property": "#0043ce", - "syntax-type": "#007d79", - "syntax-constant": "#6929c4", - "syntax-keyword": "#525252", - "syntax-info": "#0043ce", - "markdown-heading": "#0043ce", - "markdown-text": "#161616", - "markdown-link": "#0043ce", - "markdown-link-text": "#0072c3", - "markdown-code": "#198038", - "markdown-block-quote": "#525252", - "markdown-emph": "#6929c4", - "markdown-strong": "#161616", - "markdown-horizontal-rule": "#c6c6c6", - "markdown-list-item": "#0072c3", - "markdown-list-enumeration": "#0072c3", - "markdown-image": "#0043ce", - "markdown-image-text": "#0072c3", - "markdown-code-block": "#393939" + "syntax-keyword": "#8a3ffc" } }, "dark": { - "seeds": { + "palette": { "neutral": "#393939", + "ink": "#f2f4f8", "primary": "#33b1ff", + "accent": "#ff8389", "success": "#42be65", "warning": "#f1c21b", "error": "#ff8389", @@ -62,61 +35,7 @@ "diffDelete": "#ff8389" }, "overrides": { - "background-base": "#161616", - "background-weak": "#262626", - "background-strong": "#0d0d0d", - "background-stronger": "#000000", - "surface-raised-base": "#1c1c1c", - "surface-raised-base-hover": "#262626", - "surface-raised-strong": "#262626", - "surface-raised-strong-hover": "#303030", - "surface-raised-stronger": "#303030", - "surface-raised-stronger-hover": "#393939", - "surface-raised-stronger-non-alpha": "#303030", - "surface-float-base": "#0d0d0d", - "surface-float-base-hover": "#1a1a1a", - "surface-inset-base": "#0d0d0d", - "surface-inset-strong": "#000000", - "surface-base": "#1e1e1e", - "surface-base-hover": "#262626", - "surface-diff-add-base": "#0e3a22", - "surface-diff-delete-base": "#4d1a1f", - "input-base": "#262626", - "input-hover": "#303030", - "button-secondary-base": "#393939", - "button-secondary-hover": "#4c4c4c", - "border-weak-base": "#393939", - "border-weak-hover": "#4c4c4c", - "border-base": "#525252", - "border-hover": "#636363", - "border-strong-base": "#6f6f6f", - "text-base": "#f2f4f8", - "text-weak": "#8d8d8d", - "text-weaker": "#6f6f6f", - "text-strong": "#ffffff", - "icon-base": "#8d8d8d", - "icon-weak-base": "#6f6f6f", - "syntax-string": "#42be65", - "syntax-primitive": "#ff8389", - "syntax-property": "#78a9ff", - "syntax-type": "#08bdba", - "syntax-constant": "#be95ff", - "syntax-keyword": "#8d8d8d", - "syntax-info": "#78a9ff", - "markdown-heading": "#82cfff", - "markdown-text": "#f2f4f8", - "markdown-link": "#78a9ff", - "markdown-link-text": "#33b1ff", - "markdown-code": "#42be65", - "markdown-block-quote": "#8d8d8d", - "markdown-emph": "#be95ff", - "markdown-strong": "#ffffff", - "markdown-horizontal-rule": "#393939", - "markdown-list-item": "#33b1ff", - "markdown-list-enumeration": "#33b1ff", - "markdown-image": "#78a9ff", - "markdown-image-text": "#33b1ff", - "markdown-code-block": "#c6c6c6" + "syntax-keyword": "#be95ff" } } } diff --git a/packages/ui/src/theme/themes/catppuccin.json b/packages/ui/src/theme/themes/catppuccin.json index 2a32df0984..66fd37e26b 100644 --- a/packages/ui/src/theme/themes/catppuccin.json +++ b/packages/ui/src/theme/themes/catppuccin.json @@ -3,129 +3,39 @@ "name": "Catppuccin", "id": "catppuccin", "light": { - "seeds": { + "palette": { "neutral": "#f5e0dc", + "ink": "#4c4f69", "primary": "#7287fd", + "accent": "#d20f39", "success": "#40a02b", "warning": "#df8e1d", "error": "#d20f39", "info": "#04a5e5", - "interactive": "#7287fd", "diffAdd": "#a6d189", "diffDelete": "#e78284" }, "overrides": { - "background-base": "#f5e0dc", - "background-weak": "#f2d8d4", - "background-strong": "#f9e8e4", - "background-stronger": "#fdeeee", - "border-weak-base": "#e0cfd3", - "border-weak-hover": "#d6c4c8", - "border-weak-active": "#cdb9be", - "border-weak-selected": "#c2aeb4", - "border-weak-disabled": "#fbeff2", - "border-weak-focus": "#c7b4ba", - "border-base": "#bca6b2", - "border-hover": "#b19ca8", - "border-active": "#a6929e", - "border-selected": "#9a8894", - "border-disabled": "#f3e4e7", - "border-focus": "#ab97a1", - "border-strong-base": "#83677f", - "border-strong-hover": "#775b73", - "border-strong-active": "#6b5068", - "border-strong-selected": "#5f465d", - "border-strong-disabled": "#d9c5cf", - "border-strong-focus": "#714f66", - "surface-diff-add-base": "#edf5e6", - "surface-diff-delete-base": "#fde1e3", - "surface-diff-hidden-base": "#e4e2f6", - "text-base": "#4c4f69", - "text-weak": "#6c6f85", - "text-strong": "#1f1f2a", - "syntax-string": "#40a02b", - "syntax-primitive": "#d20f39", - "syntax-property": "#7287fd", - "syntax-type": "#df8e1d", - "syntax-constant": "#04a5e5", - "syntax-info": "#04a5e5", - "markdown-heading": "#7287fd", - "markdown-text": "#4c4f69", - "markdown-link": "#7287fd", - "markdown-link-text": "#04a5e5", - "markdown-code": "#40a02b", - "markdown-block-quote": "#df8e1d", - "markdown-emph": "#df8e1d", - "markdown-strong": "#d20f39", - "markdown-horizontal-rule": "#d4c5cf", - "markdown-list-item": "#7287fd", - "markdown-list-enumeration": "#04a5e5", - "markdown-image": "#7287fd", - "markdown-image-text": "#04a5e5", - "markdown-code-block": "#7287fd" + "syntax-keyword": "#8839ef", + "syntax-primitive": "#fe640b" } }, "dark": { - "seeds": { + "palette": { "neutral": "#1e1e2e", + "ink": "#cdd6f4", "primary": "#b4befe", + "accent": "#f38ba8", "success": "#a6d189", "warning": "#f4b8e4", "error": "#f38ba8", "info": "#89dceb", - "interactive": "#b4befe", "diffAdd": "#94e2d5", "diffDelete": "#f38ba8" }, "overrides": { - "background-base": "#1e1e2e", - "background-weak": "#211f31", - "background-strong": "#1c1c29", - "background-stronger": "#191926", - "border-weak-base": "#35324a", - "border-weak-hover": "#393655", - "border-weak-active": "#403c61", - "border-weak-selected": "#47436d", - "border-weak-disabled": "#141426", - "border-weak-focus": "#3d3a63", - "border-base": "#4a4763", - "border-hover": "#524f70", - "border-active": "#5a577d", - "border-selected": "#625f8a", - "border-disabled": "#1b1a2c", - "border-focus": "#575379", - "border-strong-base": "#6e6a8c", - "border-strong-hover": "#787497", - "border-strong-active": "#8380a2", - "border-strong-selected": "#8d8bad", - "border-strong-disabled": "#232237", - "border-strong-focus": "#7b779b", - "surface-diff-add-base": "#1d2c30", - "surface-diff-delete-base": "#2c1f2a", - "surface-diff-hidden-base": "#232538", - "text-base": "#cdd6f4", - "text-weak": "#a6adc8", - "text-strong": "#f4f2ff", - "syntax-string": "#a6e3a1", - "syntax-primitive": "#f38ba8", - "syntax-property": "#b4befe", - "syntax-type": "#f9e2af", - "syntax-constant": "#89dceb", - "syntax-info": "#89dceb", - "markdown-heading": "#b4befe", - "markdown-text": "#cdd6f4", - "markdown-link": "#b4befe", - "markdown-link-text": "#89dceb", - "markdown-code": "#a6e3a1", - "markdown-block-quote": "#f9e2af", - "markdown-emph": "#f9e2af", - "markdown-strong": "#f38ba8", - "markdown-horizontal-rule": "#2e2d45", - "markdown-list-item": "#b4befe", - "markdown-list-enumeration": "#89dceb", - "markdown-image": "#b4befe", - "markdown-image-text": "#89dceb", - "markdown-code-block": "#cdd6f4" + "syntax-keyword": "#cba6f7", + "syntax-primitive": "#fab387" } } } diff --git a/packages/ui/src/theme/themes/dracula.json b/packages/ui/src/theme/themes/dracula.json index 696f1060c7..495042ca7b 100644 --- a/packages/ui/src/theme/themes/dracula.json +++ b/packages/ui/src/theme/themes/dracula.json @@ -3,129 +3,41 @@ "name": "Dracula", "id": "dracula", "light": { - "seeds": { + "palette": { "neutral": "#f8f8f2", + "ink": "#1f1f2f", "primary": "#7c6bf5", + "accent": "#d16090", "success": "#2fbf71", "warning": "#f7a14d", "error": "#d9536f", "info": "#1d7fc5", - "interactive": "#7c6bf5", "diffAdd": "#9fe3b3", "diffDelete": "#f8a1b8" }, "overrides": { - "background-base": "#f8f8f2", - "background-weak": "#f1f2ed", - "background-strong": "#f6f6f1", - "background-stronger": "#f2f2ec", - "border-weak-base": "#e2e3da", - "border-weak-hover": "#d8d9d0", - "border-weak-active": "#cfd0c7", - "border-weak-selected": "#c4c6bc", - "border-weak-disabled": "#eceee3", - "border-weak-focus": "#c9cabf", - "border-base": "#c4c6ba", - "border-hover": "#b8baae", - "border-active": "#abada3", - "border-selected": "#979a90", - "border-disabled": "#e5e7dd", - "border-focus": "#b0b2a7", - "border-strong-base": "#9fa293", - "border-strong-hover": "#8e9185", - "border-strong-active": "#7e8176", - "border-strong-selected": "#6f7268", - "border-strong-disabled": "#c7c9be", - "border-strong-focus": "#878b7f", - "surface-diff-add-base": "#e4f5e6", - "surface-diff-delete-base": "#fae4eb", - "surface-diff-hidden-base": "#dedfe9", - "text-base": "#1f1f2f", - "text-weak": "#52526b", - "text-strong": "#05040c", - "syntax-string": "#2fbf71", - "syntax-primitive": "#d16090", - "syntax-property": "#7c6bf5", - "syntax-type": "#f7a14d", - "syntax-constant": "#1d7fc5", - "syntax-info": "#1d7fc5", - "markdown-heading": "#7c6bf5", - "markdown-text": "#1f1f2f", - "markdown-link": "#7c6bf5", - "markdown-link-text": "#1d7fc5", - "markdown-code": "#2fbf71", - "markdown-block-quote": "#f7a14d", - "markdown-emph": "#f7a14d", - "markdown-strong": "#d16090", - "markdown-horizontal-rule": "#c3c5d4", - "markdown-list-item": "#7c6bf5", - "markdown-list-enumeration": "#1d7fc5", - "markdown-image": "#7c6bf5", - "markdown-image-text": "#1d7fc5", - "markdown-code-block": "#1d7fc5" + "syntax-keyword": "#d16090", + "syntax-string": "#596600", + "syntax-primitive": "#7c6bf5" } }, "dark": { - "seeds": { + "palette": { "neutral": "#1d1e28", + "ink": "#f8f8f2", "primary": "#bd93f9", + "accent": "#ff79c6", "success": "#50fa7b", "warning": "#ffb86c", "error": "#ff5555", "info": "#8be9fd", - "interactive": "#bd93f9", "diffAdd": "#2fb27d", "diffDelete": "#ff6b81" }, "overrides": { - "background-base": "#14151f", - "background-weak": "#181926", - "background-strong": "#161722", - "background-stronger": "#191a26", - "border-weak-base": "#2d2f3c", - "border-weak-hover": "#303244", - "border-weak-active": "#35364c", - "border-weak-selected": "#3b3d55", - "border-weak-disabled": "#1e1f2b", - "border-weak-focus": "#383a50", - "border-base": "#3f415a", - "border-hover": "#464967", - "border-active": "#4d5073", - "border-selected": "#55587f", - "border-disabled": "#272834", - "border-focus": "#4a4d6d", - "border-strong-base": "#606488", - "border-strong-hover": "#6a6e96", - "border-strong-active": "#7378a3", - "border-strong-selected": "#7d82b1", - "border-strong-disabled": "#343649", - "border-strong-focus": "#6f739c", - "surface-diff-add-base": "#1f2a2f", - "surface-diff-delete-base": "#2d1f27", - "surface-diff-hidden-base": "#24253a", - "text-base": "#f8f8f2", - "text-weak": "#b6b9e4", - "text-strong": "#ffffff", - "syntax-string": "#50fa7b", - "syntax-primitive": "#ff79c6", - "syntax-property": "#bd93f9", - "syntax-type": "#ffb86c", - "syntax-constant": "#8be9fd", - "syntax-info": "#8be9fd", - "markdown-heading": "#bd93f9", - "markdown-text": "#f8f8f2", - "markdown-link": "#bd93f9", - "markdown-link-text": "#8be9fd", - "markdown-code": "#50fa7b", - "markdown-block-quote": "#ffb86c", - "markdown-emph": "#ffb86c", - "markdown-strong": "#ff79c6", - "markdown-horizontal-rule": "#44475a", - "markdown-list-item": "#bd93f9", - "markdown-list-enumeration": "#8be9fd", - "markdown-image": "#bd93f9", - "markdown-image-text": "#8be9fd", - "markdown-code-block": "#f8f8f2" + "syntax-keyword": "#ff79c6", + "syntax-string": "#f1fa8c", + "syntax-primitive": "#bd93f9" } } } diff --git a/packages/ui/src/theme/themes/gruvbox.json b/packages/ui/src/theme/themes/gruvbox.json index cf87ccd553..f078db2d4c 100644 --- a/packages/ui/src/theme/themes/gruvbox.json +++ b/packages/ui/src/theme/themes/gruvbox.json @@ -3,130 +3,39 @@ "name": "Gruvbox", "id": "gruvbox", "light": { - "seeds": { + "palette": { "neutral": "#fbf1c7", + "ink": "#3c3836", "primary": "#076678", + "accent": "#9d0006", "success": "#79740e", "warning": "#b57614", "error": "#9d0006", "info": "#8f3f71", - "interactive": "#076678", "diffAdd": "#79740e", "diffDelete": "#9d0006" }, "overrides": { - "background-base": "#fbf1c7", - "background-weak": "#f2e5bc", - "background-strong": "#f9f5d7", - "background-stronger": "#fdf9e8", - "surface-raised-stronger-non-alpha": "#fbfaf5", - "border-weak-base": "#d5c4a1", - "border-weak-hover": "#c9b897", - "border-weak-active": "#bdae93", - "border-weak-selected": "#b0a285", - "border-weak-disabled": "#f0e4b8", - "border-weak-focus": "#c4b590", - "border-base": "#bdae93", - "border-hover": "#b0a285", - "border-active": "#a89984", - "border-selected": "#928374", - "border-disabled": "#e5d9ad", - "border-focus": "#a89984", - "border-strong-base": "#7c6f64", - "border-strong-hover": "#6e6259", - "border-strong-active": "#665c54", - "border-strong-selected": "#5a524b", - "border-strong-disabled": "#c9bda1", - "border-strong-focus": "#665c54", - "surface-diff-add-base": "#dde3b1", - "surface-diff-delete-base": "#e8c7c3", - "surface-diff-hidden-base": "#ebdfb5", - "text-base": "#3c3836", - "text-weak": "#7c6f64", - "text-strong": "#282828", - "syntax-string": "#79740e", - "syntax-primitive": "#9d0006", - "syntax-property": "#076678", - "syntax-type": "#b57614", - "syntax-constant": "#8f3f71", - "syntax-info": "#427b58", - "markdown-heading": "#076678", - "markdown-text": "#3c3836", - "markdown-link": "#076678", - "markdown-link-text": "#427b58", - "markdown-code": "#79740e", - "markdown-block-quote": "#928374", - "markdown-emph": "#8f3f71", - "markdown-strong": "#af3a03", - "markdown-horizontal-rule": "#d5c4a1", - "markdown-list-item": "#076678", - "markdown-list-enumeration": "#427b58", - "markdown-image": "#076678", - "markdown-image-text": "#427b58", - "markdown-code-block": "#3c3836" + "syntax-keyword": "#9d0006", + "syntax-primitive": "#8f3f71" } }, "dark": { - "seeds": { + "palette": { "neutral": "#282828", + "ink": "#ebdbb2", "primary": "#83a598", + "accent": "#fb4934", "success": "#b8bb26", "warning": "#fabd2f", "error": "#fb4934", "info": "#d3869b", - "interactive": "#83a598", "diffAdd": "#b8bb26", "diffDelete": "#fb4934" }, "overrides": { - "background-base": "#282828", - "background-weak": "#32302f", - "background-strong": "#1d2021", - "background-stronger": "#141617", - "border-weak-base": "#504945", - "border-weak-hover": "#5a524b", - "border-weak-active": "#665c54", - "border-weak-selected": "#70665d", - "border-weak-disabled": "#1e1d1c", - "border-weak-focus": "#5e5650", - "border-base": "#665c54", - "border-hover": "#70665d", - "border-active": "#7c6f64", - "border-selected": "#928374", - "border-disabled": "#2a2827", - "border-focus": "#7c6f64", - "border-strong-base": "#928374", - "border-strong-hover": "#9d8e7f", - "border-strong-active": "#a89984", - "border-strong-selected": "#b3a48f", - "border-strong-disabled": "#3c3836", - "border-strong-focus": "#a89984", - "surface-diff-add-base": "#2a3325", - "surface-diff-delete-base": "#3c2222", - "surface-diff-hidden-base": "#32302f", - "text-base": "#ebdbb2", - "text-weak": "#a89984", - "text-strong": "#fbf1c7", - "syntax-string": "#b8bb26", - "syntax-primitive": "#fb4934", - "syntax-property": "#83a598", - "syntax-type": "#fabd2f", - "syntax-constant": "#d3869b", - "syntax-info": "#8ec07c", - "markdown-heading": "#83a598", - "markdown-text": "#ebdbb2", - "markdown-link": "#83a598", - "markdown-link-text": "#8ec07c", - "markdown-code": "#b8bb26", - "markdown-block-quote": "#928374", - "markdown-emph": "#d3869b", - "markdown-strong": "#fe8019", - "markdown-horizontal-rule": "#504945", - "markdown-list-item": "#83a598", - "markdown-list-enumeration": "#8ec07c", - "markdown-image": "#83a598", - "markdown-image-text": "#8ec07c", - "markdown-code-block": "#ebdbb2" + "syntax-keyword": "#fb4934", + "syntax-primitive": "#d3869b" } } } diff --git a/packages/ui/src/theme/themes/monokai.json b/packages/ui/src/theme/themes/monokai.json index d49846ddb3..3a2656b6ea 100644 --- a/packages/ui/src/theme/themes/monokai.json +++ b/packages/ui/src/theme/themes/monokai.json @@ -3,129 +3,41 @@ "name": "Monokai", "id": "monokai", "light": { - "seeds": { + "palette": { "neutral": "#fdf8ec", + "ink": "#292318", "primary": "#bf7bff", + "accent": "#d9487c", "success": "#4fb54b", "warning": "#f1a948", "error": "#e54b4b", "info": "#2d9ad7", - "interactive": "#bf7bff", "diffAdd": "#bfe7a3", "diffDelete": "#f6a3ae" }, "overrides": { - "background-base": "#fdf8ec", - "background-weak": "#f8f2e6", - "background-strong": "#fbf5e8", - "background-stronger": "#f7efdd", - "border-weak-base": "#e9e0cf", - "border-weak-hover": "#dfd5c3", - "border-weak-active": "#d5cab7", - "border-weak-selected": "#cabfad", - "border-weak-disabled": "#f3ebdd", - "border-weak-focus": "#d0c2b1", - "border-base": "#c7b9a5", - "border-hover": "#bcae98", - "border-active": "#b0a28c", - "border-selected": "#a49781", - "border-disabled": "#efe5d6", - "border-focus": "#b6a893", - "border-strong-base": "#998b76", - "border-strong-hover": "#8a7c67", - "border-strong-active": "#7a6d58", - "border-strong-selected": "#6c604c", - "border-strong-disabled": "#d7cabc", - "border-strong-focus": "#82745f", - "surface-diff-add-base": "#e8f7e1", - "surface-diff-delete-base": "#fde5e4", - "surface-diff-hidden-base": "#e9e0d0", - "text-base": "#292318", - "text-weak": "#6d5c40", - "text-strong": "#1c150c", - "syntax-string": "#4fb54b", - "syntax-primitive": "#d9487c", - "syntax-property": "#bf7bff", - "syntax-type": "#f1a948", - "syntax-constant": "#2d9ad7", - "syntax-info": "#2d9ad7", - "markdown-heading": "#bf7bff", - "markdown-text": "#292318", - "markdown-link": "#bf7bff", - "markdown-link-text": "#2d9ad7", - "markdown-code": "#4fb54b", - "markdown-block-quote": "#f1a948", - "markdown-emph": "#f1a948", - "markdown-strong": "#d9487c", - "markdown-horizontal-rule": "#cdbdab", - "markdown-list-item": "#bf7bff", - "markdown-list-enumeration": "#2d9ad7", - "markdown-image": "#bf7bff", - "markdown-image-text": "#2d9ad7", - "markdown-code-block": "#2d9ad7" + "syntax-keyword": "#d9487c", + "syntax-string": "#8a6500", + "syntax-primitive": "#bf7bff" } }, "dark": { - "seeds": { + "palette": { "neutral": "#272822", + "ink": "#f8f8f2", "primary": "#ae81ff", + "accent": "#f92672", "success": "#a6e22e", "warning": "#fd971f", "error": "#f92672", "info": "#66d9ef", - "interactive": "#ae81ff", "diffAdd": "#4d7f2a", "diffDelete": "#f4477c" }, "overrides": { - "background-base": "#23241e", - "background-weak": "#27281f", - "background-strong": "#25261f", - "background-stronger": "#292a23", - "border-weak-base": "#343528", - "border-weak-hover": "#393a2d", - "border-weak-active": "#3f4033", - "border-weak-selected": "#454639", - "border-weak-disabled": "#1d1e16", - "border-weak-focus": "#414235", - "border-base": "#494a3a", - "border-hover": "#50523f", - "border-active": "#585a45", - "border-selected": "#60624b", - "border-disabled": "#23241b", - "border-focus": "#555741", - "border-strong-base": "#6a6c55", - "border-strong-hover": "#73755d", - "border-strong-active": "#7d7f66", - "border-strong-selected": "#878970", - "border-strong-disabled": "#2c2d23", - "border-strong-focus": "#7a7c63", - "surface-diff-add-base": "#1e2a1d", - "surface-diff-delete-base": "#301c24", - "surface-diff-hidden-base": "#2f2f24", - "text-base": "#f8f8f2", - "text-weak": "#c5c5c0", - "text-strong": "#ffffff", - "syntax-string": "#a6e22e", - "syntax-primitive": "#f92672", - "syntax-property": "#ae81ff", - "syntax-type": "#fd971f", - "syntax-constant": "#66d9ef", - "syntax-info": "#66d9ef", - "markdown-heading": "#ae81ff", - "markdown-text": "#f8f8f2", - "markdown-link": "#ae81ff", - "markdown-link-text": "#66d9ef", - "markdown-code": "#a6e22e", - "markdown-block-quote": "#fd971f", - "markdown-emph": "#fd971f", - "markdown-strong": "#f92672", - "markdown-horizontal-rule": "#3b3c34", - "markdown-list-item": "#ae81ff", - "markdown-list-enumeration": "#66d9ef", - "markdown-image": "#ae81ff", - "markdown-image-text": "#66d9ef", - "markdown-code-block": "#f8f8f2" + "syntax-keyword": "#f92672", + "syntax-string": "#e6db74", + "syntax-primitive": "#ae81ff" } } } diff --git a/packages/ui/src/theme/themes/nightowl.json b/packages/ui/src/theme/themes/nightowl.json index 5b0331e5fd..d6b4d4dad2 100644 --- a/packages/ui/src/theme/themes/nightowl.json +++ b/packages/ui/src/theme/themes/nightowl.json @@ -3,129 +3,40 @@ "name": "Night Owl", "id": "nightowl", "light": { - "seeds": { + "palette": { "neutral": "#f0f0f0", + "ink": "#403f53", "primary": "#4876d6", + "accent": "#aa0982", "success": "#2aa298", "warning": "#c96765", "error": "#de3d3b", "info": "#4876d6", - "interactive": "#4876d6", "diffAdd": "#2aa298", "diffDelete": "#de3d3b" }, "overrides": { - "background-base": "#fbfbfb", - "background-weak": "#f0f0f0", - "background-strong": "#ffffff", - "background-stronger": "#ffffff", - "border-weak-base": "#d9d9d9", - "border-weak-hover": "#cccccc", - "border-weak-active": "#bfbfbf", - "border-weak-selected": "#4876d6", - "border-weak-disabled": "#e6e6e6", - "border-weak-focus": "#4876d6", - "border-base": "#c0c0c0", - "border-hover": "#b3b3b3", - "border-active": "#a6a6a6", - "border-selected": "#4876d6", - "border-disabled": "#d9d9d9", - "border-focus": "#4876d6", - "border-strong-base": "#90a7b2", - "border-strong-hover": "#7d9aa6", - "border-strong-active": "#6a8d9a", - "border-strong-selected": "#4876d6", - "border-strong-disabled": "#c0c0c0", - "border-strong-focus": "#4876d6", - "surface-diff-add-base": "#eaf8f6", - "surface-diff-delete-base": "#fbe9e9", - "surface-diff-hidden-base": "#e8f0fc", - "text-base": "#403f53", - "text-weak": "#7a8181", - "text-strong": "#1a1a1a", - "syntax-string": "#c96765", - "syntax-primitive": "#aa0982", - "syntax-property": "#4876d6", - "syntax-type": "#994cc3", - "syntax-constant": "#2aa298", - "syntax-info": "#4876d6", - "markdown-heading": "#4876d6", - "markdown-text": "#403f53", - "markdown-link": "#4876d6", - "markdown-link-text": "#2aa298", - "markdown-code": "#2aa298", - "markdown-block-quote": "#7a8181", - "markdown-emph": "#994cc3", - "markdown-strong": "#c96765", - "markdown-horizontal-rule": "#90a7b2", - "markdown-list-item": "#4876d6", - "markdown-list-enumeration": "#2aa298", - "markdown-image": "#4876d6", - "markdown-image-text": "#2aa298", - "markdown-code-block": "#403f53" + "syntax-keyword": "#994cc3" } }, "dark": { - "seeds": { + "palette": { "neutral": "#011627", + "ink": "#d6deeb", "primary": "#82aaff", + "accent": "#f78c6c", "success": "#c5e478", "warning": "#ecc48d", "error": "#ef5350", "info": "#82aaff", - "interactive": "#82aaff", "diffAdd": "#c5e478", "diffDelete": "#ef5350" }, "overrides": { - "background-base": "#011627", - "background-weak": "#0b253a", - "background-strong": "#001122", - "background-stronger": "#000c17", - "border-weak-base": "#1d3b53", - "border-weak-hover": "#234561", - "border-weak-active": "#2a506f", - "border-weak-selected": "#82aaff", - "border-weak-disabled": "#0f2132", - "border-weak-focus": "#82aaff", - "border-base": "#3a5a75", - "border-hover": "#456785", - "border-active": "#507494", - "border-selected": "#82aaff", - "border-disabled": "#1a3347", - "border-focus": "#82aaff", - "border-strong-base": "#5f7e97", - "border-strong-hover": "#6e8da6", - "border-strong-active": "#7d9cb5", - "border-strong-selected": "#82aaff", - "border-strong-disabled": "#2c4a63", - "border-strong-focus": "#82aaff", - "surface-diff-add-base": "#0a2e1a", - "surface-diff-delete-base": "#2d1b1b", - "surface-diff-hidden-base": "#0b253a", - "text-base": "#d6deeb", - "text-weak": "#5f7e97", - "text-strong": "#ffffff", + "syntax-comment": "#637777", + "syntax-keyword": "#c792ea", "syntax-string": "#ecc48d", - "syntax-primitive": "#f78c6c", - "syntax-property": "#82aaff", - "syntax-type": "#c5e478", - "syntax-constant": "#7fdbca", - "syntax-info": "#82aaff", - "markdown-heading": "#82aaff", - "markdown-text": "#d6deeb", - "markdown-link": "#82aaff", - "markdown-link-text": "#7fdbca", - "markdown-code": "#c5e478", - "markdown-block-quote": "#5f7e97", - "markdown-emph": "#c792ea", - "markdown-strong": "#ecc48d", - "markdown-horizontal-rule": "#5f7e97", - "markdown-list-item": "#82aaff", - "markdown-list-enumeration": "#7fdbca", - "markdown-image": "#82aaff", - "markdown-image-text": "#7fdbca", - "markdown-code-block": "#d6deeb" + "syntax-primitive": "#f78c6c" } } } diff --git a/packages/ui/src/theme/themes/nord.json b/packages/ui/src/theme/themes/nord.json index 44378de06a..05ec4672ec 100644 --- a/packages/ui/src/theme/themes/nord.json +++ b/packages/ui/src/theme/themes/nord.json @@ -3,129 +3,40 @@ "name": "Nord", "id": "nord", "light": { - "seeds": { + "palette": { "neutral": "#eceff4", + "ink": "#2e3440", "primary": "#5e81ac", + "accent": "#bf616a", "success": "#8fbcbb", "warning": "#d08770", "error": "#bf616a", "info": "#81a1c1", - "interactive": "#5e81ac", "diffAdd": "#a3be8c", "diffDelete": "#bf616a" }, "overrides": { - "background-base": "#eceff4", - "background-weak": "#e4e8f0", - "background-strong": "#f1f3f8", - "background-stronger": "#f6f8fc", - "border-weak-base": "#d5dbe7", - "border-weak-hover": "#c9d0de", - "border-weak-active": "#bec5d4", - "border-weak-selected": "#b2bacc", - "border-weak-disabled": "#f0f3fa", - "border-weak-focus": "#b9bfd0", - "border-base": "#afb7cb", - "border-hover": "#a3abc1", - "border-active": "#979fb7", - "border-selected": "#8b94ad", - "border-disabled": "#e5e9f2", - "border-focus": "#9ca4ba", - "border-strong-base": "#757f97", - "border-strong-hover": "#69718a", - "border-strong-active": "#5d647d", - "border-strong-selected": "#525970", - "border-strong-disabled": "#c9cedc", - "border-strong-focus": "#636c84", - "surface-diff-add-base": "#e4f0e4", - "surface-diff-delete-base": "#f4e1e4", - "surface-diff-hidden-base": "#dfe6f2", - "text-base": "#2e3440", - "text-weak": "#4c566a", - "text-strong": "#1f2530", + "syntax-keyword": "#5e81ac", "syntax-string": "#a3be8c", - "syntax-primitive": "#bf616a", - "syntax-property": "#5e81ac", - "syntax-type": "#d08770", - "syntax-constant": "#81a1c1", - "syntax-info": "#81a1c1", - "markdown-heading": "#5e81ac", - "markdown-text": "#2e3440", - "markdown-link": "#5e81ac", - "markdown-link-text": "#81a1c1", - "markdown-code": "#a3be8c", - "markdown-block-quote": "#d08770", - "markdown-emph": "#d08770", - "markdown-strong": "#bf616a", - "markdown-horizontal-rule": "#cbd3e1", - "markdown-list-item": "#5e81ac", - "markdown-list-enumeration": "#81a1c1", - "markdown-image": "#5e81ac", - "markdown-image-text": "#81a1c1", - "markdown-code-block": "#5e81ac" + "syntax-primitive": "#b48ead" } }, "dark": { - "seeds": { + "palette": { "neutral": "#2e3440", + "ink": "#e5e9f0", "primary": "#88c0d0", + "accent": "#d57780", "success": "#a3be8c", "warning": "#d08770", "error": "#bf616a", "info": "#81a1c1", - "interactive": "#88c0d0", "diffAdd": "#81a1c1", "diffDelete": "#bf616a" }, "overrides": { - "background-base": "#1f2430", - "background-weak": "#222938", - "background-strong": "#1c202a", - "background-stronger": "#181c24", - "border-weak-base": "#343a47", - "border-weak-hover": "#383f50", - "border-weak-active": "#3d4458", - "border-weak-selected": "#434a62", - "border-weak-disabled": "#151923", - "border-weak-focus": "#3f4359", - "border-base": "#4a5163", - "border-hover": "#515870", - "border-active": "#585f7c", - "border-selected": "#606889", - "border-disabled": "#1b202a", - "border-focus": "#545b78", - "border-strong-base": "#6a7492", - "border-strong-hover": "#747e9f", - "border-strong-active": "#7e88ac", - "border-strong-selected": "#8993b9", - "border-strong-disabled": "#232836", - "border-strong-focus": "#76819f", - "surface-diff-add-base": "#1f2e33", - "surface-diff-delete-base": "#2e212a", - "surface-diff-hidden-base": "#222b3a", - "text-base": "#e5e9f0", - "text-weak": "#a4adbf", - "text-strong": "#f8fafc", - "syntax-string": "#a3be8c", - "syntax-primitive": "#d57780", - "syntax-property": "#88c0d0", - "syntax-type": "#eac196", - "syntax-constant": "#81a1c1", - "syntax-info": "#81a1c1", - "markdown-heading": "#88c0d0", - "markdown-text": "#e5e9f0", - "markdown-link": "#88c0d0", - "markdown-link-text": "#81a1c1", - "markdown-code": "#a3be8c", - "markdown-block-quote": "#d08770", - "markdown-emph": "#d08770", - "markdown-strong": "#bf616a", - "markdown-horizontal-rule": "#2f384a", - "markdown-list-item": "#88c0d0", - "markdown-list-enumeration": "#81a1c1", - "markdown-image": "#88c0d0", - "markdown-image-text": "#81a1c1", - "markdown-code-block": "#cbd3e1" + "syntax-keyword": "#81a1c1", + "syntax-primitive": "#b48ead" } } } diff --git a/packages/ui/src/theme/themes/oc-1.json b/packages/ui/src/theme/themes/oc-1.json deleted file mode 100644 index 03a67ee239..0000000000 --- a/packages/ui/src/theme/themes/oc-1.json +++ /dev/null @@ -1,537 +0,0 @@ -{ - "$schema": "https://opencode.ai/desktop-theme.json", - "name": "OC-1", - "id": "oc-1", - "light": { - "seeds": { - "neutral": "#8e8b8b", - "primary": "#dcde8d", - "success": "#12c905", - "warning": "#ffdc17", - "error": "#fc533a", - "info": "#a753ae", - "interactive": "#034cff", - "diffAdd": "#9ff29a", - "diffDelete": "#fc533a" - }, - "overrides": { - "background-base": "#f8f7f7", - "background-weak": "var(--smoke-light-3)", - "background-strong": "var(--smoke-light-1)", - "background-stronger": "#fcfcfc", - "surface-base": "var(--smoke-light-alpha-2)", - "base": "var(--smoke-light-alpha-2)", - "surface-base-hover": "#0500000f", - "surface-base-active": "var(--smoke-light-alpha-3)", - "surface-base-interactive-active": "var(--cobalt-light-alpha-3)", - "base2": "var(--smoke-light-alpha-2)", - "base3": "var(--smoke-light-alpha-2)", - "surface-inset-base": "var(--smoke-light-alpha-2)", - "surface-inset-base-hover": "var(--smoke-light-alpha-3)", - "surface-inset-strong": "#1f000017", - "surface-inset-strong-hover": "#1f000017", - "surface-raised-base": "var(--smoke-light-alpha-2)", - "surface-float-base": "var(--smoke-dark-1)", - "surface-float-base-hover": "var(--smoke-dark-2)", - "surface-raised-base-hover": "var(--smoke-light-alpha-3)", - "surface-raised-base-active": "var(--smoke-light-alpha-4)", - "surface-raised-strong": "var(--smoke-light-1)", - "surface-raised-strong-hover": "var(--white)", - "surface-raised-stronger": "var(--white)", - "surface-raised-stronger-hover": "var(--white)", - "surface-weak": "var(--smoke-light-alpha-3)", - "surface-weaker": "var(--smoke-light-alpha-4)", - "surface-strong": "#ffffff", - "surface-raised-stronger-non-alpha": "var(--white)", - "surface-brand-base": "var(--yuzu-light-9)", - "surface-brand-hover": "var(--yuzu-light-10)", - "surface-interactive-base": "var(--cobalt-light-3)", - "surface-interactive-hover": "#E5F0FF", - "surface-interactive-weak": "var(--cobalt-light-2)", - "surface-interactive-weak-hover": "var(--cobalt-light-3)", - "surface-success-base": "var(--apple-light-3)", - "surface-success-weak": "var(--apple-light-2)", - "surface-success-strong": "var(--apple-light-9)", - "surface-warning-base": "var(--solaris-light-3)", - "surface-warning-weak": "var(--solaris-light-2)", - "surface-warning-strong": "var(--solaris-light-9)", - "surface-critical-base": "var(--ember-light-3)", - "surface-critical-weak": "var(--ember-light-2)", - "surface-critical-strong": "var(--ember-light-9)", - "surface-info-base": "var(--lilac-light-3)", - "surface-info-weak": "var(--lilac-light-2)", - "surface-info-strong": "var(--lilac-light-9)", - "surface-diff-unchanged-base": "#ffffff00", - "surface-diff-skip-base": "var(--smoke-light-2)", - "surface-diff-hidden-base": "var(--blue-light-3)", - "surface-diff-hidden-weak": "var(--blue-light-2)", - "surface-diff-hidden-weaker": "var(--blue-light-1)", - "surface-diff-hidden-strong": "var(--blue-light-5)", - "surface-diff-hidden-stronger": "var(--blue-light-9)", - "surface-diff-add-base": "#dafbe0", - "surface-diff-add-weak": "var(--mint-light-2)", - "surface-diff-add-weaker": "var(--mint-light-1)", - "surface-diff-add-strong": "var(--mint-light-5)", - "surface-diff-add-stronger": "var(--mint-light-9)", - "surface-diff-delete-base": "var(--ember-light-3)", - "surface-diff-delete-weak": "var(--ember-light-2)", - "surface-diff-delete-weaker": "var(--ember-light-1)", - "surface-diff-delete-strong": "var(--ember-light-6)", - "surface-diff-delete-stronger": "var(--ember-light-9)", - "input-base": "var(--smoke-light-1)", - "input-hover": "var(--smoke-light-2)", - "input-active": "var(--cobalt-light-1)", - "input-selected": "var(--cobalt-light-4)", - "input-focus": "var(--cobalt-light-1)", - "input-disabled": "var(--smoke-light-4)", - "text-base": "var(--smoke-light-11)", - "text-weak": "var(--smoke-light-9)", - "text-weaker": "var(--smoke-light-8)", - "text-strong": "var(--smoke-light-12)", - "text-invert-base": "var(--smoke-dark-alpha-11)", - "text-invert-weak": "var(--smoke-dark-alpha-9)", - "text-invert-weaker": "var(--smoke-dark-alpha-8)", - "text-invert-strong": "var(--smoke-dark-alpha-12)", - "text-interactive-base": "var(--cobalt-light-9)", - "text-on-brand-base": "var(--smoke-light-alpha-11)", - "text-on-interactive-base": "var(--smoke-light-1)", - "text-on-interactive-weak": "var(--smoke-dark-alpha-11)", - "text-on-success-base": "var(--apple-light-10)", - "text-on-critical-base": "var(--ember-light-10)", - "text-on-critical-weak": "var(--ember-light-8)", - "text-on-critical-strong": "var(--ember-light-12)", - "text-on-warning-base": "var(--smoke-dark-alpha-11)", - "text-on-info-base": "var(--smoke-dark-alpha-11)", - "text-diff-add-base": "var(--mint-light-11)", - "text-diff-delete-base": "var(--ember-light-10)", - "text-diff-delete-strong": "var(--ember-light-12)", - "text-diff-add-strong": "var(--mint-light-12)", - "text-on-info-weak": "var(--smoke-dark-alpha-9)", - "text-on-info-strong": "var(--smoke-dark-alpha-12)", - "text-on-warning-weak": "var(--smoke-dark-alpha-9)", - "text-on-warning-strong": "var(--smoke-dark-alpha-12)", - "text-on-success-weak": "var(--apple-light-6)", - "text-on-success-strong": "var(--apple-light-12)", - "text-on-brand-weak": "var(--smoke-light-alpha-9)", - "text-on-brand-weaker": "var(--smoke-light-alpha-8)", - "text-on-brand-strong": "var(--smoke-light-alpha-12)", - "button-primary-base": "var(--smoke-light-12)", - "button-secondary-base": "#fdfcfc", - "button-secondary-hover": "#faf9f9", - "border-base": "var(--smoke-light-alpha-7)", - "border-hover": "var(--smoke-light-alpha-8)", - "border-active": "var(--smoke-light-alpha-9)", - "border-selected": "var(--cobalt-light-alpha-9)", - "border-disabled": "var(--smoke-light-alpha-8)", - "border-focus": "var(--smoke-light-alpha-9)", - "border-weak-base": "var(--smoke-light-alpha-5)", - "border-strong-base": "var(--smoke-light-alpha-7)", - "border-strong-hover": "var(--smoke-light-alpha-8)", - "border-strong-active": "var(--smoke-light-alpha-7)", - "border-strong-selected": "var(--cobalt-light-alpha-6)", - "border-strong-disabled": "var(--smoke-light-alpha-6)", - "border-strong-focus": "var(--smoke-light-alpha-7)", - "border-weak-hover": "var(--smoke-light-alpha-6)", - "border-weak-active": "var(--smoke-light-alpha-7)", - "border-weak-selected": "var(--cobalt-light-alpha-5)", - "border-weak-disabled": "var(--smoke-light-alpha-6)", - "border-weak-focus": "var(--smoke-light-alpha-7)", - "border-interactive-base": "var(--cobalt-light-7)", - "border-interactive-hover": "var(--cobalt-light-8)", - "border-interactive-active": "var(--cobalt-light-9)", - "border-interactive-selected": "var(--cobalt-light-9)", - "border-interactive-disabled": "var(--smoke-light-8)", - "border-interactive-focus": "var(--cobalt-light-9)", - "border-success-base": "var(--apple-light-6)", - "border-success-hover": "var(--apple-light-7)", - "border-success-selected": "var(--apple-light-9)", - "border-warning-base": "var(--solaris-light-6)", - "border-warning-hover": "var(--solaris-light-7)", - "border-warning-selected": "var(--solaris-light-9)", - "border-critical-base": "var(--ember-light-6)", - "border-critical-hover": "var(--ember-light-7)", - "border-critical-selected": "var(--ember-light-9)", - "border-info-base": "var(--lilac-light-6)", - "border-info-hover": "var(--lilac-light-7)", - "border-info-selected": "var(--lilac-light-9)", - "icon-base": "var(--smoke-light-9)", - "icon-hover": "var(--smoke-light-11)", - "icon-active": "var(--smoke-light-12)", - "icon-selected": "var(--smoke-light-12)", - "icon-disabled": "var(--smoke-light-8)", - "icon-focus": "var(--smoke-light-12)", - "icon-invert-base": "#ffffff", - "icon-weak-base": "var(--smoke-light-7)", - "icon-weak-hover": "var(--smoke-light-8)", - "icon-weak-active": "var(--smoke-light-9)", - "icon-weak-selected": "var(--smoke-light-10)", - "icon-weak-disabled": "var(--smoke-light-6)", - "icon-weak-focus": "var(--smoke-light-9)", - "icon-strong-base": "var(--smoke-light-12)", - "icon-strong-hover": "#151313", - "icon-strong-active": "#020202", - "icon-strong-selected": "#020202", - "icon-strong-disabled": "var(--smoke-light-8)", - "icon-strong-focus": "#020202", - "icon-brand-base": "var(--smoke-light-12)", - "icon-interactive-base": "var(--cobalt-light-9)", - "icon-success-base": "var(--apple-light-7)", - "icon-success-hover": "var(--apple-light-8)", - "icon-success-active": "var(--apple-light-11)", - "icon-warning-base": "var(--amber-light-7)", - "icon-warning-hover": "var(--amber-light-8)", - "icon-warning-active": "var(--amber-light-11)", - "icon-critical-base": "var(--ember-light-10)", - "icon-critical-hover": "var(--ember-light-11)", - "icon-critical-active": "var(--ember-light-12)", - "icon-info-base": "var(--lilac-light-7)", - "icon-info-hover": "var(--lilac-light-8)", - "icon-info-active": "var(--lilac-light-11)", - "icon-on-brand-base": "var(--smoke-light-alpha-11)", - "icon-on-brand-hover": "var(--smoke-light-alpha-12)", - "icon-on-brand-selected": "var(--smoke-light-alpha-12)", - "icon-on-interactive-base": "var(--smoke-light-1)", - "icon-agent-plan-base": "var(--purple-light-9)", - "icon-agent-docs-base": "var(--amber-light-9)", - "icon-agent-ask-base": "var(--cyan-light-9)", - "icon-agent-build-base": "var(--cobalt-light-9)", - "icon-on-success-base": "var(--apple-light-alpha-9)", - "icon-on-success-hover": "var(--apple-light-alpha-10)", - "icon-on-success-selected": "var(--apple-light-alpha-11)", - "icon-on-warning-base": "var(--amber-lightalpha-9)", - "icon-on-warning-hover": "var(--amber-lightalpha-10)", - "icon-on-warning-selected": "var(--amber-lightalpha-11)", - "icon-on-critical-base": "var(--ember-light-alpha-9)", - "icon-on-critical-hover": "var(--ember-light-alpha-10)", - "icon-on-critical-selected": "var(--ember-light-alpha-11)", - "icon-on-info-base": "var(--lilac-light-9)", - "icon-on-info-hover": "var(--lilac-light-alpha-10)", - "icon-on-info-selected": "var(--lilac-light-alpha-11)", - "icon-diff-add-base": "var(--mint-light-11)", - "icon-diff-add-hover": "var(--mint-light-12)", - "icon-diff-add-active": "var(--mint-light-12)", - "icon-diff-delete-base": "var(--ember-light-10)", - "icon-diff-delete-hover": "var(--ember-light-11)", - "syntax-comment": "var(--text-weak)", - "syntax-regexp": "var(--text-base)", - "syntax-string": "#006656", - "syntax-keyword": "var(--text-weak)", - "syntax-primitive": "#fb4804", - "syntax-operator": "var(--text-base)", - "syntax-variable": "var(--text-strong)", - "syntax-property": "#ed6dc8", - "syntax-type": "#596600", - "syntax-constant": "#007b80", - "syntax-punctuation": "var(--text-base)", - "syntax-object": "var(--text-strong)", - "syntax-success": "var(--apple-light-10)", - "syntax-warning": "var(--amber-light-10)", - "syntax-critical": "var(--ember-light-10)", - "syntax-info": "#0092a8", - "syntax-diff-add": "var(--mint-light-11)", - "syntax-diff-delete": "var(--ember-light-11)", - "syntax-diff-unknown": "#ff0000", - "markdown-heading": "#d68c27", - "markdown-text": "#1a1a1a", - "markdown-link": "#3b7dd8", - "markdown-link-text": "#318795", - "markdown-code": "#3d9a57", - "markdown-block-quote": "#b0851f", - "markdown-emph": "#b0851f", - "markdown-strong": "#d68c27", - "markdown-horizontal-rule": "#8a8a8a", - "markdown-list-item": "#3b7dd8", - "markdown-list-enumeration": "#318795", - "markdown-image": "#3b7dd8", - "markdown-image-text": "#318795", - "markdown-code-block": "#1a1a1a", - "border-color": "#ffffff", - "border-weaker-base": "var(--smoke-light-alpha-3)", - "border-weaker-hover": "var(--smoke-light-alpha-4)", - "border-weaker-active": "var(--smoke-light-alpha-6)", - "border-weaker-selected": "var(--cobalt-light-alpha-4)", - "border-weaker-disabled": "var(--smoke-light-alpha-2)", - "border-weaker-focus": "var(--smoke-light-alpha-6)", - "button-ghost-hover": "var(--smoke-light-alpha-2)", - "button-ghost-hover2": "var(--smoke-light-alpha-3)", - "avatar-background-pink": "#feeef8", - "avatar-background-mint": "#e1fbf4", - "avatar-background-orange": "#fff1e7", - "avatar-background-purple": "#f9f1fe", - "avatar-background-cyan": "#e7f9fb", - "avatar-background-lime": "#eefadc", - "avatar-text-pink": "#cd1d8d", - "avatar-text-mint": "#147d6f", - "avatar-text-orange": "#ed5f00", - "avatar-text-purple": "#8445bc", - "avatar-text-cyan": "#0894b3", - "avatar-text-lime": "#5d770d" - } - }, - "dark": { - "seeds": { - "neutral": "#716c6b", - "primary": "#fab283", - "success": "#12c905", - "warning": "#fcd53a", - "error": "#fc533a", - "info": "#edb2f1", - "interactive": "#034cff", - "diffAdd": "#c8ffc4", - "diffDelete": "#fc533a" - }, - "overrides": { - "background-base": "var(--smoke-dark-1)", - "background-weak": "#1c1717", - "background-strong": "#151313", - "background-stronger": "#191515", - "surface-base": "var(--smoke-dark-alpha-2)", - "base": "var(--smoke-dark-alpha-2)", - "surface-base-hover": "#e0b7b716", - "surface-base-active": "var(--smoke-dark-alpha-3)", - "surface-base-interactive-active": "var(--cobalt-dark-alpha-2)", - "base2": "var(--smoke-dark-alpha-2)", - "base3": "var(--smoke-dark-alpha-2)", - "surface-inset-base": "#0e0b0b7f", - "surface-inset-base-hover": "#0e0b0b7f", - "surface-inset-strong": "#060505cc", - "surface-inset-strong-hover": "#060505cc", - "surface-raised-base": "var(--smoke-dark-alpha-3)", - "surface-float-base": "var(--smoke-dark-1)", - "surface-float-base-hover": "var(--smoke-dark-2)", - "surface-raised-base-hover": "var(--smoke-dark-alpha-4)", - "surface-raised-base-active": "var(--smoke-dark-alpha-5)", - "surface-raised-strong": "var(--smoke-dark-alpha-4)", - "surface-raised-strong-hover": "var(--smoke-dark-alpha-6)", - "surface-raised-stronger": "var(--smoke-dark-alpha-6)", - "surface-raised-stronger-hover": "var(--smoke-dark-alpha-7)", - "surface-weak": "var(--smoke-dark-alpha-4)", - "surface-weaker": "var(--smoke-dark-alpha-5)", - "surface-strong": "var(--smoke-dark-alpha-7)", - "surface-raised-stronger-non-alpha": "var(--smoke-dark-3)", - "surface-brand-base": "var(--yuzu-light-9)", - "surface-brand-hover": "var(--yuzu-light-10)", - "surface-interactive-base": "var(--cobalt-dark-3)", - "surface-interactive-hover": "#0A1D4D", - "surface-interactive-weak": "var(--cobalt-dark-2)", - "surface-interactive-weak-hover": "var(--cobalt-light-3)", - "surface-success-base": "var(--apple-dark-3)", - "surface-success-weak": "var(--apple-dark-2)", - "surface-success-strong": "var(--apple-dark-9)", - "surface-warning-base": "var(--solaris-light-3)", - "surface-warning-weak": "var(--solaris-light-2)", - "surface-warning-strong": "var(--solaris-light-9)", - "surface-critical-base": "var(--ember-dark-3)", - "surface-critical-weak": "var(--ember-dark-2)", - "surface-critical-strong": "var(--ember-dark-9)", - "surface-info-base": "var(--lilac-light-3)", - "surface-info-weak": "var(--lilac-light-2)", - "surface-info-strong": "var(--lilac-light-9)", - "surface-diff-unchanged-base": "var(--smoke-dark-1)", - "surface-diff-skip-base": "var(--smoke-dark-alpha-1)", - "surface-diff-hidden-base": "var(--blue-dark-2)", - "surface-diff-hidden-weak": "var(--blue-dark-1)", - "surface-diff-hidden-weaker": "var(--blue-dark-3)", - "surface-diff-hidden-strong": "var(--blue-dark-5)", - "surface-diff-hidden-stronger": "var(--blue-dark-11)", - "surface-diff-add-base": "var(--mint-dark-3)", - "surface-diff-add-weak": "var(--mint-dark-4)", - "surface-diff-add-weaker": "var(--mint-dark-3)", - "surface-diff-add-strong": "var(--mint-dark-5)", - "surface-diff-add-stronger": "var(--mint-dark-11)", - "surface-diff-delete-base": "var(--ember-dark-3)", - "surface-diff-delete-weak": "var(--ember-dark-4)", - "surface-diff-delete-weaker": "var(--ember-dark-3)", - "surface-diff-delete-strong": "var(--ember-dark-5)", - "surface-diff-delete-stronger": "var(--ember-dark-11)", - "input-base": "var(--smoke-dark-2)", - "input-hover": "var(--smoke-dark-2)", - "input-active": "var(--cobalt-dark-1)", - "input-selected": "var(--cobalt-dark-2)", - "input-focus": "var(--cobalt-dark-1)", - "input-disabled": "var(--smoke-dark-4)", - "text-base": "var(--smoke-dark-alpha-11)", - "text-weak": "var(--smoke-dark-alpha-9)", - "text-weaker": "var(--smoke-dark-alpha-8)", - "text-strong": "var(--smoke-dark-alpha-12)", - "text-invert-base": "var(--smoke-dark-alpha-11)", - "text-invert-weak": "var(--smoke-dark-alpha-9)", - "text-invert-weaker": "var(--smoke-dark-alpha-8)", - "text-invert-strong": "var(--smoke-dark-alpha-12)", - "text-interactive-base": "var(--cobalt-dark-11)", - "text-on-brand-base": "var(--smoke-dark-alpha-11)", - "text-on-interactive-base": "var(--smoke-dark-12)", - "text-on-interactive-weak": "var(--smoke-dark-alpha-11)", - "text-on-success-base": "var(--apple-dark-9)", - "text-on-critical-base": "var(--ember-dark-9)", - "text-on-critical-weak": "var(--ember-dark-8)", - "text-on-critical-strong": "var(--ember-dark-12)", - "text-on-warning-base": "var(--smoke-dark-alpha-11)", - "text-on-info-base": "var(--smoke-dark-alpha-11)", - "text-diff-add-base": "var(--mint-dark-11)", - "text-diff-delete-base": "var(--ember-dark-9)", - "text-diff-delete-strong": "var(--ember-dark-12)", - "text-diff-add-strong": "var(--mint-dark-8)", - "text-on-info-weak": "var(--smoke-dark-alpha-9)", - "text-on-info-strong": "var(--smoke-dark-alpha-12)", - "text-on-warning-weak": "var(--smoke-dark-alpha-9)", - "text-on-warning-strong": "var(--smoke-dark-alpha-12)", - "text-on-success-weak": "var(--apple-dark-8)", - "text-on-success-strong": "var(--apple-dark-12)", - "text-on-brand-weak": "var(--smoke-dark-alpha-9)", - "text-on-brand-weaker": "var(--smoke-dark-alpha-8)", - "text-on-brand-strong": "var(--smoke-dark-alpha-12)", - "button-primary-base": "var(--smoke-dark-12)", - "button-secondary-base": "#231f1f", - "button-secondary-hover": "#2a2727", - "border-base": "var(--smoke-dark-alpha-7)", - "border-hover": "var(--smoke-dark-alpha-8)", - "border-active": "var(--smoke-dark-alpha-9)", - "border-selected": "var(--cobalt-dark-alpha-11)", - "border-disabled": "var(--smoke-dark-alpha-8)", - "border-focus": "var(--smoke-dark-alpha-9)", - "border-weak-base": "var(--smoke-dark-alpha-6)", - "border-strong-base": "var(--smoke-dark-alpha-8)", - "border-strong-hover": "var(--smoke-dark-alpha-7)", - "border-strong-active": "var(--smoke-dark-alpha-8)", - "border-strong-selected": "var(--cobalt-dark-alpha-6)", - "border-strong-disabled": "var(--smoke-dark-alpha-6)", - "border-strong-focus": "var(--smoke-dark-alpha-8)", - "border-weak-hover": "var(--smoke-dark-alpha-7)", - "border-weak-active": "var(--smoke-dark-alpha-8)", - "border-weak-selected": "var(--cobalt-dark-alpha-6)", - "border-weak-disabled": "var(--smoke-dark-alpha-6)", - "border-weak-focus": "var(--smoke-dark-alpha-8)", - "border-interactive-base": "var(--cobalt-light-7)", - "border-interactive-hover": "var(--cobalt-light-8)", - "border-interactive-active": "var(--cobalt-light-9)", - "border-interactive-selected": "var(--cobalt-light-9)", - "border-interactive-disabled": "var(--smoke-light-8)", - "border-interactive-focus": "var(--cobalt-light-9)", - "border-success-base": "var(--apple-light-6)", - "border-success-hover": "var(--apple-light-7)", - "border-success-selected": "var(--apple-light-9)", - "border-warning-base": "var(--solaris-light-6)", - "border-warning-hover": "var(--solaris-light-7)", - "border-warning-selected": "var(--solaris-light-9)", - "border-critical-base": "var(--ember-dark-5)", - "border-critical-hover": "var(--ember-dark-7)", - "border-critical-selected": "var(--ember-dark-9)", - "border-info-base": "var(--lilac-light-6)", - "border-info-hover": "var(--lilac-light-7)", - "border-info-selected": "var(--lilac-light-9)", - "icon-base": "var(--smoke-dark-9)", - "icon-hover": "var(--smoke-dark-10)", - "icon-active": "var(--smoke-dark-11)", - "icon-selected": "var(--smoke-dark-12)", - "icon-disabled": "var(--smoke-dark-7)", - "icon-focus": "var(--smoke-dark-12)", - "icon-invert-base": "var(--smoke-dark-1)", - "icon-weak-base": "var(--smoke-dark-6)", - "icon-weak-hover": "var(--smoke-light-7)", - "icon-weak-active": "var(--smoke-light-8)", - "icon-weak-selected": "var(--smoke-light-9)", - "icon-weak-disabled": "var(--smoke-light-4)", - "icon-weak-focus": "var(--smoke-light-9)", - "icon-strong-base": "var(--smoke-dark-12)", - "icon-strong-hover": "#f6f3f3", - "icon-strong-active": "#fcfcfc", - "icon-strong-selected": "#fdfcfc", - "icon-strong-disabled": "var(--smoke-dark-8)", - "icon-strong-focus": "#fdfcfc", - "icon-brand-base": "var(--white)", - "icon-interactive-base": "var(--cobalt-dark-11)", - "icon-success-base": "var(--apple-dark-9)", - "icon-success-hover": "var(--apple-dark-10)", - "icon-success-active": "var(--apple-dark-11)", - "icon-warning-base": "var(--amber-dark-9)", - "icon-warning-hover": "var(--amber-dark-8)", - "icon-warning-active": "var(--amber-dark-11)", - "icon-critical-base": "var(--ember-dark-9)", - "icon-critical-hover": "var(--ember-dark-11)", - "icon-critical-active": "var(--ember-dark-12)", - "icon-info-base": "var(--lilac-dark-7)", - "icon-info-hover": "var(--lilac-dark-8)", - "icon-info-active": "var(--lilac-dark-11)", - "icon-on-brand-base": "var(--smoke-light-alpha-11)", - "icon-on-brand-hover": "var(--smoke-light-alpha-12)", - "icon-on-brand-selected": "var(--smoke-light-alpha-12)", - "icon-on-interactive-base": "var(--smoke-dark-12)", - "icon-agent-plan-base": "var(--purple-dark-9)", - "icon-agent-docs-base": "var(--amber-dark-9)", - "icon-agent-ask-base": "var(--cyan-dark-9)", - "icon-agent-build-base": "var(--cobalt-dark-11)", - "icon-on-success-base": "var(--apple-dark-alpha-9)", - "icon-on-success-hover": "var(--apple-dark-alpha-10)", - "icon-on-success-selected": "var(--apple-dark-alpha-11)", - "icon-on-warning-base": "var(--amber-darkalpha-9)", - "icon-on-warning-hover": "var(--amber-darkalpha-10)", - "icon-on-warning-selected": "var(--amber-darkalpha-11)", - "icon-on-critical-base": "var(--ember-dark-alpha-9)", - "icon-on-critical-hover": "var(--ember-dark-alpha-10)", - "icon-on-critical-selected": "var(--ember-dark-alpha-11)", - "icon-on-info-base": "var(--lilac-dark-9)", - "icon-on-info-hover": "var(--lilac-dark-alpha-10)", - "icon-on-info-selected": "var(--lilac-dark-alpha-11)", - "icon-diff-add-base": "var(--mint-dark-11)", - "icon-diff-add-hover": "var(--mint-dark-10)", - "icon-diff-add-active": "var(--mint-dark-11)", - "icon-diff-delete-base": "var(--ember-dark-9)", - "icon-diff-delete-hover": "var(--ember-dark-10)", - "syntax-comment": "var(--text-weak)", - "syntax-regexp": "var(--text-base)", - "syntax-string": "#00ceb9", - "syntax-keyword": "var(--text-weak)", - "syntax-primitive": "#ffba92", - "syntax-operator": "var(--text-weak)", - "syntax-variable": "var(--text-strong)", - "syntax-property": "#ff9ae2", - "syntax-type": "#ecf58c", - "syntax-constant": "#93e9f6", - "syntax-punctuation": "var(--text-weak)", - "syntax-object": "var(--text-strong)", - "syntax-success": "var(--apple-dark-10)", - "syntax-warning": "var(--amber-dark-10)", - "syntax-critical": "var(--ember-dark-10)", - "syntax-info": "#93e9f6", - "syntax-diff-add": "var(--mint-dark-11)", - "syntax-diff-delete": "var(--ember-dark-11)", - "syntax-diff-unknown": "#ff0000", - "markdown-heading": "#9d7cd8", - "markdown-text": "#eeeeee", - "markdown-link": "#fab283", - "markdown-link-text": "#56b6c2", - "markdown-code": "#7fd88f", - "markdown-block-quote": "#e5c07b", - "markdown-emph": "#e5c07b", - "markdown-strong": "#f5a742", - "markdown-horizontal-rule": "#808080", - "markdown-list-item": "#fab283", - "markdown-list-enumeration": "#56b6c2", - "markdown-image": "#fab283", - "markdown-image-text": "#56b6c2", - "markdown-code-block": "#eeeeee", - "border-color": "#ffffff", - "border-weaker-base": "var(--smoke-dark-alpha-3)", - "border-weaker-hover": "var(--smoke-dark-alpha-4)", - "border-weaker-active": "var(--smoke-dark-alpha-6)", - "border-weaker-selected": "var(--cobalt-dark-alpha-3)", - "border-weaker-disabled": "var(--smoke-dark-alpha-2)", - "border-weaker-focus": "var(--smoke-dark-alpha-6)", - "button-ghost-hover": "var(--smoke-dark-alpha-2)", - "button-ghost-hover2": "var(--smoke-dark-alpha-3)", - "avatar-background-pink": "#501b3f", - "avatar-background-mint": "#033a34", - "avatar-background-orange": "#5f2a06", - "avatar-background-purple": "#432155", - "avatar-background-cyan": "#0f3058", - "avatar-background-lime": "#2b3711", - "avatar-text-pink": "#e34ba9", - "avatar-text-mint": "#95f3d9", - "avatar-text-orange": "#ff802b", - "avatar-text-purple": "#9d5bd2", - "avatar-text-cyan": "#369eff", - "avatar-text-lime": "#c4f042" - } - } -} diff --git a/packages/ui/src/theme/themes/oc-2.json b/packages/ui/src/theme/themes/oc-2.json index 01ec1131a2..fdf0c2caf4 100644 --- a/packages/ui/src/theme/themes/oc-2.json +++ b/packages/ui/src/theme/themes/oc-2.json @@ -3,8 +3,8 @@ "name": "OC-2", "id": "oc-2", "light": { - "seeds": { - "neutral": "#8e8b8b", + "palette": { + "neutral": "#8f8f8f", "primary": "#dcde8d", "success": "#12c905", "warning": "#ffdc17", @@ -13,264 +13,11 @@ "interactive": "#034cff", "diffAdd": "#9ff29a", "diffDelete": "#fc533a" - }, - "overrides": { - "background-base": "#f8f7f7", - "background-weak": "var(--gray-light-3)", - "background-strong": "var(--gray-light-1)", - "background-stronger": "#fcfcfc", - "surface-base": "var(--gray-light-alpha-2)", - "base": "var(--gray-light-alpha-2)", - "surface-base-hover": "#0500000f", - "surface-base-active": "var(--gray-light-alpha-3)", - "surface-base-interactive-active": "var(--cobalt-light-alpha-3)", - "base2": "var(--gray-light-alpha-2)", - "base3": "var(--gray-light-alpha-2)", - "surface-inset-base": "var(--gray-light-alpha-2)", - "surface-inset-base-hover": "var(--gray-light-alpha-3)", - "surface-inset-strong": "#1f000017", - "surface-inset-strong-hover": "#1f000017", - "surface-raised-base": "var(--gray-light-alpha-2)", - "surface-float-base": "var(--gray-dark-1)", - "surface-float-base-hover": "var(--gray-dark-2)", - "surface-raised-base-hover": "var(--gray-light-alpha-3)", - "surface-raised-base-active": "var(--gray-light-alpha-5)", - "surface-raised-strong": "var(--gray-light-1)", - "surface-raised-strong-hover": "var(--white)", - "surface-raised-stronger": "var(--white)", - "surface-raised-stronger-hover": "var(--white)", - "surface-weak": "var(--gray-light-alpha-3)", - "surface-weaker": "var(--gray-light-alpha-4)", - "surface-strong": "#ffffff", - "surface-raised-stronger-non-alpha": "var(--white)", - "surface-brand-base": "var(--yuzu-light-9)", - "surface-brand-hover": "var(--yuzu-light-10)", - "surface-interactive-base": "var(--cobalt-light-3)", - "surface-interactive-hover": "#E5F0FF", - "surface-interactive-weak": "var(--cobalt-light-2)", - "surface-interactive-weak-hover": "var(--cobalt-light-3)", - "surface-success-base": "var(--apple-light-3)", - "surface-success-weak": "var(--apple-light-2)", - "surface-success-strong": "var(--apple-light-9)", - "surface-warning-base": "var(--solaris-light-3)", - "surface-warning-weak": "var(--solaris-light-2)", - "surface-warning-strong": "var(--solaris-light-9)", - "surface-critical-base": "var(--ember-light-3)", - "surface-critical-weak": "var(--ember-light-2)", - "surface-critical-strong": "var(--ember-light-9)", - "surface-info-base": "var(--lilac-light-3)", - "surface-info-weak": "var(--lilac-light-2)", - "surface-info-strong": "var(--lilac-light-9)", - "surface-diff-unchanged-base": "#ffffff00", - "surface-diff-skip-base": "var(--gray-light-2)", - "surface-diff-hidden-base": "var(--blue-light-3)", - "surface-diff-hidden-weak": "var(--blue-light-2)", - "surface-diff-hidden-weaker": "var(--blue-light-1)", - "surface-diff-hidden-strong": "var(--blue-light-5)", - "surface-diff-hidden-stronger": "var(--blue-light-9)", - "surface-diff-add-base": "#dafbe0", - "surface-diff-add-weak": "var(--mint-light-2)", - "surface-diff-add-weaker": "var(--mint-light-1)", - "surface-diff-add-strong": "var(--mint-light-5)", - "surface-diff-add-stronger": "var(--mint-light-9)", - "surface-diff-delete-base": "var(--ember-light-3)", - "surface-diff-delete-weak": "var(--ember-light-2)", - "surface-diff-delete-weaker": "var(--ember-light-1)", - "surface-diff-delete-strong": "var(--ember-light-6)", - "surface-diff-delete-stronger": "var(--ember-light-9)", - "input-base": "var(--gray-light-1)", - "input-hover": "var(--gray-light-2)", - "input-active": "var(--cobalt-light-1)", - "input-selected": "var(--cobalt-light-4)", - "input-focus": "var(--cobalt-light-1)", - "input-disabled": "var(--gray-light-4)", - "text-base": "var(--gray-light-11)", - "text-weak": "var(--gray-light-9)", - "text-weaker": "var(--gray-light-8)", - "text-strong": "var(--gray-light-12)", - "text-invert-base": "var(--gray-dark-alpha-11)", - "text-invert-weak": "var(--gray-dark-alpha-9)", - "text-invert-weaker": "var(--gray-dark-alpha-8)", - "text-invert-strong": "var(--gray-dark-alpha-12)", - "text-interactive-base": "var(--cobalt-light-9)", - "text-on-brand-base": "var(--gray-light-alpha-11)", - "text-on-interactive-base": "var(--gray-light-1)", - "text-on-interactive-weak": "var(--gray-dark-alpha-11)", - "text-on-success-base": "var(--apple-light-10)", - "text-on-critical-base": "var(--ember-light-10)", - "text-on-critical-weak": "var(--ember-light-8)", - "text-on-critical-strong": "var(--ember-light-12)", - "text-on-warning-base": "var(--gray-dark-alpha-11)", - "text-on-info-base": "var(--gray-dark-alpha-11)", - "text-diff-add-base": "var(--mint-light-11)", - "text-diff-delete-base": "var(--ember-light-10)", - "text-diff-delete-strong": "var(--ember-light-12)", - "text-diff-add-strong": "var(--mint-light-12)", - "text-on-info-weak": "var(--gray-dark-alpha-9)", - "text-on-info-strong": "var(--gray-dark-alpha-12)", - "text-on-warning-weak": "var(--gray-dark-alpha-9)", - "text-on-warning-strong": "var(--gray-dark-alpha-12)", - "text-on-success-weak": "var(--apple-light-6)", - "text-on-success-strong": "var(--apple-light-12)", - "text-on-brand-weak": "var(--gray-light-alpha-9)", - "text-on-brand-weaker": "var(--gray-light-alpha-8)", - "text-on-brand-strong": "var(--gray-light-alpha-12)", - "button-primary-base": "var(--gray-light-12)", - "button-secondary-base": "var(--gray-light-1)", - "button-secondary-hover": "FFFFFF0A", - "border-base": "var(--gray-light-alpha-7)", - "border-hover": "var(--gray-light-alpha-8)", - "border-active": "var(--gray-light-alpha-9)", - "border-selected": "var(--cobalt-light-alpha-9)", - "border-disabled": "var(--gray-light-alpha-8)", - "border-focus": "var(--gray-light-alpha-9)", - "border-weak-base": "var(--gray-light-alpha-5)", - "border-strong-base": "var(--gray-light-alpha-7)", - "border-strong-hover": "var(--gray-light-alpha-8)", - "border-strong-active": "var(--gray-light-alpha-7)", - "border-strong-selected": "var(--cobalt-light-alpha-6)", - "border-strong-disabled": "var(--gray-light-alpha-6)", - "border-strong-focus": "var(--gray-light-alpha-7)", - "border-weak-hover": "var(--gray-light-alpha-6)", - "border-weak-active": "var(--gray-light-alpha-7)", - "border-weak-selected": "var(--cobalt-light-alpha-5)", - "border-weak-disabled": "var(--gray-light-alpha-6)", - "border-weak-focus": "var(--gray-light-alpha-7)", - "border-interactive-base": "var(--cobalt-light-7)", - "border-interactive-hover": "var(--cobalt-light-8)", - "border-interactive-active": "var(--cobalt-light-9)", - "border-interactive-selected": "var(--cobalt-light-9)", - "border-interactive-disabled": "var(--gray-light-8)", - "border-interactive-focus": "var(--cobalt-light-9)", - "border-success-base": "var(--apple-light-6)", - "border-success-hover": "var(--apple-light-7)", - "border-success-selected": "var(--apple-light-9)", - "border-warning-base": "var(--solaris-light-6)", - "border-warning-hover": "var(--solaris-light-7)", - "border-warning-selected": "var(--solaris-light-9)", - "border-critical-base": "var(--ember-light-6)", - "border-critical-hover": "var(--ember-light-7)", - "border-critical-selected": "var(--ember-light-9)", - "border-info-base": "var(--lilac-light-6)", - "border-info-hover": "var(--lilac-light-7)", - "border-info-selected": "var(--lilac-light-9)", - "icon-base": "var(--gray-light-9)", - "icon-hover": "var(--gray-light-11)", - "icon-active": "var(--gray-light-12)", - "icon-selected": "var(--gray-light-12)", - "icon-disabled": "var(--gray-light-8)", - "icon-focus": "var(--gray-light-12)", - "icon-invert-base": "#ffffff", - "icon-weak-base": "var(--gray-light-7)", - "icon-weak-hover": "var(--gray-light-8)", - "icon-weak-active": "var(--gray-light-9)", - "icon-weak-selected": "var(--gray-light-10)", - "icon-weak-disabled": "var(--gray-light-6)", - "icon-weak-focus": "var(--gray-light-9)", - "icon-strong-base": "var(--gray-light-12)", - "icon-strong-hover": "#151313", - "icon-strong-active": "#020202", - "icon-strong-selected": "#020202", - "icon-strong-disabled": "var(--gray-light-6)", - "icon-strong-focus": "#020202", - "icon-brand-base": "var(--gray-light-12)", - "icon-interactive-base": "var(--cobalt-light-9)", - "icon-success-base": "var(--apple-light-7)", - "icon-success-hover": "var(--apple-light-8)", - "icon-success-active": "var(--apple-light-11)", - "icon-warning-base": "var(--amber-light-7)", - "icon-warning-hover": "var(--amber-light-8)", - "icon-warning-active": "var(--amber-light-11)", - "icon-critical-base": "var(--ember-light-10)", - "icon-critical-hover": "var(--ember-light-11)", - "icon-critical-active": "var(--ember-light-12)", - "icon-info-base": "var(--lilac-light-7)", - "icon-info-hover": "var(--lilac-light-8)", - "icon-info-active": "var(--lilac-light-11)", - "icon-on-brand-base": "var(--gray-light-alpha-11)", - "icon-on-brand-hover": "var(--gray-light-alpha-12)", - "icon-on-brand-selected": "var(--gray-light-alpha-12)", - "icon-on-interactive-base": "var(--gray-light-1)", - "icon-agent-plan-base": "var(--purple-light-9)", - "icon-agent-docs-base": "var(--amber-light-9)", - "icon-agent-ask-base": "var(--cyan-light-9)", - "icon-agent-build-base": "var(--cobalt-light-9)", - "icon-on-success-base": "var(--apple-light-alpha-9)", - "icon-on-success-hover": "var(--apple-light-alpha-10)", - "icon-on-success-selected": "var(--apple-light-alpha-11)", - "icon-on-warning-base": "var(--amber-lightalpha-9)", - "icon-on-warning-hover": "var(--amber-lightalpha-10)", - "icon-on-warning-selected": "var(--amber-lightalpha-11)", - "icon-on-critical-base": "var(--ember-light-alpha-9)", - "icon-on-critical-hover": "var(--ember-light-alpha-10)", - "icon-on-critical-selected": "var(--ember-light-alpha-11)", - "icon-on-info-base": "var(--lilac-light-9)", - "icon-on-info-hover": "var(--lilac-light-alpha-10)", - "icon-on-info-selected": "var(--lilac-light-alpha-11)", - "icon-diff-add-base": "var(--mint-light-11)", - "icon-diff-add-hover": "var(--mint-light-12)", - "icon-diff-add-active": "var(--mint-light-12)", - "icon-diff-delete-base": "var(--ember-light-10)", - "icon-diff-delete-hover": "var(--ember-light-11)", - "syntax-comment": "var(--text-weak)", - "syntax-regexp": "var(--text-base)", - "syntax-string": "#006656", - "syntax-keyword": "var(--text-weak)", - "syntax-primitive": "#fb4804", - "syntax-operator": "var(--text-base)", - "syntax-variable": "var(--text-strong)", - "syntax-property": "#ed6dc8", - "syntax-type": "#596600", - "syntax-constant": "#007b80", - "syntax-punctuation": "var(--text-base)", - "syntax-object": "var(--text-strong)", - "syntax-success": "var(--apple-light-10)", - "syntax-warning": "var(--amber-light-10)", - "syntax-critical": "var(--ember-light-10)", - "syntax-info": "#0092a8", - "syntax-diff-add": "var(--mint-light-11)", - "syntax-diff-delete": "var(--ember-light-11)", - "syntax-diff-unknown": "#ff0000", - "markdown-heading": "#d68c27", - "markdown-text": "#1a1a1a", - "markdown-link": "#3b7dd8", - "markdown-link-text": "#318795", - "markdown-code": "#3d9a57", - "markdown-block-quote": "#b0851f", - "markdown-emph": "#b0851f", - "markdown-strong": "#d68c27", - "markdown-horizontal-rule": "#8a8a8a", - "markdown-list-item": "#3b7dd8", - "markdown-list-enumeration": "#318795", - "markdown-image": "#3b7dd8", - "markdown-image-text": "#318795", - "markdown-code-block": "#1a1a1a", - "border-color": "#ffffff", - "border-weaker-base": "var(--gray-light-alpha-3)", - "border-weaker-hover": "var(--gray-light-alpha-4)", - "border-weaker-active": "var(--gray-light-alpha-6)", - "border-weaker-selected": "var(--cobalt-light-alpha-4)", - "border-weaker-disabled": "var(--gray-light-alpha-2)", - "border-weaker-focus": "var(--gray-light-alpha-6)", - "button-ghost-hover": "var(--gray-light-alpha-2)", - "button-ghost-hover2": "var(--gray-light-alpha-3)", - "avatar-background-pink": "#feeef8", - "avatar-background-mint": "#e1fbf4", - "avatar-background-orange": "#fff1e7", - "avatar-background-purple": "#f9f1fe", - "avatar-background-cyan": "#e7f9fb", - "avatar-background-lime": "#eefadc", - "avatar-text-pink": "#cd1d8d", - "avatar-text-mint": "#147d6f", - "avatar-text-orange": "#ed5f00", - "avatar-text-purple": "#8445bc", - "avatar-text-cyan": "#0894b3", - "avatar-text-lime": "#5d770d" } }, "dark": { - "seeds": { - "neutral": "#716c6b", + "palette": { + "neutral": "#707070", "primary": "#fab283", "success": "#12c905", "warning": "#fcd53a", @@ -279,254 +26,6 @@ "interactive": "#034cff", "diffAdd": "#c8ffc4", "diffDelete": "#fc533a" - }, - "overrides": { - "base": "var(--gray-dark-alpha-2)", - "base2": "var(--gray-dark-alpha-2)", - "base3": "var(--gray-dark-alpha-2)", - "background-base": "#101010", - "background-weak": "#1E1E1E", - "background-strong": "#121212", - "background-stronger": "#151515", - "surface-base": "var(--gray-dark-alpha-2)", - "surface-base-hover": "#FFFFFF0A", - "surface-base-active": "var(--gray-dark-alpha-3)", - "surface-base-interactive-active": "var(--cobalt-dark-alpha-2)", - "surface-inset-base": "#0e0b0b7f", - "surface-inset-base-hover": "#0e0b0b7f", - "surface-inset-strong": "#060505cc", - "surface-inset-strong-hover": "#060505cc", - "surface-raised-base": "var(--gray-dark-alpha-3)", - "surface-float-base": "var(--gray-dark-1)", - "surface-float-base-hover": "var(--gray-dark-2)", - "surface-raised-base-hover": "var(--gray-dark-alpha-4)", - "surface-raised-base-active": "var(--gray-dark-alpha-5)", - "surface-raised-strong": "var(--gray-dark-alpha-4)", - "surface-raised-strong-hover": "var(--gray-dark-alpha-6)", - "surface-raised-stronger": "var(--gray-dark-alpha-6)", - "surface-raised-stronger-hover": "var(--gray-dark-alpha-7)", - "surface-weak": "var(--gray-dark-alpha-4)", - "surface-weaker": "var(--gray-dark-alpha-5)", - "surface-strong": "var(--gray-dark-alpha-7)", - "surface-raised-stronger-non-alpha": "#1B1B1B", - "surface-brand-base": "var(--yuzu-light-9)", - "surface-brand-hover": "var(--yuzu-light-10)", - "surface-interactive-base": "var(--cobalt-dark-3)", - "surface-interactive-hover": "#0A1D4D", - "surface-interactive-weak": "var(--cobalt-dark-2)", - "surface-interactive-weak-hover": "var(--cobalt-light-3)", - "surface-success-base": "var(--apple-dark-3)", - "surface-success-weak": "var(--apple-dark-2)", - "surface-success-strong": "var(--apple-dark-9)", - "surface-warning-base": "var(--solaris-light-3)", - "surface-warning-weak": "var(--solaris-light-2)", - "surface-warning-strong": "var(--solaris-light-9)", - "surface-critical-base": "var(--ember-dark-3)", - "surface-critical-weak": "var(--ember-dark-2)", - "surface-critical-strong": "var(--ember-dark-9)", - "surface-info-base": "var(--lilac-light-3)", - "surface-info-weak": "var(--lilac-light-2)", - "surface-info-strong": "var(--lilac-light-9)", - "surface-diff-unchanged-base": "var(--gray-dark-1)", - "surface-diff-skip-base": "var(--gray-dark-alpha-1)", - "surface-diff-hidden-base": "var(--blue-dark-2)", - "surface-diff-hidden-weak": "var(--blue-dark-1)", - "surface-diff-hidden-weaker": "var(--blue-dark-3)", - "surface-diff-hidden-strong": "var(--blue-dark-5)", - "surface-diff-hidden-stronger": "var(--blue-dark-11)", - "surface-diff-add-base": "var(--mint-dark-3)", - "surface-diff-add-weak": "var(--mint-dark-4)", - "surface-diff-add-weaker": "var(--mint-dark-3)", - "surface-diff-add-strong": "var(--mint-dark-5)", - "surface-diff-add-stronger": "var(--mint-dark-11)", - "surface-diff-delete-base": "var(--ember-dark-3)", - "surface-diff-delete-weak": "var(--ember-dark-4)", - "surface-diff-delete-weaker": "var(--ember-dark-3)", - "surface-diff-delete-strong": "var(--ember-dark-5)", - "surface-diff-delete-stronger": "var(--ember-dark-11)", - "input-base": "var(--gray-dark-2)", - "input-hover": "var(--gray-dark-2)", - "input-active": "var(--cobalt-dark-1)", - "input-selected": "var(--cobalt-dark-2)", - "input-focus": "var(--cobalt-dark-1)", - "input-disabled": "var(--gray-dark-4)", - "text-base": "var(--gray-dark-alpha-11)", - "text-weak": "var(--gray-dark-alpha-9)", - "text-weaker": "var(--gray-dark-alpha-8)", - "text-strong": "var(--gray-dark-alpha-12)", - "text-invert-base": "var(--gray-dark-alpha-11)", - "text-invert-weak": "var(--gray-dark-alpha-9)", - "text-invert-weaker": "var(--gray-dark-alpha-8)", - "text-invert-strong": "var(--gray-dark-alpha-12)", - "text-interactive-base": "var(--cobalt-dark-11)", - "text-on-brand-base": "var(--gray-dark-alpha-11)", - "text-on-interactive-base": "var(--gray-dark-12)", - "text-on-interactive-weak": "var(--gray-dark-alpha-11)", - "text-on-success-base": "var(--apple-dark-9)", - "text-on-critical-base": "var(--ember-dark-9)", - "text-on-critical-weak": "var(--ember-dark-8)", - "text-on-critical-strong": "var(--ember-dark-12)", - "text-on-warning-base": "var(--gray-dark-alpha-11)", - "text-on-info-base": "var(--gray-dark-alpha-11)", - "text-diff-add-base": "var(--mint-dark-11)", - "text-diff-delete-base": "var(--ember-dark-9)", - "text-diff-delete-strong": "var(--ember-dark-12)", - "text-diff-add-strong": "var(--mint-dark-8)", - "text-on-info-weak": "var(--gray-dark-alpha-9)", - "text-on-info-strong": "var(--gray-dark-alpha-12)", - "text-on-warning-weak": "var(--gray-dark-alpha-9)", - "text-on-warning-strong": "var(--gray-dark-alpha-12)", - "text-on-success-weak": "var(--apple-dark-8)", - "text-on-success-strong": "var(--apple-dark-12)", - "text-on-brand-weak": "var(--gray-dark-alpha-9)", - "text-on-brand-weaker": "var(--gray-dark-alpha-8)", - "text-on-brand-strong": "var(--gray-dark-alpha-12)", - "button-primary-base": "var(--gray-dark-12)", - "button-secondary-base": "var(--gray-dark-2)", - "button-secondary-hover": "#FFFFFF0A", - "border-base": "var(--gray-dark-alpha-7)", - "border-hover": "var(--gray-dark-alpha-8)", - "border-active": "var(--gray-dark-alpha-9)", - "border-selected": "var(--cobalt-dark-alpha-11)", - "border-disabled": "var(--gray-dark-alpha-8)", - "border-focus": "var(--gray-dark-alpha-9)", - "border-weak-base": "var(--gray-dark-alpha-5)", - "border-weak-hover": "var(--gray-dark-alpha-7)", - "border-weak-active": "var(--gray-dark-alpha-8)", - "border-weak-selected": "var(--cobalt-dark-alpha-6)", - "border-weak-disabled": "var(--gray-dark-alpha-6)", - "border-weak-focus": "var(--gray-dark-alpha-8)", - "border-strong-base": "var(--gray-dark-alpha-8)", - "border-interactive-base": "var(--cobalt-light-7)", - "border-interactive-hover": "var(--cobalt-light-8)", - "border-interactive-active": "var(--cobalt-light-9)", - "border-interactive-selected": "var(--cobalt-light-9)", - "border-interactive-disabled": "var(--gray-light-8)", - "border-interactive-focus": "var(--cobalt-light-9)", - "border-success-base": "var(--apple-light-6)", - "border-success-hover": "var(--apple-light-7)", - "border-success-selected": "var(--apple-light-9)", - "border-warning-base": "var(--solaris-light-6)", - "border-warning-hover": "var(--solaris-light-7)", - "border-warning-selected": "var(--solaris-light-9)", - "border-critical-base": "var(--ember-dark-5)", - "border-critical-hover": "var(--ember-dark-7)", - "border-critical-selected": "var(--ember-dark-9)", - "border-info-base": "var(--lilac-light-6)", - "border-info-hover": "var(--lilac-light-7)", - "border-info-selected": "var(--lilac-light-9)", - "icon-base": "var(--gray-dark-10)", - "icon-hover": "var(--gray-dark-11)", - "icon-active": "var(--gray-dark-12)", - "icon-selected": "var(--gray-dark-12)", - "icon-disabled": "var(--gray-dark-8)", - "icon-focus": "var(--gray-dark-12)", - "icon-invert-base": "var(--gray-dark-1)", - "icon-weak-base": "var(--gray-dark-6)", - "icon-weak-hover": "var(--gray-light-7)", - "icon-weak-active": "var(--gray-light-8)", - "icon-weak-selected": "var(--gray-light-9)", - "icon-weak-disabled": "var(--gray-light-4)", - "icon-weak-focus": "var(--gray-light-9)", - "icon-strong-base": "var(--gray-dark-12)", - "icon-strong-hover": "#F3F3F3", - "icon-strong-active": "#EBEBEB", - "icon-strong-selected": "#FCFCFC", - "icon-strong-disabled": "var(--gray-dark-7)", - "icon-strong-focus": "#FCFCFC", - "icon-brand-base": "var(--white)", - "icon-interactive-base": "var(--cobalt-dark-11)", - "icon-success-base": "var(--apple-dark-9)", - "icon-success-hover": "var(--apple-dark-10)", - "icon-success-active": "var(--apple-dark-11)", - "icon-warning-base": "var(--amber-dark-9)", - "icon-warning-hover": "var(--amber-dark-8)", - "icon-warning-active": "var(--amber-dark-11)", - "icon-critical-base": "var(--ember-dark-9)", - "icon-critical-hover": "var(--ember-dark-11)", - "icon-critical-active": "var(--ember-dark-12)", - "icon-info-base": "var(--lilac-dark-7)", - "icon-info-hover": "var(--lilac-dark-8)", - "icon-info-active": "var(--lilac-dark-11)", - "icon-on-brand-base": "var(--gray-light-alpha-11)", - "icon-on-brand-hover": "var(--gray-light-alpha-12)", - "icon-on-brand-selected": "var(--gray-light-alpha-12)", - "icon-on-interactive-base": "var(--gray-dark-12)", - "icon-agent-plan-base": "var(--purple-dark-9)", - "icon-agent-docs-base": "var(--amber-dark-9)", - "icon-agent-ask-base": "var(--cyan-dark-9)", - "icon-agent-build-base": "var(--cobalt-dark-11)", - "icon-on-success-base": "var(--apple-dark-alpha-9)", - "icon-on-success-hover": "var(--apple-dark-alpha-10)", - "icon-on-success-selected": "var(--apple-dark-alpha-11)", - "icon-on-warning-base": "var(--amber-darkalpha-9)", - "icon-on-warning-hover": "var(--amber-darkalpha-10)", - "icon-on-warning-selected": "var(--amber-darkalpha-11)", - "icon-on-critical-base": "var(--ember-dark-alpha-9)", - "icon-on-critical-hover": "var(--ember-dark-alpha-10)", - "icon-on-critical-selected": "var(--ember-dark-alpha-11)", - "icon-on-info-base": "var(--lilac-dark-9)", - "icon-on-info-hover": "var(--lilac-dark-alpha-10)", - "icon-on-info-selected": "var(--lilac-dark-alpha-11)", - "icon-diff-add-base": "var(--mint-dark-11)", - "icon-diff-add-hover": "var(--mint-dark-10)", - "icon-diff-add-active": "var(--mint-dark-11)", - "icon-diff-delete-base": "var(--ember-dark-9)", - "icon-diff-delete-hover": "var(--ember-dark-10)", - "syntax-comment": "var(--text-weak)", - "syntax-regexp": "var(--text-base)", - "syntax-string": "#00ceb9", - "syntax-keyword": "var(--text-weak)", - "syntax-primitive": "#ffba92", - "syntax-operator": "var(--text-weak)", - "syntax-variable": "var(--text-strong)", - "syntax-property": "#ff9ae2", - "syntax-type": "#ecf58c", - "syntax-constant": "#93e9f6", - "syntax-punctuation": "var(--text-weak)", - "syntax-object": "var(--text-strong)", - "syntax-success": "var(--apple-dark-10)", - "syntax-warning": "var(--amber-dark-10)", - "syntax-critical": "var(--ember-dark-10)", - "syntax-info": "#93e9f6", - "syntax-diff-add": "var(--mint-dark-11)", - "syntax-diff-delete": "var(--ember-dark-11)", - "syntax-diff-unknown": "#ff0000", - "markdown-heading": "#9d7cd8", - "markdown-text": "#eeeeee", - "markdown-link": "#fab283", - "markdown-link-text": "#56b6c2", - "markdown-code": "#7fd88f", - "markdown-block-quote": "#e5c07b", - "markdown-emph": "#e5c07b", - "markdown-strong": "#f5a742", - "markdown-horizontal-rule": "#808080", - "markdown-list-item": "#fab283", - "markdown-list-enumeration": "#56b6c2", - "markdown-image": "#fab283", - "markdown-image-text": "#56b6c2", - "markdown-code-block": "#eeeeee", - "border-color": "#ffffff", - "border-weaker-base": "var(--gray-dark-alpha-3)", - "border-weaker-hover": "var(--gray-dark-alpha-4)", - "border-weaker-active": "var(--gray-dark-alpha-6)", - "border-weaker-selected": "var(--cobalt-dark-alpha-3)", - "border-weaker-disabled": "var(--gray-dark-alpha-2)", - "border-weaker-focus": "var(--gray-dark-alpha-6)", - "button-ghost-hover": "var(--gray-dark-alpha-2)", - "button-ghost-hover2": "var(--gray-dark-alpha-3)", - "avatar-background-pink": "#501b3f", - "avatar-background-mint": "#033a34", - "avatar-background-orange": "#5f2a06", - "avatar-background-purple": "#432155", - "avatar-background-cyan": "#0f3058", - "avatar-background-lime": "#2b3711", - "avatar-text-pink": "#e34ba9", - "avatar-text-mint": "#95f3d9", - "avatar-text-orange": "#ff802b", - "avatar-text-purple": "#9d5bd2", - "avatar-text-cyan": "#369eff", - "avatar-text-lime": "#c4f042" } } } diff --git a/packages/ui/src/theme/themes/onedarkpro.json b/packages/ui/src/theme/themes/onedarkpro.json index ce01511e85..be17dedff3 100644 --- a/packages/ui/src/theme/themes/onedarkpro.json +++ b/packages/ui/src/theme/themes/onedarkpro.json @@ -3,129 +3,39 @@ "name": "One Dark Pro", "id": "onedarkpro", "light": { - "seeds": { + "palette": { "neutral": "#f5f6f8", + "ink": "#2b303b", "primary": "#528bff", + "accent": "#d85462", "success": "#4fa66d", "warning": "#d19a66", "error": "#e06c75", "info": "#61afef", - "interactive": "#528bff", "diffAdd": "#c2ebcf", "diffDelete": "#f7c1c5" }, "overrides": { - "background-base": "#f5f6f8", - "background-weak": "#eef0f4", - "background-strong": "#fafbfc", - "background-stronger": "#ffffff", - "border-weak-base": "#dee2eb", - "border-weak-hover": "#d4d9e3", - "border-weak-active": "#caced6", - "border-weak-selected": "#bec4d0", - "border-weak-disabled": "#f4f6fb", - "border-weak-focus": "#c4cada", - "border-base": "#b5bccd", - "border-hover": "#aab1c2", - "border-active": "#a0a7b8", - "border-selected": "#959cae", - "border-disabled": "#eceef4", - "border-focus": "#a6adbf", - "border-strong-base": "#747c92", - "border-strong-hover": "#6a7287", - "border-strong-active": "#60687c", - "border-strong-selected": "#565e71", - "border-strong-disabled": "#cbd0dd", - "border-strong-focus": "#666d82", - "surface-diff-add-base": "#e5f4ea", - "surface-diff-delete-base": "#fde7ea", - "surface-diff-hidden-base": "#e4e8f4", - "text-base": "#2b303b", - "text-weak": "#6b717f", - "text-strong": "#0e1118", - "syntax-string": "#4fa66d", - "syntax-primitive": "#d85462", - "syntax-property": "#528bff", - "syntax-type": "#d19a66", - "syntax-constant": "#61afef", - "syntax-info": "#61afef", - "markdown-heading": "#528bff", - "markdown-text": "#2b303b", - "markdown-link": "#528bff", - "markdown-link-text": "#61afef", - "markdown-code": "#4fa66d", - "markdown-block-quote": "#d19a66", - "markdown-emph": "#d19a66", - "markdown-strong": "#d85462", - "markdown-horizontal-rule": "#d3d7e4", - "markdown-list-item": "#528bff", - "markdown-list-enumeration": "#61afef", - "markdown-image": "#528bff", - "markdown-image-text": "#61afef", - "markdown-code-block": "#528bff" + "syntax-keyword": "#a626a4", + "syntax-primitive": "#986801" } }, "dark": { - "seeds": { + "palette": { "neutral": "#1e222a", + "ink": "#abb2bf", "primary": "#61afef", + "accent": "#e06c75", "success": "#98c379", "warning": "#e5c07b", "error": "#e06c75", "info": "#56b6c2", - "interactive": "#61afef", "diffAdd": "#4b815a", "diffDelete": "#b2555f" }, "overrides": { - "background-base": "#1e222a", - "background-weak": "#212631", - "background-strong": "#1b1f27", - "background-stronger": "#171b23", - "border-weak-base": "#323848", - "border-weak-hover": "#363d52", - "border-weak-active": "#3c435c", - "border-weak-selected": "#424967", - "border-weak-disabled": "#141720", - "border-weak-focus": "#3f4560", - "border-base": "#4a5164", - "border-hover": "#515871", - "border-active": "#585f7e", - "border-selected": "#60688a", - "border-disabled": "#1a1e27", - "border-focus": "#555c79", - "border-strong-base": "#6a7390", - "border-strong-hover": "#737c9d", - "border-strong-active": "#7d87ab", - "border-strong-selected": "#8791b8", - "border-strong-disabled": "#212533", - "border-strong-focus": "#7680a2", - "surface-diff-add-base": "#1c2a26", - "surface-diff-delete-base": "#2a1c22", - "surface-diff-hidden-base": "#232836", - "text-base": "#abb2bf", - "text-weak": "#818899", - "text-strong": "#f6f7fb", - "syntax-string": "#98c379", - "syntax-primitive": "#e06c75", - "syntax-property": "#61afef", - "syntax-type": "#e5c07b", - "syntax-constant": "#56b6c2", - "syntax-info": "#56b6c2", - "markdown-heading": "#61afef", - "markdown-text": "#abb2bf", - "markdown-link": "#61afef", - "markdown-link-text": "#56b6c2", - "markdown-code": "#98c379", - "markdown-block-quote": "#e5c07b", - "markdown-emph": "#e5c07b", - "markdown-strong": "#e06c75", - "markdown-horizontal-rule": "#2d3444", - "markdown-list-item": "#61afef", - "markdown-list-enumeration": "#56b6c2", - "markdown-image": "#61afef", - "markdown-image-text": "#56b6c2", - "markdown-code-block": "#abb2bf" + "syntax-keyword": "#c678dd", + "syntax-primitive": "#d19a66" } } } diff --git a/packages/ui/src/theme/themes/shadesofpurple.json b/packages/ui/src/theme/themes/shadesofpurple.json index bc625770f9..03af35c2a3 100644 --- a/packages/ui/src/theme/themes/shadesofpurple.json +++ b/packages/ui/src/theme/themes/shadesofpurple.json @@ -3,129 +3,37 @@ "name": "Shades of Purple", "id": "shadesofpurple", "light": { - "seeds": { + "palette": { "neutral": "#f7ebff", + "ink": "#3b2c59", "primary": "#7a5af8", + "accent": "#ff6bd5", "success": "#3dd598", "warning": "#f7c948", "error": "#ff6bd5", "info": "#62d4ff", - "interactive": "#7a5af8", "diffAdd": "#c8f8da", "diffDelete": "#ffc3ef" }, "overrides": { - "background-base": "#f7ebff", - "background-weak": "#f2e2ff", - "background-strong": "#fbf2ff", - "background-stronger": "#fff7ff", - "border-weak-base": "#e5d3ff", - "border-weak-hover": "#dac8f5", - "border-weak-active": "#d1bdeb", - "border-weak-selected": "#c6b3e1", - "border-weak-disabled": "#fcf6ff", - "border-weak-focus": "#ccb9e7", - "border-base": "#baa4d5", - "border-hover": "#b098cb", - "border-active": "#a68dc2", - "border-selected": "#9b82b8", - "border-disabled": "#f1e7ff", - "border-focus": "#a692c6", - "border-strong-base": "#8769a9", - "border-strong-hover": "#7b5c9d", - "border-strong-active": "#704f91", - "border-strong-selected": "#664587", - "border-strong-disabled": "#d8c4f0", - "border-strong-focus": "#755495", - "surface-diff-add-base": "#edf8f1", - "surface-diff-delete-base": "#ffe4f4", - "surface-diff-hidden-base": "#e9e4ff", - "text-base": "#3b2c59", - "text-weak": "#6c568f", - "text-strong": "#1c1033", - "syntax-string": "#3dd598", - "syntax-primitive": "#ff6bd5", - "syntax-property": "#7a5af8", - "syntax-type": "#f7c948", - "syntax-constant": "#62d4ff", - "syntax-info": "#62d4ff", - "markdown-heading": "#7a5af8", - "markdown-text": "#3b2c59", - "markdown-link": "#7a5af8", - "markdown-link-text": "#62d4ff", - "markdown-code": "#3dd598", - "markdown-block-quote": "#f7c948", - "markdown-emph": "#f7c948", - "markdown-strong": "#ff6bd5", - "markdown-horizontal-rule": "#decbed", - "markdown-list-item": "#7a5af8", - "markdown-list-enumeration": "#62d4ff", - "markdown-image": "#7a5af8", - "markdown-image-text": "#62d4ff", - "markdown-code-block": "#7a5af8" + "syntax-keyword": "#ff6bd5" } }, "dark": { - "seeds": { + "palette": { "neutral": "#1a102b", + "ink": "#f5f0ff", "primary": "#c792ff", + "accent": "#ff7ac6", "success": "#7be0b0", "warning": "#ffd580", "error": "#ff7ac6", "info": "#7dd4ff", - "interactive": "#c792ff", "diffAdd": "#53c39f", "diffDelete": "#d85aa0" }, "overrides": { - "background-base": "#1a102b", - "background-weak": "#1f1434", - "background-strong": "#1c122f", - "background-stronger": "#170e26", - "border-weak-base": "#352552", - "border-weak-hover": "#3a2a5d", - "border-weak-active": "#402f68", - "border-weak-selected": "#463674", - "border-weak-disabled": "#10091b", - "border-weak-focus": "#3d2d65", - "border-base": "#4d3a73", - "border-hover": "#553f7f", - "border-active": "#5d468c", - "border-selected": "#654c99", - "border-disabled": "#150d21", - "border-focus": "#594283", - "border-strong-base": "#7659b0", - "border-strong-hover": "#8262be", - "border-strong-active": "#8e6ccc", - "border-strong-selected": "#9a77da", - "border-strong-disabled": "#1c122c", - "border-strong-focus": "#8666c4", - "surface-diff-add-base": "#142c27", - "surface-diff-delete-base": "#2d1424", - "surface-diff-hidden-base": "#231737", - "text-base": "#f5f0ff", - "text-weak": "#c9b6ff", - "text-strong": "#ffffff", - "syntax-string": "#7be0b0", - "syntax-primitive": "#ff7ac6", - "syntax-property": "#c792ff", - "syntax-type": "#ffd580", - "syntax-constant": "#7dd4ff", - "syntax-info": "#7dd4ff", - "markdown-heading": "#c792ff", - "markdown-text": "#f5f0ff", - "markdown-link": "#c792ff", - "markdown-link-text": "#7dd4ff", - "markdown-code": "#7be0b0", - "markdown-block-quote": "#ffd580", - "markdown-emph": "#ffd580", - "markdown-strong": "#ff7ac6", - "markdown-horizontal-rule": "#2d1d41", - "markdown-list-item": "#c792ff", - "markdown-list-enumeration": "#7dd4ff", - "markdown-image": "#c792ff", - "markdown-image-text": "#7dd4ff", - "markdown-code-block": "#f5f0ff" + "syntax-keyword": "#ff7ac6" } } } diff --git a/packages/ui/src/theme/themes/solarized.json b/packages/ui/src/theme/themes/solarized.json index 7cb44775af..24a4daf458 100644 --- a/packages/ui/src/theme/themes/solarized.json +++ b/packages/ui/src/theme/themes/solarized.json @@ -3,129 +3,39 @@ "name": "Solarized", "id": "solarized", "light": { - "seeds": { + "palette": { "neutral": "#fdf6e3", + "ink": "#586e75", "primary": "#268bd2", + "accent": "#d33682", "success": "#859900", "warning": "#b58900", "error": "#dc322f", "info": "#2aa198", - "interactive": "#268bd2", "diffAdd": "#c6dc7a", "diffDelete": "#f2a1a1" }, "overrides": { - "background-base": "#fdf6e3", - "background-weak": "#f6efda", - "background-strong": "#faf3dc", - "background-stronger": "#f6edd4", - "border-weak-base": "#e3e0cd", - "border-weak-hover": "#d9d4c2", - "border-weak-active": "#cfcab7", - "border-weak-selected": "#c5c0ad", - "border-weak-disabled": "#f2edda", - "border-weak-focus": "#cbc6b2", - "border-base": "#bcb5a0", - "border-hover": "#b1aa96", - "border-active": "#a59f8c", - "border-selected": "#999382", - "border-disabled": "#ede7d4", - "border-focus": "#aca58f", - "border-strong-base": "#8c8572", - "border-strong-hover": "#7f7866", - "border-strong-active": "#716b5b", - "border-strong-selected": "#645f50", - "border-strong-disabled": "#d5cdb8", - "border-strong-focus": "#78715f", - "surface-diff-add-base": "#eef5d6", - "surface-diff-delete-base": "#fde4dd", - "surface-diff-hidden-base": "#e3ecf3", - "text-base": "#586e75", - "text-weak": "#7a8c8e", - "text-strong": "#073642", - "syntax-string": "#859900", - "syntax-primitive": "#d33682", - "syntax-property": "#268bd2", - "syntax-type": "#b58900", - "syntax-constant": "#2aa198", - "syntax-info": "#2aa198", - "markdown-heading": "#268bd2", - "markdown-text": "#586e75", - "markdown-link": "#268bd2", - "markdown-link-text": "#2aa198", - "markdown-code": "#859900", - "markdown-block-quote": "#b58900", - "markdown-emph": "#b58900", - "markdown-strong": "#d33682", - "markdown-horizontal-rule": "#cfd1bf", - "markdown-list-item": "#268bd2", - "markdown-list-enumeration": "#2aa198", - "markdown-image": "#268bd2", - "markdown-image-text": "#2aa198", - "markdown-code-block": "#2aa198" + "syntax-keyword": "#859900", + "syntax-string": "#2aa198" } }, "dark": { - "seeds": { + "palette": { "neutral": "#002b36", + "ink": "#93a1a1", "primary": "#6c71c4", + "accent": "#d33682", "success": "#859900", "warning": "#b58900", "error": "#dc322f", "info": "#2aa198", - "interactive": "#6c71c4", "diffAdd": "#4c7654", "diffDelete": "#c34b4b" }, "overrides": { - "background-base": "#001f27", - "background-weak": "#022733", - "background-strong": "#01222b", - "background-stronger": "#032830", - "border-weak-base": "#20373f", - "border-weak-hover": "#243e47", - "border-weak-active": "#28434f", - "border-weak-selected": "#2d4958", - "border-weak-disabled": "#0f2026", - "border-weak-focus": "#2a4552", - "border-base": "#31505b", - "border-hover": "#365765", - "border-active": "#3c5e70", - "border-selected": "#42657a", - "border-disabled": "#13272e", - "border-focus": "#3a5a6b", - "border-strong-base": "#4a7887", - "border-strong-hover": "#528294", - "border-strong-active": "#5a8ca1", - "border-strong-selected": "#6396ae", - "border-strong-disabled": "#1b323b", - "border-strong-focus": "#56879a", - "surface-diff-add-base": "#0f2f29", - "surface-diff-delete-base": "#321c1c", - "surface-diff-hidden-base": "#0f3844", - "text-base": "#93a1a1", - "text-weak": "#6c7f80", - "text-strong": "#fdf6e3", - "syntax-string": "#859900", - "syntax-primitive": "#d33682", - "syntax-property": "#6c71c4", - "syntax-type": "#b58900", - "syntax-constant": "#2aa198", - "syntax-info": "#2aa198", - "markdown-heading": "#6c71c4", - "markdown-text": "#93a1a1", - "markdown-link": "#6c71c4", - "markdown-link-text": "#2aa198", - "markdown-code": "#859900", - "markdown-block-quote": "#b58900", - "markdown-emph": "#b58900", - "markdown-strong": "#d33682", - "markdown-horizontal-rule": "#0e3b46", - "markdown-list-item": "#6c71c4", - "markdown-list-enumeration": "#2aa198", - "markdown-image": "#6c71c4", - "markdown-image-text": "#2aa198", - "markdown-code-block": "#93a1a1" + "syntax-keyword": "#859900", + "syntax-string": "#2aa198" } } } diff --git a/packages/ui/src/theme/themes/tokyonight.json b/packages/ui/src/theme/themes/tokyonight.json index 31d0e8a474..d29c359942 100644 --- a/packages/ui/src/theme/themes/tokyonight.json +++ b/packages/ui/src/theme/themes/tokyonight.json @@ -3,153 +3,37 @@ "name": "Tokyonight", "id": "tokyonight", "light": { - "seeds": { + "palette": { "neutral": "#e1e2e7", + "ink": "#273153", "primary": "#2e7de9", + "accent": "#b15c00", "success": "#587539", "warning": "#8c6c3e", "error": "#c94060", "info": "#007197", - "interactive": "#2e7de9", "diffAdd": "#4f8f7b", "diffDelete": "#d05f7c" }, "overrides": { - "background-base": "#e1e2e7", - "background-weak": "#dee0ea", - "background-strong": "#e5e6ee", - "background-stronger": "#e9eaf1", - "border-weak-base": "#cdd0dc", - "border-weak-hover": "#c3c6d2", - "border-weak-active": "#b9bcc8", - "border-weak-selected": "#aeb2bf", - "border-weak-disabled": "#e6e7ef", - "border-weak-focus": "#b3b6c3", - "border-base": "#a7abbb", - "border-hover": "#9ba0b1", - "border-active": "#9095a8", - "border-selected": "#83889e", - "border-disabled": "#dedfe6", - "border-focus": "#9599a8", - "border-strong-base": "#757b90", - "border-strong-hover": "#6a7084", - "border-strong-active": "#5f6578", - "border-strong-selected": "#545a6d", - "border-strong-disabled": "#c4c6d0", - "border-strong-focus": "#666b7f", - "surface-diff-add-base": "#dfe7da", - "surface-diff-delete-base": "#f4dadd", - "surface-diff-hidden-base": "#cfd1dd", - "text-base": "#273153", - "text-weak": "#5c6390", - "text-strong": "#1c2544", - "syntax-string": "#587539", - "syntax-primitive": "#b15c00", - "syntax-property": "#9854f1", - "syntax-type": "#3760bf", - "syntax-constant": "#007197", - "syntax-info": "#007197", - "markdown-heading": "#9854f1", - "markdown-text": "#273153", - "markdown-link": "#2e7de9", - "markdown-link-text": "#007197", - "markdown-code": "#587539", - "markdown-block-quote": "#8c6c3e", - "markdown-emph": "#8c6c3e", - "markdown-strong": "#b15c00", - "markdown-horizontal-rule": "#a1a6c5", - "markdown-list-item": "#2e7de9", - "markdown-list-enumeration": "#007197", - "markdown-image": "#2e7de9", - "markdown-image-text": "#007197", - "markdown-code-block": "#3760bf" + "syntax-keyword": "#9854f1" } }, "dark": { - "seeds": { + "palette": { "neutral": "#1a1b26", + "ink": "#c0caf5", "primary": "#7aa2f7", + "accent": "#ff9e64", "success": "#9ece6a", "warning": "#e0af68", "error": "#f7768e", "info": "#7dcfff", - "interactive": "#7aa2f7", "diffAdd": "#41a6b5", "diffDelete": "#c34043" }, "overrides": { - "background-base": "#0f111a", - "background-weak": "#111428", - "background-strong": "#101324", - "background-stronger": "#13172a", - "border-weak-base": "#25283b", - "border-weak-hover": "#292c43", - "border-weak-active": "#2e314b", - "border-weak-selected": "#343755", - "border-weak-disabled": "#151727", - "border-weak-focus": "#30324f", - "border-base": "#3a3e57", - "border-hover": "#414264", - "border-active": "#474972", - "border-selected": "#4f507f", - "border-disabled": "#1c1d2d", - "border-focus": "#45496f", - "border-strong-base": "#5a5f82", - "border-strong-hover": "#646994", - "border-strong-active": "#6f74a6", - "border-strong-selected": "#7a7fb8", - "border-strong-disabled": "#23243a", - "border-strong-focus": "#6a6f9f", - "surface-base": "#1f2335", - "base": "#1f2335", - "surface-base-hover": "#232840", - "surface-base-active": "#262c46", - "surface-base-interactive-active": "#2b3357", - "base2": "#1f2335", - "base3": "#1f2335", - "surface-inset-base": "#161a2ab3", - "surface-inset-base-hover": "#161a2acc", - "surface-inset-strong": "#0d111fcc", - "surface-inset-strong-hover": "#0d111fcc", - "surface-raised-base": "#242a42", - "surface-float-base": "#242b45", - "surface-float-base-hover": "#2a3154", - "surface-raised-base-hover": "#272e49", - "surface-raised-base-active": "#2c3353", - "surface-raised-strong": "#31385a", - "surface-raised-strong-hover": "#373f6b", - "surface-raised-stronger": "#3b4261", - "surface-raised-stronger-hover": "#444c82", - "surface-weak": "#1b2033", - "surface-weaker": "#181d2d", - "surface-strong": "#323858", - "surface-raised-stronger-non-alpha": "#2b3150", - "surface-diff-add-base": "#1c2a38", - "surface-diff-delete-base": "#2a1f32", - "surface-diff-hidden-base": "#24283b", - "text-base": "#c0caf5", - "text-weak": "#7a88cf", - "text-strong": "#eaeaff", - "syntax-string": "#9ece6a", - "syntax-primitive": "#ff9e64", - "syntax-property": "#bb9af7", - "syntax-type": "#e0af68", - "syntax-constant": "#7dcfff", - "syntax-info": "#7dcfff", - "markdown-heading": "#bb9af7", - "markdown-text": "#c0caf5", - "markdown-link": "#7aa2f7", - "markdown-link-text": "#7dcfff", - "markdown-code": "#9ece6a", - "markdown-block-quote": "#e0af68", - "markdown-emph": "#e0af68", - "markdown-strong": "#ff9e64", - "markdown-horizontal-rule": "#3b4261", - "markdown-list-item": "#7aa2f7", - "markdown-list-enumeration": "#7dcfff", - "markdown-image": "#7aa2f7", - "markdown-image-text": "#7dcfff", - "markdown-code-block": "#c0caf5" + "syntax-keyword": "#bb9af7" } } } diff --git a/packages/ui/src/theme/themes/vesper.json b/packages/ui/src/theme/themes/vesper.json index 040bdc049b..8cc658232f 100644 --- a/packages/ui/src/theme/themes/vesper.json +++ b/packages/ui/src/theme/themes/vesper.json @@ -3,129 +3,38 @@ "name": "Vesper", "id": "vesper", "light": { - "seeds": { + "palette": { "neutral": "#F0F0F0", + "ink": "#101010", "primary": "#FFC799", + "accent": "#B30000", "success": "#99FFE4", "warning": "#FFC799", "error": "#FF8080", "info": "#FFC799", - "interactive": "#FFC799", "diffAdd": "#99FFE4", "diffDelete": "#FF8080" }, "overrides": { - "background-base": "#FFF", - "background-weak": "#F8F8F8", - "background-strong": "#F0F0F0", - "background-stronger": "#FBFBFB", - "border-weak-hover": "#E0E0E0", - "border-weak-active": "#D8D8D8", - "border-weak-selected": "#D0D0D0", - "border-weak-disabled": "#F0F0F0", - "border-weak-focus": "#D8D8D8", - "border-base": "#D0D0D0", - "border-hover": "#C8C8C8", - "border-active": "#C0C0C0", - "border-selected": "#B8B8B8", - "border-disabled": "#E8E8E8", - "border-focus": "#C0C0C0", - "border-strong-base": "#A0A0A0", - "border-strong-hover": "#989898", - "border-strong-active": "#909090", - "border-strong-selected": "#888888", - "border-strong-disabled": "#D0D0D0", - "border-strong-focus": "#909090", - "surface-diff-add-base": "#e8f5e8", - "surface-diff-delete-base": "#f5e8e8", - "surface-diff-hidden-base": "#F0F0F0", - "text-base": "#101010", - "text-invert-strong": "var(--smoke-dark-alpha-12)", - "text-weak": "#606060", - "text-strong": "#000000", - "syntax-string": "#0D5C4F", - "syntax-primitive": "#B30000", - "syntax-property": "#C66C00", - "syntax-type": "#9C5C12", - "syntax-constant": "#404040", - "syntax-info": "#606060", - "markdown-heading": "#FFC799", - "markdown-text": "#101010", - "markdown-link": "#FFC799", - "markdown-link-text": "#A0A0A0", - "markdown-code": "#A0A0A0", - "markdown-block-quote": "#101010", - "markdown-emph": "#101010", - "markdown-strong": "#101010", - "markdown-horizontal-rule": "#65737E", - "markdown-list-item": "#101010", - "markdown-list-enumeration": "#101010", - "markdown-image": "#FFC799", - "markdown-image-text": "#A0A0A0", - "markdown-code-block": "#FFC799" + "syntax-keyword": "#b30000" } }, "dark": { - "seeds": { + "palette": { "neutral": "#101010", + "ink": "#FFF", "primary": "#FFC799", + "accent": "#FF8080", "success": "#99FFE4", "warning": "#FFC799", "error": "#FF8080", "info": "#FFC799", - "interactive": "#FFC799", "diffAdd": "#99FFE4", "diffDelete": "#FF8080" }, "overrides": { - "background-base": "#101010", - "background-weak": "#141414", - "background-strong": "#0C0C0C", - "background-stronger": "#080808", - "border-weak-base": "#1C1C1C", - "border-weak-hover": "#202020", - "border-weak-active": "#242424", - "border-weak-selected": "#282828", - "border-weak-disabled": "#141414", - "border-weak-focus": "#242424", - "border-base": "#282828", - "border-hover": "#303030", - "border-active": "#383838", - "border-selected": "#404040", - "border-disabled": "#181818", - "border-focus": "#383838", - "border-strong-base": "#505050", - "border-strong-hover": "#585858", - "border-strong-active": "#606060", - "border-strong-selected": "#686868", - "border-strong-disabled": "#202020", - "border-strong-focus": "#606060", - "surface-diff-add-base": "#0d2818", - "surface-diff-delete-base": "#281a1a", - "surface-diff-hidden-base": "#141414", - "text-base": "#FFF", - "text-weak": "#A0A0A0", - "text-strong": "#FFFFFF", - "syntax-string": "#99FFE4", - "syntax-primitive": "#FF8080", - "syntax-property": "#FFC799", - "syntax-type": "#FFC799", - "syntax-constant": "#A0A0A0", - "syntax-info": "#8b8b8b", - "markdown-heading": "#FFC799", - "markdown-text": "#FFF", - "markdown-link": "#FFC799", - "markdown-link-text": "#A0A0A0", - "markdown-code": "#A0A0A0", - "markdown-block-quote": "#FFF", - "markdown-emph": "#FFF", - "markdown-strong": "#FFF", - "markdown-horizontal-rule": "#65737E", - "markdown-list-item": "#FFF", - "markdown-list-enumeration": "#FFF", - "markdown-image": "#FFC799", - "markdown-image-text": "#A0A0A0", - "markdown-code-block": "#FFF" + "syntax-keyword": "#ff8080", + "syntax-primitive": "#ffc799" } } } diff --git a/packages/ui/src/theme/types.ts b/packages/ui/src/theme/types.ts index 73bd372b45..126e9bb5aa 100644 --- a/packages/ui/src/theme/types.ts +++ b/packages/ui/src/theme/types.ts @@ -18,11 +18,28 @@ export interface ThemeSeedColors { diffDelete: HexColor } -export interface ThemeVariant { - seeds: ThemeSeedColors +export interface ThemePaletteColors { + neutral: HexColor + ink?: HexColor + primary: HexColor + success: HexColor + warning: HexColor + error: HexColor + info: HexColor + accent?: HexColor + interactive?: HexColor + diffAdd?: HexColor + diffDelete?: HexColor +} + +type ThemeVariantBase = { overrides?: Record<string, ColorValue> } +export type ThemeVariant = + | ({ seeds: ThemeSeedColors; palette?: never } & ThemeVariantBase) + | ({ palette: ThemePaletteColors; seeds?: never } & ThemeVariantBase) + export interface DesktopTheme { $schema?: string name: string diff --git a/packages/ui/tsconfig.json b/packages/ui/tsconfig.json index 832f7cbf81..25f6a3dcc4 100644 --- a/packages/ui/tsconfig.json +++ b/packages/ui/tsconfig.json @@ -17,5 +17,6 @@ // Type Checking & Safety "strict": true, "types": ["vite/client", "bun"] - } + }, + "exclude": ["**/*.stories.*", "**/*.mdx"] } diff --git a/packages/util/package.json b/packages/util/package.json index 4bcbb0305d..1b36f37484 100644 --- a/packages/util/package.json +++ b/packages/util/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/util", - "version": "1.2.10", + "version": "1.2.24", "private": true, "type": "module", "license": "MIT", diff --git a/packages/util/src/module.ts b/packages/util/src/module.ts new file mode 100644 index 0000000000..6ed3b23d7a --- /dev/null +++ b/packages/util/src/module.ts @@ -0,0 +1,10 @@ +import { createRequire } from "node:module" +import path from "node:path" + +export namespace Module { + export function resolve(id: string, dir: string) { + try { + return createRequire(path.join(dir, "package.json")).resolve(id) + } catch {} + } +} diff --git a/packages/web/astro.config.mjs b/packages/web/astro.config.mjs index b14a7ccb8f..110c8ce919 100644 --- a/packages/web/astro.config.mjs +++ b/packages/web/astro.config.mjs @@ -224,7 +224,7 @@ export default defineConfig({ "zh-CN": "使用", "zh-TW": "使用", }, - items: ["tui", "cli", "web", "ide", "zen", "share", "github", "gitlab"], + items: ["go", "tui", "cli", "web", "ide", "zen", "share", "github", "gitlab"], }, { @@ -314,7 +314,7 @@ function configSchema() { hooks: { "astro:build:done": async () => { console.log("generating config schema") - spawnSync("../opencode/script/schema.ts", ["./dist/config.json"]) + spawnSync("../opencode/script/schema.ts", ["./dist/config.json", "./dist/tui.json"]) }, }, } diff --git a/packages/web/package.json b/packages/web/package.json index 110c6ca235..378493853b 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -2,7 +2,7 @@ "name": "@opencode-ai/web", "type": "module", "license": "MIT", - "version": "1.2.10", + "version": "1.2.24", "scripts": { "dev": "astro dev", "dev:remote": "VITE_API_URL=https://api.opencode.ai astro dev", diff --git a/packages/web/src/content/docs/ar/config.mdx b/packages/web/src/content/docs/ar/config.mdx index d415969972..5a1c294bf2 100644 --- a/packages/web/src/content/docs/ar/config.mdx +++ b/packages/web/src/content/docs/ar/config.mdx @@ -496,6 +496,7 @@ opencode run "Hello world" - `auto` - ضغط الجلسة تلقائيًا عند امتلاء السياق (الافتراضي: `true`). - `prune` - إزالة مخرجات الأدوات القديمة لتوفير الرموز (tokens) (الافتراضي: `true`). +- `reserved` - مخزن مؤقت للرموز (tokens) من أجل الضغط. يترك نافذة كافية لتجنب الفيضان أثناء الضغط. --- diff --git a/packages/web/src/content/docs/ar/custom-tools.mdx b/packages/web/src/content/docs/ar/custom-tools.mdx index 9382627fab..62eeed9cdc 100644 --- a/packages/web/src/content/docs/ar/custom-tools.mdx +++ b/packages/web/src/content/docs/ar/custom-tools.mdx @@ -79,6 +79,32 @@ export const multiply = tool({ --- +#### تضارب الأسماء مع الأدوات المدمجة + +تُصنّف الأدوات المخصصة حسب اسم الأداة. إذا استخدمت أداة مخصصة نفس اسم أداة مدمجة، فإن الأداة المخصصة تأخذ الأولوية. + +على سبيل المثال، يستبدل هذا الملف أداة `bash` المدمجة: + +```ts title=".opencode/tools/bash.ts" +import { tool } from "@opencode-ai/plugin" + +export default tool({ + description: "Restricted bash wrapper", + args: { + command: tool.schema.string(), + }, + async execute(args) { + return `blocked: ${args.command}` + }, +}) +``` + +:::note +فضّل استخدام أسماء فريدة ما لم تكن تريد استبدال أداة مدمجة عمدا. إذا كنت تريد تعطيل أداة مدمجة ولكن لا تريد استبدالها، استخدم [الأذونات](/docs/permissions). +::: + +--- + ### الوسائط يمكنك استخدام `tool.schema`، وهو في الأساس [Zod](https://zod.dev)، لتعريف أنواع الوسائط. diff --git a/packages/web/src/content/docs/ar/ecosystem.mdx b/packages/web/src/content/docs/ar/ecosystem.mdx index df3a4c7ddb..1725daffc6 100644 --- a/packages/web/src/content/docs/ar/ecosystem.mdx +++ b/packages/web/src/content/docs/ar/ecosystem.mdx @@ -6,71 +6,73 @@ description: مشاريع وتكاملات مبنية باستخدام OpenCode. مجموعة من مشاريع المجتمع المبنية على OpenCode. :::note -هل تريد إضافة مشروع مرتبط بـ OpenCode إلى هذه القائمة؟ قدّم PR. +هل تريد إضافة مشروعك المتعلق بـ OpenCode إلى هذه القائمة؟ أرسل طلب سحب (PR). ::: -يمكنك أيضا الاطلاع على [awesome-opencode](https://github.com/awesome-opencode/awesome-opencode) و [opencode.cafe](https://opencode.cafe)؛ وهو مجتمع يجمع روابط النظام البيئي والمجتمع. +يمكنك أيضًا الاطلاع على [awesome-opencode](https://github.com/awesome-opencode/awesome-opencode) و [opencode.cafe](https://opencode.cafe)، وهو مجتمع يجمع النظام البيئي والمجتمع. --- ## الإضافات -| الاسم | الوصف | -| --------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | -| [opencode-daytona](https://github.com/jamesmurdza/daytona/blob/main/guides/typescript/opencode/README.md) | تشغيل جلسات OpenCode تلقائيا داخل بيئات Daytona معزولة مع مزامنة git ومعاينات حية | -| [opencode-helicone-session](https://github.com/H2Shami/opencode-helicone-session) | حقن ترويسات جلسة Helicone تلقائيا لتجميع الطلبات | -| [opencode-type-inject](https://github.com/nick-vi/opencode-type-inject) | حقن أنواع TypeScript/Svelte تلقائيا في قراءات الملفات باستخدام أدوات البحث | -| [opencode-openai-codex-auth](https://github.com/numman-ali/opencode-openai-codex-auth) | استخدام اشتراك ChatGPT Plus/Pro بدلا من أرصدة واجهة API | -| [opencode-gemini-auth](https://github.com/jenslys/opencode-gemini-auth) | استخدام خطة Gemini الحالية بدلا من فوترة API | -| [opencode-antigravity-auth](https://github.com/NoeFabris/opencode-antigravity-auth) | استخدام نماذج Antigravity المجانية بدلا من فوترة API | -| [opencode-devcontainers](https://github.com/athal7/opencode-devcontainers) | عزل devcontainer متعدد الفروع مع استنساخات shallow ومنافذ تُعيَّن تلقائيا | -| [opencode-google-antigravity-auth](https://github.com/shekohex/opencode-google-antigravity-auth) | ملحق Google Antigravity OAuth مع دعم Google Search ومعالجة API أكثر متانة | -| [opencode-dynamic-context-pruning](https://github.com/Tarquinen/opencode-dynamic-context-pruning) | تحسين استخدام الرموز (tokens) عبر تقليم مخرجات الأدوات القديمة | -| [opencode-websearch-cited](https://github.com/ghoulr/opencode-websearch-cited.git) | إضافة دعم websearch أصلي للمزوّدين المدعومين بأسلوب مستند إلى Google | -| [opencode-pty](https://github.com/shekohex/opencode-pty.git) | تمكين وكلاء الذكاء الاصطناعي من تشغيل عمليات بالخلفية داخل PTY وإرسال إدخال تفاعلي إليها. | -| [opencode-shell-strategy](https://github.com/JRedeker/opencode-shell-strategy) | إرشادات لأوامر shell غير التفاعلية - تمنع التعليق الناتج عن عمليات تعتمد على TTY | -| [opencode-wakatime](https://github.com/angristan/opencode-wakatime) | تتبع استخدام OpenCode عبر Wakatime | -| [opencode-md-table-formatter](https://github.com/franlol/opencode-md-table-formatter/tree/main) | تنظيف جداول Markdown التي تنتجها نماذج LLM | -| [opencode-morph-fast-apply](https://github.com/JRedeker/opencode-morph-fast-apply) | تحرير الشيفرة أسرع بـ 10x باستخدام Morph Fast Apply API وعلامات تعديل كسولة | -| [oh-my-opencode](https://github.com/code-yeongyu/oh-my-opencode) | وكلاء خلفية وأدوات LSP/AST/MCP جاهزة ووكلاء منتقون وتوافق مع Claude Code | -| [opencode-notificator](https://github.com/panta82/opencode-notificator) | إشعارات سطح المكتب وتنبيهات صوتية لجلسات OpenCode | -| [opencode-notifier](https://github.com/mohak34/opencode-notifier) | إشعارات سطح المكتب وتنبيهات صوتية لأحداث الأذونات والإكمال والأخطاء | -| [opencode-zellij-namer](https://github.com/24601/opencode-zellij-namer) | تسمية جلسات Zellij تلقائيا بالاعتماد على سياق OpenCode وبمساعدة الذكاء الاصطناعي | -| [opencode-skillful](https://github.com/zenobi-us/opencode-skillful) | تمكين وكلاء OpenCode من تحميل الموجهات عند الطلب عبر اكتشاف المهارات وحقنها | -| [opencode-supermemory](https://github.com/supermemoryai/opencode-supermemory) | ذاكرة مستمرة عبر الجلسات باستخدام Supermemory | -| [@plannotator/opencode](https://github.com/backnotprop/plannotator/tree/main/apps/opencode-plugin) | مراجعة تفاعلية للخطة مع تعليقات توضيحية مرئية ومشاركة خاصة/دون اتصال | -| [@openspoon/subtask2](https://github.com/spoons-and-mirrors/subtask2) | توسيع /commands في opencode إلى نظام تنسيق قوي مع تحكم دقيق في التدفق | -| [opencode-scheduler](https://github.com/different-ai/opencode-scheduler) | جدولة مهام متكررة باستخدام launchd (Mac) أو systemd (Linux) بصياغة cron | -| [micode](https://github.com/vtemian/micode) | سير عمل منظم: عصف ذهني → خطة → تنفيذ مع استمرارية الجلسة | -| [octto](https://github.com/vtemian/octto) | واجهة متصفح تفاعلية للعصف الذهني بالذكاء الاصطناعي مع نماذج متعددة الأسئلة | -| [opencode-background-agents](https://github.com/kdcokenny/opencode-background-agents) | وكلاء خلفية على نمط Claude Code مع تفويض غير متزامن واستمرارية للسياق | -| [opencode-notify](https://github.com/kdcokenny/opencode-notify) | إشعارات نظام تشغيل أصلية لـ OpenCode - اعرف متى تكتمل المهام | -| [opencode-workspace](https://github.com/kdcokenny/opencode-workspace) | حزمة تنسيق متعددة الوكلاء - 16 مكوّنا، تثبيت واحد | -| [opencode-worktree](https://github.com/kdcokenny/opencode-worktree) | git worktrees بلا تعقيد لـ OpenCode | +| الاسم | الوصف | +| -------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | +| [opencode-daytona](https://github.com/daytonaio/daytona/tree/main/libs/opencode-plugin) | تشغيل جلسات OpenCode تلقائيًا في صناديق حماية Daytona معزولة مع مزامنة git ومعاينات حية | +| [opencode-helicone-session](https://github.com/H2Shami/opencode-helicone-session) | حقن ترويسات جلسة Helicone تلقائيًا لتجميع الطلبات | +| [opencode-type-inject](https://github.com/nick-vi/opencode-type-inject) | حقن أنواع TypeScript/Svelte تلقائيًا في عمليات قراءة الملفات باستخدام أدوات البحث | +| [opencode-openai-codex-auth](https://github.com/numman-ali/opencode-openai-codex-auth) | استخدام اشتراك ChatGPT Plus/Pro الخاص بك بدلاً من أرصدة API | +| [opencode-gemini-auth](https://github.com/jenslys/opencode-gemini-auth) | استخدام خطة Gemini الحالية الخاصة بك بدلاً من فوترة API | +| [opencode-antigravity-auth](https://github.com/NoeFabris/opencode-antigravity-auth) | استخدام نماذج Antigravity المجانية بدلاً من فوترة API | +| [opencode-devcontainers](https://github.com/athal7/opencode-devcontainers) | عزل devcontainer متعدد الفروع مع نسخ shallow ومنافذ معينة تلقائيًا | +| [opencode-google-antigravity-auth](https://github.com/shekohex/opencode-google-antigravity-auth) | إضافة Google Antigravity OAuth، مع دعم بحث Google، ومعالجة API أكثر قوة | +| [opencode-dynamic-context-pruning](https://github.com/Tarquinen/opencode-dynamic-context-pruning) | تحسين استخدام التوكنات عن طريق تقليم مخرجات الأدوات القديمة | +| [opencode-vibeguard](https://github.com/inkdust2021/opencode-vibeguard) | تنقيح الأسرار/بيانات التعريف الشخصي (PII) إلى نصوص بديلة بأسلوب VibeGuard قبل استدعاءات LLM؛ واستعادتها محليًا | +| [opencode-websearch-cited](https://github.com/ghoulr/opencode-websearch-cited.git) | إضافة دعم بحث الويب الأصلي للموفرين المدعومين بأسلوب Google grounded | +| [opencode-pty](https://github.com/shekohex/opencode-pty.git) | تمكين وكلاء الذكاء الاصطناعي من تشغيل عمليات الخلفية في PTY، وإرسال مدخلات تفاعلية إليها. | +| [opencode-shell-strategy](https://github.com/JRedeker/opencode-shell-strategy) | تعليمات لأوامر shell غير التفاعلية - تمنع التعليق الناتج عن العمليات المعتمدة على TTY | +| [opencode-wakatime](https://github.com/angristan/opencode-wakatime) | تتبع استخدام OpenCode باستخدام Wakatime | +| [opencode-md-table-formatter](https://github.com/franlol/opencode-md-table-formatter/tree/main) | تنظيف جداول markdown التي تنتجها LLMs | +| [opencode-morph-fast-apply](https://github.com/JRedeker/opencode-morph-fast-apply) | تحرير الكود أسرع بـ 10 مرات باستخدام Morph Fast Apply API وعلامات التحرير الكسولة | +| [oh-my-opencode](https://github.com/code-yeongyu/oh-my-opencode) | وكلاء الخلفية، وأدوات LSP/AST/MCP المعدة مسبقًا، ووكلاء مختارون، متوافق مع Claude Code | +| [opencode-notificator](https://github.com/panta82/opencode-notificator) | إشعارات سطح المكتب وتنبيهات صوتية لجلسات OpenCode | +| [opencode-notifier](https://github.com/mohak34/opencode-notifier) | إشعارات سطح المكتب وتنبيهات صوتية لأحداث الإذن والاكتمال والخطأ | +| [opencode-zellij-namer](https://github.com/24601/opencode-zellij-namer) | تسمية جلسات Zellij تلقائيًا بدعم الذكاء الاصطناعي بناءً على سياق OpenCode | +| [opencode-skillful](https://github.com/zenobi-us/opencode-skillful) | السماح لوكلاء OpenCode بتحميل المطالبات (prompts) بشكل كسول عند الطلب مع اكتشاف المهارات وحقنها | +| [opencode-supermemory](https://github.com/supermemoryai/opencode-supermemory) | ذاكرة مستمرة عبر الجلسات باستخدام Supermemory | +| [@plannotator/opencode](https://github.com/backnotprop/plannotator/tree/main/apps/opencode-plugin) | مراجعة تفاعلية للخطة مع تعليقات توضيحية مرئية ومشاركة خاصة/بدون اتصال | +| [@openspoon/subtask2](https://github.com/spoons-and-mirrors/subtask2) | توسيع opencode /commands إلى نظام تنسيق قوي مع تحكم دقيق في التدفق | +| [opencode-scheduler](https://github.com/different-ai/opencode-scheduler) | جدولة الوظائف المتكررة باستخدام launchd (Mac) أو systemd (Linux) بصيغة cron | +| [micode](https://github.com/vtemian/micode) | سير عمل منظم: عصف ذهني ← تخطيط ← تنفيذ مع استمرارية الجلسة | +| [octto](https://github.com/vtemian/octto) | واجهة مستخدم تفاعلية للمتصفح للعصف الذهني بالذكاء الاصطناعي مع نماذج متعددة الأسئلة | +| [opencode-background-agents](https://github.com/kdcokenny/opencode-background-agents) | وكلاء خلفية بأسلوب Claude Code مع تفويض غير متزامن واستمرارية السياق | +| [opencode-notify](https://github.com/kdcokenny/opencode-notify) | إشعارات نظام التشغيل الأصلية لـ OpenCode – اعرف متى تكتمل المهام | +| [opencode-workspace](https://github.com/kdcokenny/opencode-workspace) | حزمة تنسيق متعددة الوكلاء – 16 مكونًا، تثبيت واحد | +| [opencode-worktree](https://github.com/kdcokenny/opencode-worktree) | أشجار عمل git (worktrees) خالية من الاحتكاك لـ OpenCode | +| [opencode-sentry-monitor](https://github.com/stolinski/opencode-sentry-monitor) | تتبع وتصحيح أخطاء وكلاء الذكاء الاصطناعي باستخدام Sentry AI Monitoring | --- ## المشاريع -| الاسم | الوصف | -| ------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------ | -| [kimaki](https://github.com/remorses/kimaki) | بوت Discord للتحكم بجلسات OpenCode، مبني على SDK | -| [opencode.nvim](https://github.com/NickvanDyke/opencode.nvim) | ملحق Neovim لموجهات تراعي المحرر، مبني على API | -| [portal](https://github.com/hosenur/portal) | واجهة ويب تركز على الجوال لـ OpenCode عبر Tailscale/VPN | -| [opencode plugin template](https://github.com/zenobi-us/opencode-plugin-template/) | قالب لبناء ملحقات OpenCode | -| [opencode.nvim](https://github.com/sudo-tee/opencode.nvim) | واجهة Neovim لـ opencode - وكيل برمجة بالذكاء الاصطناعي يعمل في terminal | -| [ai-sdk-provider-opencode-sdk](https://github.com/ben-vargas/ai-sdk-provider-opencode-sdk) | موفر Vercel AI SDK لاستخدام OpenCode عبر @opencode-ai/sdk | -| [OpenChamber](https://github.com/btriapitsyn/openchamber) | تطبيق ويب/سطح مكتب وامتداد VS Code لـ OpenCode | -| [OpenCode-Obsidian](https://github.com/mtymek/opencode-obsidian) | ملحق Obsidian يدمج OpenCode داخل واجهة Obsidian | -| [OpenWork](https://github.com/different-ai/openwork) | بديل مفتوح المصدر لـ Claude Cowork، مدعوم بـ OpenCode | -| [ocx](https://github.com/kdcokenny/ocx) | مدير امتدادات OpenCode مع ملفات تعريف محمولة ومعزولة. | -| [CodeNomad](https://github.com/NeuralNomadsAI/CodeNomad) | تطبيق عميل لسطح المكتب والويب والجوال وعن بُعد لـ OpenCode | +| الاسم | الوصف | +| ------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------- | +| [kimaki](https://github.com/remorses/kimaki) | بوت Discord للتحكم في جلسات OpenCode، مبني على SDK | +| [opencode.nvim](https://github.com/NickvanDyke/opencode.nvim) | إضافة Neovim للمطالبات المدركة للمحرر، مبنية على API | +| [portal](https://github.com/hosenur/portal) | واجهة ويب مخصصة للجوال لـ OpenCode عبر Tailscale/VPN | +| [opencode plugin template](https://github.com/zenobi-us/opencode-plugin-template/) | قالب لبناء إضافات OpenCode | +| [opencode.nvim](https://github.com/sudo-tee/opencode.nvim) | واجهة Neovim لـ opencode - وكيل برمجة بالذكاء الاصطناعي يعتمد على الطرفية | +| [ai-sdk-provider-opencode-sdk](https://github.com/ben-vargas/ai-sdk-provider-opencode-sdk) | موفر Vercel AI SDK لاستخدام OpenCode عبر @opencode-ai/sdk | +| [OpenChamber](https://github.com/btriapitsyn/openchamber) | تطبيق ويب / سطح مكتب وامتداد VS Code لـ OpenCode | +| [OpenCode-Obsidian](https://github.com/mtymek/opencode-obsidian) | إضافة Obsidian تدمج OpenCode في واجهة مستخدم Obsidian | +| [OpenWork](https://github.com/different-ai/openwork) | بديل مفتوح المصدر لـ Claude Cowork، مدعوم بواسطة OpenCode | +| [ocx](https://github.com/kdcokenny/ocx) | مدير امتدادات OpenCode مع ملفات تعريف محمولة ومعزولة. | +| [CodeNomad](https://github.com/NeuralNomadsAI/CodeNomad) | تطبيق عميل لسطح المكتب والويب والجوال وعن بعد لـ OpenCode | --- ## الوكلاء -| الاسم | الوصف | -| ----------------------------------------------------------------- | --------------------------------------------- | -| [Agentic](https://github.com/Cluster444/agentic) | وكلاء وأوامر ذكاء اصطناعي معيارية لتطوير منظم | -| [opencode-agents](https://github.com/darrenhinde/opencode-agents) | إعدادات وموجهات ووكلاء وملحقات لسير عمل محسّن | +| الاسم | الوصف | +| ----------------------------------------------------------------- | ------------------------------------------------ | +| [Agentic](https://github.com/Cluster444/agentic) | وكلاء ذكاء اصطناعي وأوامر معيارية للتطوير المنظم | +| [opencode-agents](https://github.com/darrenhinde/opencode-agents) | تكوينات، ومطالبات، ووكلاء، وإضافات لسير عمل محسن | diff --git a/packages/web/src/content/docs/ar/go.mdx b/packages/web/src/content/docs/ar/go.mdx new file mode 100644 index 0000000000..76dbecbd33 --- /dev/null +++ b/packages/web/src/content/docs/ar/go.mdx @@ -0,0 +1,145 @@ +--- +title: Go +description: اشتراك منخفض التكلفة لنماذج البرمجة المفتوحة. +--- + +import config from "../../../../config.mjs" +export const console = config.console +export const email = `mailto:${config.email}` + +OpenCode Go هو اشتراك منخفض التكلفة بقيمة **10 دولارات شهرياً** يمنحك وصولاً موثوقاً إلى نماذج البرمجة المفتوحة الشائعة. + +:::note +OpenCode Go حالياً في مرحلة تجريبية (beta). +::: + +يعمل Go مثل أي مزود آخر في OpenCode. تشترك في OpenCode Go وتحصل على مفتاح API الخاص بك. إنه **اختياري تماماً** ولا تحتاج إلى استخدامه لاستخدام OpenCode. + +صُمم بشكل أساسي للمستخدمين الدوليين، مع استضافة النماذج في الولايات المتحدة والاتحاد الأوروبي وسنغافورة لضمان وصول عالمي مستقر. + +--- + +## الخلفية (Background) + +أصبحت النماذج المفتوحة جيدة حقاً. فهي تصل الآن إلى أداء قريب من النماذج المملوكة لمهام البرمجة. ولأن العديد من المزودين يمكنهم تقديمها بشكل تنافسي، فهي عادة ما تكون أرخص بكثير. + +ومع ذلك، فإن الحصول على وصول موثوق ومنخفض الكمون (low latency) إليها قد يكون صعباً. يختلف المزودون في الجودة والتوافر. + +:::tip +قمنا باختبار مجموعة مختارة من النماذج والمزودين الذين يعملون بشكل جيد مع OpenCode. +::: + +لإصلاح ذلك، قمنا ببعض الأشياء: + +1. اختبرنا مجموعة مختارة من النماذج المفتوحة وتحدثنا مع فرقهم حول أفضل طريقة لتشغيلها. +2. عملنا بعد ذلك مع عدد قليل من المزودين للتأكد من تقديمها بشكل صحيح. +3. أخيراً، قمنا بقياس أداء (benchmark) مزيج النموذج/المزود وتوصلنا إلى قائمة نشعر بالراحة في التوصية بها. + +يمنحك OpenCode Go الوصول إلى هذه النماذج مقابل **10 دولارات شهرياً**. + +--- + +## كيف يعمل (How it works) + +يعمل OpenCode Go مثل أي مزود آخر في OpenCode. + +1. قم بتسجيل الدخول إلى **<a href={console}>OpenCode Zen</a>**، واشترك في Go، وانسخ مفتاح API الخاص بك. +2. قم بتشغيل الأمر `/connect` في واجهة TUI، وحدد `OpenCode Go`، والصق مفتاح API الخاص بك. +3. قم بتشغيل `/models` في واجهة TUI لرؤية قائمة النماذج المتاحة من خلال Go. + +:::note +يمكن لعضو واحد فقط لكل مساحة عمل (workspace) الاشتراك في OpenCode Go. +::: + +تتضمن القائمة الحالية للنماذج: + +- **GLM-5** +- **Kimi K2.5** +- **MiniMax M2.5** + +قد تتغير قائمة النماذج ونحن نختبر ونضيف نماذج جديدة. + +--- + +## حدود الاستخدام (Usage limits) + +يتضمن OpenCode Go الحدود التالية: + +- **حد 5 ساعات** — 12 دولاراً من الاستخدام +- **حد أسبوعي** — 30 دولاراً من الاستخدام +- **حد شهري** — 60 دولاراً من الاستخدام + +يتم تعريف الحدود بقيمة الدولار. هذا يعني أن عدد طلباتك الفعلي يعتمد على النموذج الذي تستخدمه. تسمح النماذج الأرخص مثل MiniMax M2.5 بمزيد من الطلبات، بينما تسمح النماذج الأعلى تكلفة مثل GLM-5 بعدد أقل. + +يوفر الجدول أدناه عدداً تقديرياً للطلبات بناءً على أنماط استخدام Go النموذجية: + +| | GLM-5 | Kimi K2.5 | MiniMax M2.5 | +| ---------------- | ----- | --------- | ------------ | +| طلبات كل 5 ساعات | 1,150 | 1,850 | 30,000 | +| طلبات أسبوعياً | 2,880 | 4,630 | 75,000 | +| طلبات شهرياً | 5,750 | 9,250 | 150,000 | + +تعتمد التقديرات على أنماط الطلبات المتوسطة الملحوظة: + +- GLM-5 — 700 input, 52,000 cached, 150 output tokens per request +- Kimi K2.5 — 870 input, 55,000 cached, 200 output tokens per request +- MiniMax M2.5 — 300 input, 55,000 cached, 125 output tokens per request + +يمكنك تتبع استخدامك الحالي في **<a href={console}>console</a>**. + +:::tip +إذا وصلت إلى حد الاستخدام، يمكنك الاستمرار في استخدام النماذج المجانية. +::: + +قد تتغير حدود الاستخدام ونحن نتعلم من الاستخدام المبكر والملاحظات. + +--- + +### التسعير (Pricing) + +OpenCode Go هي خطة اشتراك بقيمة **10 دولارات شهرياً**. أدناه الأسعار **لكل 1 مليون رمز (token)**. + +| Model | Input | Output | Cached Read | +| ------------ | ----- | ------ | ----------- | +| GLM-5 | $1.00 | $3.20 | $0.20 | +| Kimi K2.5 | $0.60 | $3.00 | $0.10 | +| MiniMax M2.5 | $0.30 | $1.20 | $0.03 | + +--- + +### الاستخدام خارج الحدود (Usage beyond limits) + +إذا كان لديك أيضاً أرصدة في رصيد Zen الخاص بك، يمكنك تمكين خيار **Use balance** في الـ console. عند التمكين، سيعود Go لاستخدام رصيد Zen الخاص بك بعد وصولك إلى حدود الاستخدام بدلاً من حظر الطلبات. + +--- + +## نقاط النهاية (Endpoints) + +يمكنك أيضاً الوصول إلى نماذج Go من خلال نقاط نهاية API التالية. + +| Model | Model ID | Endpoint | AI SDK Package | +| ------------ | ------------ | ------------------------------------------------ | --------------------------- | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | + +يستخدم [model id](/docs/config/#models) في تكوين OpenCode الخاص بك التنسيق `opencode-go/<model-id>`. على سبيل المثال، بالنسبة لـ Kimi K2.5، ستستخدم `opencode-go/kimi-k2.5` في التكوين الخاص بك. + +--- + +## الخصوصية (Privacy) + +تم تصميم الخطة بشكل أساسي للمستخدمين الدوليين، مع استضافة النماذج في الولايات المتحدة والاتحاد الأوروبي وسنغافورة لضمان وصول عالمي مستقر. + +<a href={email}>تواصل معنا</a> إذا كان لديك أي أسئلة. + +--- + +## الأهداف (Goals) + +أنشأنا OpenCode Go لـ: + +1. جعل برمجة الذكاء الاصطناعي **في المتناول** لمزيد من الناس باشتراك منخفض التكلفة. +2. توفير وصول **موثوق** لأفضل نماذج البرمجة المفتوحة. +3. انتقاء نماذج **مختبرة وتم قياس أدائها** لاستخدام وكيل البرمجة. +4. عدم وجود **قيود (lock-in)** من خلال السماح لك باستخدام أي مزود آخر مع OpenCode أيضاً. diff --git a/packages/web/src/content/docs/ar/keybinds.mdx b/packages/web/src/content/docs/ar/keybinds.mdx index f07eaed37b..986313a5b5 100644 --- a/packages/web/src/content/docs/ar/keybinds.mdx +++ b/packages/web/src/content/docs/ar/keybinds.mdx @@ -28,6 +28,7 @@ description: خصّص اختصارات لوحة المفاتيح. "session_unshare": "none", "session_interrupt": "escape", "session_compact": "<leader>c", + "session_child_first": "<leader>down", "session_child_cycle": "<leader>right", "session_child_cycle_reverse": "<leader>left", "session_parent": "<leader>up", diff --git a/packages/web/src/content/docs/ar/lsp.mdx b/packages/web/src/content/docs/ar/lsp.mdx index 541b48ecc9..fd1b455340 100644 --- a/packages/web/src/content/docs/ar/lsp.mdx +++ b/packages/web/src/content/docs/ar/lsp.mdx @@ -182,7 +182,7 @@ description: يتكامل OpenCode مع خوادم LSP لديك. يوفر PHP Intelephense ميزات مدفوعة عبر مفتاح ترخيص. يمكنك تزويده بمفتاح الترخيص عبر وضع (فقط) المفتاح داخل ملف نصي في: -- على macOS/Linux: `$HOME/intelephense/licence.txt` -- على Windows: `%USERPROFILE%/intelephense/licence.txt` +- على macOS/Linux: `$HOME/intelephense/license.txt` +- على Windows: `%USERPROFILE%/intelephense/license.txt` يجب أن يحتوي الملف على مفتاح الترخيص فقط دون أي محتوى إضافي. diff --git a/packages/web/src/content/docs/ar/providers.mdx b/packages/web/src/content/docs/ar/providers.mdx index 1d448986f3..f5dd70125f 100644 --- a/packages/web/src/content/docs/ar/providers.mdx +++ b/packages/web/src/content/docs/ar/providers.mdx @@ -83,6 +83,37 @@ OpenCode Zen هي قائمة نماذج يوفّرها فريق OpenCode وقد --- +## OpenCode Go + +OpenCode Go هي خطة اشتراك منخفضة التكلفة توفّر وصولا موثوقا إلى نماذج البرمجة المفتوحة الشهيرة المقدّمة من فريق OpenCode، والتي تم اختبارها والتحقق من أنها تعمل بشكل جيد مع OpenCode. + +1. شغّل الأمر `/connect` في TUI، واختر `OpenCode Go`، ثم انتقل إلى [opencode.ai/auth](https://opencode.ai/zen). + + ```txt + /connect + ``` + +2. سجّل الدخول، وأضف تفاصيل الفوترة، ثم انسخ مفتاح API الخاص بك. + +3. الصق مفتاح API. + + ```txt + ┌ API key + │ + │ + └ enter + ``` + +4. شغّل `/models` في TUI لعرض قائمة النماذج التي نوصي بها. + + ```txt + /models + ``` + +يعمل مثل أي مزوّد آخر في OpenCode واستخدامه اختياري بالكامل. + +--- + ## الدليل لنلقِ نظرة على بعض المزوّدات بالتفصيل. إذا رغبت في إضافة مزوّد إلى القائمة، @@ -1476,6 +1507,39 @@ OpenCode Zen هي قائمة من النماذج التي تم اختبارها --- +### STACKIT + +توفّر خدمة STACKIT AI Model Serving بيئة استضافة سيادية مُدارة بالكامل لنماذج الذكاء الاصطناعي، مع التركيز على نماذج LLM مثل Llama وMistral وQwen، مع أقصى درجات سيادة البيانات على بنية تحتية أوروبية. + +1. توجّه إلى [STACKIT Portal](https://portal.stackit.cloud)، وانتقل إلى **AI Model Serving**، وأنشئ رمز مصادقة (auth token) لمشروعك. + + :::tip + تحتاج إلى حساب عميل STACKIT وحساب مستخدم ومشروع قبل إنشاء رموز المصادقة. + ::: + +2. شغّل الأمر `/connect` وابحث عن **STACKIT**. + + ```txt + /connect + ``` + +3. أدخل رمز مصادقة STACKIT AI Model Serving. + + ```txt + ┌ API key + │ + │ + └ enter + ``` + +4. شغّل الأمر `/models` للاختيار من النماذج المتاحة مثل _Qwen3-VL 235B_ أو _Llama 3.3 70B_. + + ```txt + /models + ``` + +--- + ### OVHcloud AI Endpoints 1. توجّه إلى [OVHcloud panel](https://ovh.com/manager). انتقل إلى قسم `Public Cloud`، ثم `AI & Machine Learning` > `AI Endpoints`، وفي تبويب `API Keys` انقر **Create a new API key**. diff --git a/packages/web/src/content/docs/ar/sdk.mdx b/packages/web/src/content/docs/ar/sdk.mdx index 83cdcad764..bae101acf0 100644 --- a/packages/web/src/content/docs/ar/sdk.mdx +++ b/packages/web/src/content/docs/ar/sdk.mdx @@ -117,6 +117,78 @@ try { --- +## المخرجات المنظمة + +يمكنك طلب مخرجات JSON منظمة من النموذج عن طريق تحديد `format` مع مخطط JSON. سيستخدم النموذج أداة `StructuredOutput` لإرجاع JSON تم التحقق من صحته ومطابق للمخطط الخاص بك. + +### الاستخدام الأساسي + +```typescript +const result = await client.session.prompt({ + path: { id: sessionId }, + body: { + parts: [{ type: "text", text: "Research Anthropic and provide company info" }], + format: { + type: "json_schema", + schema: { + type: "object", + properties: { + company: { type: "string", description: "Company name" }, + founded: { type: "number", description: "Year founded" }, + products: { + type: "array", + items: { type: "string" }, + description: "Main products", + }, + }, + required: ["company", "founded"], + }, + }, + }, +}) + +// Access the structured output +console.log(result.data.info.structured_output) +// { company: "Anthropic", founded: 2021, products: ["Claude", "Claude API"] } +``` + +### أنواع صيغ الإخراج + +| النوع | الوصف | +| ------------- | -------------------------------------------------- | +| `text` | الافتراضي. استجابة نصية قياسية (بدون مخرجات منظمة) | +| `json_schema` | يرجع JSON تم التحقق من صحته ومطابق للمخطط المقدم | + +### صيغة مخطط JSON + +عند استخدام `type: 'json_schema'`، يجب تقديم: + +| الحقل | النوع | الوصف | +| ------------ | --------------- | ------------------------------------------------ | +| `type` | `'json_schema'` | مطلوب. يحدد وضع مخطط JSON | +| `schema` | `object` | مطلوب. كائن مخطط JSON الذي يحدد بنية الإخراج | +| `retryCount` | `number` | اختياري. عدد محاولات إعادة التحقق (الافتراضي: 2) | + +### معالجة الأخطاء + +إذا فشل النموذج في إنتاج مخرجات منظمة صالحة بعد جميع المحاولات، ستتضمن الاستجابة `StructuredOutputError`: + +```typescript +if (result.data.info.error?.name === "StructuredOutputError") { + console.error("Failed to produce structured output:", result.data.info.error.message) + console.error("Attempts:", result.data.info.error.retries) +} +``` + +### أفضل الممارسات + +1. **قدّم أوصافا واضحة** في خصائص المخطط لمساعدة النموذج على فهم البيانات التي يجب استخراجها +2. **استخدم `required`** لتحديد الحقول التي يجب أن تكون موجودة +3. **حافظ على تركيز المخططات** - المخططات المتداخلة المعقدة قد تكون أصعب على النموذج لملئها بشكل صحيح +4. **عيّن `retryCount` مناسبا** - قم بزيادته للمخططات المعقدة، وتقليله للمخططات البسيطة + +--- + ## APIs توفر SDK جميع واجهات الخادم عبر عميل آمن للأنواع. @@ -226,27 +298,27 @@ const { providers, default: defaults } = await client.config.providers() ### الجلسات (`session`) -| الطريقة | الوصف | ملاحظات | -| ---------------------------------------------------------- | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | -| `session.list()` | سرد الجلسات | يعيد <a href={typesUrl}><code>Session[]</code></a> | -| `session.get({ path })` | جلب جلسة | يعيد <a href={typesUrl}><code>Session</code></a> | -| `session.children({ path })` | سرد الجلسات الفرعية | يعيد <a href={typesUrl}><code>Session[]</code></a> | -| `session.create({ body })` | إنشاء جلسة | يعيد <a href={typesUrl}><code>Session</code></a> | -| `session.delete({ path })` | حذف جلسة | يعيد `boolean` | -| `session.update({ path, body })` | تحديث خصائص الجلسة | يعيد <a href={typesUrl}><code>Session</code></a> | -| `session.init({ path, body })` | تحليل التطبيق وإنشاء `AGENTS.md` | يعيد `boolean` | -| `session.abort({ path })` | إيقاف جلسة قيد التشغيل | يعيد `boolean` | -| `session.share({ path })` | مشاركة جلسة | يعيد <a href={typesUrl}><code>Session</code></a> | -| `session.unshare({ path })` | إلغاء مشاركة جلسة | يعيد <a href={typesUrl}><code>Session</code></a> | -| `session.summarize({ path, body })` | تلخيص جلسة | يعيد `boolean` | -| `session.messages({ path })` | سرد الرسائل في جلسة | يعيد `{ info: `<a href={typesUrl}><code>Message</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}[]` | -| `session.message({ path })` | جلب تفاصيل الرسالة | يعيد `{ info: `<a href={typesUrl}><code>Message</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}` | -| `session.prompt({ path, body })` | إرسال رسالة مطالبة | `body.noReply: true` يعيد UserMessage (للسياق فقط). الافتراضي يعيد <a href={typesUrl}><code>AssistantMessage</code></a> مع استجابة AI | -| `session.command({ path, body })` | إرسال أمر إلى الجلسة | يعيد `{ info: `<a href={typesUrl}><code>AssistantMessage</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}` | -| `session.shell({ path, body })` | تشغيل أمر shell | يعيد <a href={typesUrl}><code>AssistantMessage</code></a> | -| `session.revert({ path, body })` | التراجع عن رسالة | يعيد <a href={typesUrl}><code>Session</code></a> | -| `session.unrevert({ path })` | استعادة الرسائل المتراجع عنها | يعيد <a href={typesUrl}><code>Session</code></a> | -| `postSessionByIdPermissionsByPermissionId({ path, body })` | الاستجابة لطلب إذن | يعيد `boolean` | +| الطريقة | الوصف | ملاحظات | +| ---------------------------------------------------------- | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `session.list()` | سرد الجلسات | يعيد <a href={typesUrl}><code>Session[]</code></a> | +| `session.get({ path })` | جلب جلسة | يعيد <a href={typesUrl}><code>Session</code></a> | +| `session.children({ path })` | سرد الجلسات الفرعية | يعيد <a href={typesUrl}><code>Session[]</code></a> | +| `session.create({ body })` | إنشاء جلسة | يعيد <a href={typesUrl}><code>Session</code></a> | +| `session.delete({ path })` | حذف جلسة | يعيد `boolean` | +| `session.update({ path, body })` | تحديث خصائص الجلسة | يعيد <a href={typesUrl}><code>Session</code></a> | +| `session.init({ path, body })` | تحليل التطبيق وإنشاء `AGENTS.md` | يعيد `boolean` | +| `session.abort({ path })` | إيقاف جلسة قيد التشغيل | يعيد `boolean` | +| `session.share({ path })` | مشاركة جلسة | يعيد <a href={typesUrl}><code>Session</code></a> | +| `session.unshare({ path })` | إلغاء مشاركة جلسة | يعيد <a href={typesUrl}><code>Session</code></a> | +| `session.summarize({ path, body })` | تلخيص جلسة | يعيد `boolean` | +| `session.messages({ path })` | سرد الرسائل في جلسة | يعيد `{ info: `<a href={typesUrl}><code>Message</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}[]` | +| `session.message({ path })` | جلب تفاصيل الرسالة | يعيد `{ info: `<a href={typesUrl}><code>Message</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}` | +| `session.prompt({ path, body })` | إرسال رسالة مطالبة | `body.noReply: true` يعيد UserMessage (للسياق فقط). الافتراضي يعيد <a href={typesUrl}><code>AssistantMessage</code></a> مع استجابة AI. يدعم `body.outputFormat` من أجل [المخرجات المنظمة](#المخرجات-المنظمة) | +| `session.command({ path, body })` | إرسال أمر إلى الجلسة | يعيد `{ info: `<a href={typesUrl}><code>AssistantMessage</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}` | +| `session.shell({ path, body })` | تشغيل أمر shell | يعيد <a href={typesUrl}><code>AssistantMessage</code></a> | +| `session.revert({ path, body })` | التراجع عن رسالة | يعيد <a href={typesUrl}><code>Session</code></a> | +| `session.unrevert({ path })` | استعادة الرسائل المتراجع عنها | يعيد <a href={typesUrl}><code>Session</code></a> | +| `postSessionByIdPermissionsByPermissionId({ path, body })` | الاستجابة لطلب إذن | يعيد `boolean` | --- diff --git a/packages/web/src/content/docs/ar/share.mdx b/packages/web/src/content/docs/ar/share.mdx index 535d44dadf..6d13410458 100644 --- a/packages/web/src/content/docs/ar/share.mdx +++ b/packages/web/src/content/docs/ar/share.mdx @@ -41,7 +41,7 @@ description: شارك محادثات OpenCode الخاصة بك. ```json title="opencode.json" { - "$schema": "https://opncd.ai/config.json", + "$schema": "https://opencode.ai/config.json", "share": "manual" } ``` @@ -54,7 +54,7 @@ description: شارك محادثات OpenCode الخاصة بك. ```json title="opencode.json" { - "$schema": "https://opncd.ai/config.json", + "$schema": "https://opencode.ai/config.json", "share": "auto" } ``` @@ -69,7 +69,7 @@ description: شارك محادثات OpenCode الخاصة بك. ```json title="opencode.json" { - "$schema": "https://opncd.ai/config.json", + "$schema": "https://opencode.ai/config.json", "share": "disabled" } ``` diff --git a/packages/web/src/content/docs/ar/tui.mdx b/packages/web/src/content/docs/ar/tui.mdx index 149f290939..bef6fda3fa 100644 --- a/packages/web/src/content/docs/ar/tui.mdx +++ b/packages/web/src/content/docs/ar/tui.mdx @@ -370,6 +370,9 @@ How is auth handled in @packages/functions/src/api/index.ts? - `scroll_acceleration` - فعّل تسارع التمرير على نمط macOS لتمرير سلس وطبيعي. عند تفعيله، تزداد سرعة التمرير مع إيماءات التمرير السريعة وتبقى دقيقة للحركات الأبطأ. **يتقدّم هذا الإعداد على `scroll_speed` ويستبدله عند تفعيله.** - `scroll_speed` - يتحكم في سرعة تمرير واجهة TUI عند استخدام أوامر التمرير (الحد الأدنى: `1`). القيمة الافتراضية هي `3`. **ملاحظة: يتم تجاهل هذا إذا تم ضبط `scroll_acceleration.enabled` على `true`.** +- `diff_style` - يتحكم في عرض الفروقات (diff). القيمة `"auto"` تتكيف مع عرض terminal، و`"stacked"` تعرض عمودًا واحدًا دائمًا. + +استخدم `OPENCODE_TUI_CONFIG` لتحميل مسار إعدادات TUI مخصص. --- diff --git a/packages/web/src/content/docs/ar/zen.mdx b/packages/web/src/content/docs/ar/zen.mdx index f25b321a9b..e155748fbf 100644 --- a/packages/web/src/content/docs/ar/zen.mdx +++ b/packages/web/src/content/docs/ar/zen.mdx @@ -59,6 +59,8 @@ OpenCode Zen هو بوابة للذكاء الاصطناعي تتيح لك ال | النموذج | معرّف النموذج | نقطة النهاية | حزمة AI SDK | | ------------------ | ------------------ | -------------------------------------------------- | --------------------------- | +| GPT 5.4 | gpt-5.4 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| GPT 5.3 Codex | gpt-5.3-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.2 | gpt-5.2 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.2 Codex | gpt-5.2-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.1 | gpt-5.1 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | @@ -68,22 +70,24 @@ OpenCode Zen هو بوابة للذكاء الاصطناعي تتيح لك ال | GPT 5 | gpt-5 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5 Codex | gpt-5-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5 Nano | gpt-5-nano | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| Claude Opus 4.6 | claude-opus-4-6 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Opus 4.5 | claude-opus-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Opus 4.1 | claude-opus-4-1 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Sonnet 4.6 | claude-sonnet-4-6 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Sonnet 4.5 | claude-sonnet-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Sonnet 4 | claude-sonnet-4 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Haiku 4.5 | claude-haiku-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Haiku 3.5 | claude-3-5-haiku | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| Claude Opus 4.6 | claude-opus-4-6 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| Claude Opus 4.5 | claude-opus-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| Claude Opus 4.1 | claude-opus-4-1 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Gemini 3.1 Pro | gemini-3.1-pro | `https://opencode.ai/zen/v1/models/gemini-3.1-pro` | `@ai-sdk/google` | | Gemini 3 Pro | gemini-3-pro | `https://opencode.ai/zen/v1/models/gemini-3-pro` | `@ai-sdk/google` | | Gemini 3 Flash | gemini-3-flash | `https://opencode.ai/zen/v1/models/gemini-3-flash` | `@ai-sdk/google` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.5 Free | minimax-m2.5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.1 | minimax-m2.1 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.1 Free | minimax-m2.1-free | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| GLM 5 | glm-5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | GLM 4.7 | glm-4.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM 4.7 Free | glm-4.7-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | GLM 4.6 | glm-4.6 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 Free | kimi-k2.5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2 Thinking | kimi-k2-thinking | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2 | kimi-k2 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Qwen3 Coder 480B | qwen3-coder | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -111,29 +115,35 @@ https://opencode.ai/zen/v1/models | النموذج | الإدخال | الإخراج | قراءة مخزنة | كتابة مخزنة | | --------------------------------- | ------- | ------- | ----------- | ----------- | | Big Pickle | Free | Free | Free | - | -| MiniMax M2.1 Free | Free | Free | Free | - | +| MiniMax M2.5 Free | Free | Free | Free | - | +| MiniMax M2.5 | $0.30 | $1.20 | $0.06 | - | | MiniMax M2.1 | $0.30 | $1.20 | $0.10 | - | -| GLM 4.7 Free | Free | Free | Free | - | +| GLM 5 | $1.00 | $3.20 | $0.20 | - | | GLM 4.7 | $0.60 | $2.20 | $0.10 | - | | GLM 4.6 | $0.60 | $2.20 | $0.10 | - | -| Kimi K2.5 Free | Free | Free | Free | - | | Kimi K2.5 | $0.60 | $3.00 | $0.08 | - | | Kimi K2 Thinking | $0.40 | $2.50 | - | - | | Kimi K2 | $0.40 | $2.50 | - | - | | Qwen3 Coder 480B | $0.45 | $1.50 | - | - | +| Claude Opus 4.6 (≤ 200K tokens) | $5.00 | $25.00 | $0.50 | $6.25 | +| Claude Opus 4.6 (> 200K tokens) | $10.00 | $37.50 | $1.00 | $12.50 | +| Claude Opus 4.5 | $5.00 | $25.00 | $0.50 | $6.25 | +| Claude Opus 4.1 | $15.00 | $75.00 | $1.50 | $18.75 | +| Claude Sonnet 4.6 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 | +| Claude Sonnet 4.6 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 | | Claude Sonnet 4.5 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 | | Claude Sonnet 4.5 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 | | Claude Sonnet 4 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 | | Claude Sonnet 4 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 | | Claude Haiku 4.5 | $1.00 | $5.00 | $0.10 | $1.25 | | Claude Haiku 3.5 | $0.80 | $4.00 | $0.08 | $1.00 | -| Claude Opus 4.6 (≤ 200K tokens) | $5.00 | $25.00 | $0.50 | $6.25 | -| Claude Opus 4.6 (> 200K tokens) | $10.00 | $37.50 | $1.00 | $12.50 | -| Claude Opus 4.5 | $5.00 | $25.00 | $0.50 | $6.25 | -| Claude Opus 4.1 | $15.00 | $75.00 | $1.50 | $18.75 | +| Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | +| Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | | Gemini 3 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | +| GPT 5.4 | $2.50 | $15.00 | $0.25 | - | +| GPT 5.3 Codex | $1.75 | $14.00 | $0.175 | - | | GPT 5.2 | $1.75 | $14.00 | $0.175 | - | | GPT 5.2 Codex | $1.75 | $14.00 | $0.175 | - | | GPT 5.1 | $1.07 | $8.50 | $0.107 | - | @@ -152,9 +162,7 @@ https://opencode.ai/zen/v1/models النماذج المجانية: -- GLM 4.7 Free متاح على OpenCode لفترة محدودة. يستخدم الفريق هذه الفترة لجمع الملاحظات وتحسين النموذج. -- Kimi K2.5 Free متاح على OpenCode لفترة محدودة. يستخدم الفريق هذه الفترة لجمع الملاحظات وتحسين النموذج. -- MiniMax M2.1 Free متاح على OpenCode لفترة محدودة. يستخدم الفريق هذه الفترة لجمع الملاحظات وتحسين النموذج. +- MiniMax M2.5 Free متاح على OpenCode لفترة محدودة. يستخدم الفريق هذه الفترة لجمع الملاحظات وتحسين النموذج. - Big Pickle نموذج خفي ومتاح مجانا على OpenCode لفترة محدودة. يستخدم الفريق هذه الفترة لجمع الملاحظات وتحسين النموذج. <a href={email}>تواصل معنا</a> إذا كانت لديك أي أسئلة. @@ -178,14 +186,25 @@ https://opencode.ai/zen/v1/models --- +### نماذج مهملة + +| النموذج | تاريخ الإيقاف | +| ---------------- | ------------- | +| Qwen3 Coder 480B | 6 فبراير 2026 | +| Kimi K2 Thinking | 6 مارس 2026 | +| Kimi K2 | 6 مارس 2026 | +| MiniMax M2.1 | 15 مارس 2026 | +| GLM 4.7 | 15 مارس 2026 | +| GLM 4.6 | 15 مارس 2026 | + +--- + ## الخصوصية تتم استضافة جميع نماذجنا في الولايات المتحدة. يلتزم مزوّدونا بسياسة عدم الاحتفاظ بالبيانات (zero-retention) ولا يستخدمون بياناتك لتدريب النماذج، مع الاستثناءات التالية: - Big Pickle: خلال فترة إتاحته المجانية، قد تُستخدم البيانات المجمعة لتحسين النموذج. -- GLM 4.7 Free: خلال فترة إتاحته المجانية، قد تُستخدم البيانات المجمعة لتحسين النموذج. -- Kimi K2.5 Free: خلال فترة إتاحته المجانية، قد تُستخدم البيانات المجمعة لتحسين النموذج. -- MiniMax M2.1 Free: خلال فترة إتاحته المجانية، قد تُستخدم البيانات المجمعة لتحسين النموذج. +- MiniMax M2.5 Free: خلال فترة إتاحته المجانية، قد تُستخدم البيانات المجمعة لتحسين النموذج. - OpenAI APIs: يتم الاحتفاظ بالطلبات لمدة 30 يوما وفقا لـ [سياسات بيانات OpenAI](https://platform.openai.com/docs/guides/your-data). - Anthropic APIs: يتم الاحتفاظ بالطلبات لمدة 30 يوما وفقا لـ [سياسات بيانات Anthropic](https://docs.anthropic.com/en/docs/claude-code/data-usage). diff --git a/packages/web/src/content/docs/bs/cli.mdx b/packages/web/src/content/docs/bs/cli.mdx index 049b43497f..7fc594e6c3 100644 --- a/packages/web/src/content/docs/bs/cli.mdx +++ b/packages/web/src/content/docs/bs/cli.mdx @@ -555,6 +555,7 @@ OpenCode se može konfigurirati pomoću varijabli okruženja. | `OPENCODE_AUTO_SHARE` | boolean | Automatski dijeli sesije | | `OPENCODE_GIT_BASH_PATH` | string | Putanja do Git Bash izvršne datoteke na Windows-u | | `OPENCODE_CONFIG` | string | Putanja do konfiguracijskog fajla | +| `OPENCODE_TUI_CONFIG` | string | Putanja do TUI konfiguracijskog fajla | | `OPENCODE_CONFIG_DIR` | string | Putanja do konfiguracijskog direktorija | | `OPENCODE_CONFIG_CONTENT` | string | Inline json konfiguracijski sadržaj | | `OPENCODE_DISABLE_AUTOUPDATE` | boolean | Onemogući automatske provjere ažuriranja | diff --git a/packages/web/src/content/docs/bs/config.mdx b/packages/web/src/content/docs/bs/config.mdx index 3e20f1890d..3183a2f92d 100644 --- a/packages/web/src/content/docs/bs/config.mdx +++ b/packages/web/src/content/docs/bs/config.mdx @@ -14,10 +14,11 @@ OpenCode podržava i **JSON** i **JSONC** (JSON sa komentarima) formate. ```jsonc title="opencode.jsonc" { "$schema": "https://opencode.ai/config.json", - // Theme configuration - "theme": "opencode", "model": "anthropic/claude-sonnet-4-5", "autoupdate": true, + "server": { + "port": 4096, + }, } ``` @@ -30,8 +31,10 @@ Možete postaviti svoju konfiguraciju na nekoliko različitih lokacija i one ima :::note Konfiguracijski fajlovi se **spajaju**, ne zamjenjuju. ::: + Konfiguracijski fajlovi se spajaju, ne zamjenjuju. Kombiniraju se postavke sa sljedećih konfiguracijskih lokacija. Kasnije konfiguracije poništavaju prethodne samo za konfliktne ključeve. Nekonfliktne postavke iz svih konfiguracija su sačuvane. -Na primjer, ako vaša globalna konfiguracija postavlja `theme: "opencode"` i `autoupdate: true`, a vaša projektna konfiguracija postavlja `model: "anthropic/claude-sonnet-4-5"`, konačna konfiguracija će uključivati ​​sve tri postavke. + +Na primjer, ako vaša globalna konfiguracija postavlja `autoupdate: true`, a vaša projektna konfiguracija postavlja `model: "anthropic/claude-sonnet-4-5"`, konačna konfiguracija će uključivati ​​obje postavke. --- @@ -40,23 +43,26 @@ Na primjer, ako vaša globalna konfiguracija postavlja `theme: "opencode"` i `au Izvori konfiguracije se učitavaju ovim redoslijedom (kasniji izvori poništavaju ranije): 1. **Udaljena konfiguracija** (od `.well-known/opencode`) - organizacijske postavke -2. **Globalna konfiguracija** (`~/.config/opencode/opencode.json`) - korisničke postavke +2. **Globalna konfiguracija** (`~/.config/opencode/opencode.json`) - korisničke preferencije 3. **Prilagođena konfiguracija** (`OPENCODE_CONFIG` env var) - prilagođena preinačenja 4. **Konfiguracija projekta** (`opencode.json` u projektu) - postavke specifične za projekat 5. **`.opencode` direktoriji** - agenti, komande, dodaci 6. **Inline konfiguracija** (`OPENCODE_CONFIG_CONTENT` env var) - runtime preinačenja - To znači da konfiguracije projekta mogu nadjačati globalne zadane postavke, a globalne konfiguracije mogu nadjačati postavke udaljene organizacije. - :::note - Direktoriji `.opencode` i `~/.config/opencode` koriste **imena u množini** za poddirektorije: `agents/`, `commands/`, `modes/`, `plugins/`, `skills/`, `tools/` i `themes/`. Pojedinačna imena (npr. `agent/`) su također podržana za kompatibilnost unatrag. - ::: +To znači da konfiguracije projekta mogu nadjačati globalne zadane postavke, a globalne konfiguracije mogu nadjačati postavke udaljene organizacije. + +:::note +Direktoriji `.opencode` i `~/.config/opencode` koriste **imena u množini** za poddirektorije: `agents/`, `commands/`, `modes/`, `plugins/`, `skills/`, `tools/` i `themes/`. Pojedinačna imena (npr. `agent/`) su također podržana za kompatibilnost unatrag. +::: --- ### Udaljeno (Remote) Organizacije mogu pružiti zadanu konfiguraciju preko `.well-known/opencode` krajnje tačke. Ovo se automatski preuzima kada se autentifikujete kod provajdera koji to podržava. + Prvo se učitava udaljena konfiguracija koja služi kao osnovni sloj. Svi ostali izvori konfiguracije (globalni, projektni) mogu nadjačati ove zadane postavke. + Na primjer, ako vaša organizacija nudi MCP servere koji su po defaultu onemogućeni: ```json title="Remote config from .well-known/opencode" @@ -89,7 +95,10 @@ Možete omogućiti određene servere u vašoj lokalnoj konfiguraciji: ### Globalno -Postavite svoju globalnu OpenCode konfiguraciju u `~/.config/opencode/opencode.json`. Koristite globalnu konfiguraciju za korisničke preferencije kao što su teme, provajderi ili veze tipki. +Postavite svoju globalnu OpenCode konfiguraciju u `~/.config/opencode/opencode.json`. Koristite globalnu konfiguraciju za korisničke preferencije kao što su provajderi, modeli i dozvole. + +Za postavke specifične za TUI, koristite `~/.config/opencode/tui.json`. + Globalna konfiguracija poništava zadane postavke udaljene organizacije. --- @@ -97,10 +106,15 @@ Globalna konfiguracija poništava zadane postavke udaljene organizacije. ### Projekt Dodajte `opencode.json` u korijen projekta. Konfiguracija projekta ima najveći prioritet među standardnim konfiguracijskim datotekama - ona nadjačava globalne i udaljene konfiguracije. + +Za TUI postavke specifične za projekat, dodajte `tui.json` pored njega. + :::tip Postavite specifičnu konfiguraciju projekta u korijen vašeg projekta. ::: + Kada se OpenCode pokrene, traži konfiguracijsku datoteku u trenutnom direktoriju ili prelazi do najbližeg Git direktorija. + Ovo je također sigurno provjeriti u Git i koristi istu shemu kao globalna. --- @@ -134,33 +148,33 @@ Prilagođeni direktorij se učitava nakon direktorija globalne konfiguracije i ` ## Šema Konfiguracijski fajl ima šemu koja je definirana u [**`opencode.ai/config.json`**](https://opencode.ai/config.json). + +TUI konfiguracija koristi [**`opencode.ai/tui.json`**](https://opencode.ai/tui.json). + Vaš editor bi trebao biti u mogućnosti da validira i autodovršava na osnovu šeme. --- ### TUI -Možete konfigurirati postavke specifične za TUI putem opcije `tui`. +Koristite namjenski `tui.json` (ili `tui.jsonc`) fajl za postavke specifične za TUI. -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", - "tui": { - "scroll_speed": 3, - "scroll_acceleration": { - "enabled": true - }, - "diff_style": "auto" - } + "$schema": "https://opencode.ai/tui.json", + "scroll_speed": 3, + "scroll_acceleration": { + "enabled": true + }, + "diff_style": "auto" } ``` -Dostupne opcije: +Koristite `OPENCODE_TUI_CONFIG` da pokažete na prilagođeni TUI konfiguracijski fajl. -- `scroll_acceleration.enabled` - Omogući ubrzanje skrolovanja u macOS stilu. **Ima prednost nad `scroll_speed`.** -- `scroll_speed` - Prilagođeni množitelj brzine pomicanja (podrazumevano: `3`, minimalno: `1`). Zanemareno ako je `scroll_acceleration.enabled` `true`. -- `diff_style` - Kontrola prikaza razlike. `"auto"` se prilagođava širini terminala, `"stacked"` uvijek prikazuje jednu kolonu. - [Saznajte više o korištenju TUI](/docs/tui) ovdje. +Stari `theme`, `keybinds`, i `tui` ključevi u `opencode.json` su zastarjeli i automatski će se migrirati kada je to moguće. + +[Saznajte više o korištenju TUI ovdje](/docs/tui#configure). --- @@ -188,7 +202,8 @@ Dostupne opcije: - `mdns` - Omogući mDNS otkrivanje servisa. Ovo omogućava drugim uređajima na mreži da otkriju vaš OpenCode server. - `mdnsDomain` - Prilagođeno ime domene za mDNS servis. Zadano je `opencode.local`. Korisno za pokretanje više instanci na istoj mreži. - `cors` - Dodatni origini koji omogućavaju CORS kada koristite HTTP server iz klijenta baziranog na pretraživaču. Vrijednosti moraju biti puni origin (shema + host + opcijski port), npr. `https://app.example.com`. - [Saznajte više o serveru](/docs/server) ovdje. + +[Saznajte više o serveru ovdje](/docs/server). --- @@ -206,7 +221,7 @@ Možete upravljati alatima koje LLM može koristiti putem opcije `tools`. } ``` -[Saznajte više o alatima](/docs/tools) ovdje. +[Saznajte više o alatima ovdje](/docs/tools). --- @@ -224,6 +239,7 @@ Možete konfigurirati dobavljače i modele koje želite koristiti u svojoj OpenC ``` Opcija `small_model` konfigurira poseban model za lagane zadatke poput generiranja naslova. Podrazumevano, OpenCode pokušava da koristi jeftiniji model ako je dostupan od vašeg provajdera, inače se vraća na vaš glavni model. + Opcije provajdera mogu uključivati ​​`timeout` i `setCacheKey`: ```json title="opencode.json" @@ -242,7 +258,8 @@ Opcije provajdera mogu uključivati ​​`timeout` i `setCacheKey`: - `timeout` - Vrijeme čekanja zahtjeva u milisekundama (podrazumevano: 300000). Postavite na `false` da onemogućite. - `setCacheKey` - Osigurajte da je ključ keš memorije uvijek postavljen za određenog provajdera. - Također možete konfigurirati [lokalne modele](/docs/models#local). [Saznajte više](/docs/models). + +Također možete konfigurirati [lokalne modele](/docs/models#local). [Saznajte više](/docs/models). --- @@ -272,21 +289,23 @@ Amazon Bedrock podržava konfiguraciju specifičnu za AWS: - `region` - AWS regija za Bedrock (zadano na `AWS_REGION` env var ili `us-east-1`) - `profile` - AWS imenovani profil iz `~/.aws/credentials` (zadano na `AWS_PROFILE` env var) - `endpoint` - URL prilagođene krajnje tačke za VPC krajnje tačke. Ovo je alias za generičku opciju `baseURL` koristeći terminologiju specifičnu za AWS. Ako su oba navedena, `endpoint` ima prednost. - :::note - Tokeni nosioca (`AWS_BEARER_TOKEN_BEDROCK` ili `/connect`) imaju prednost nad autentifikacijom zasnovanom na profilu. Pogledajte [prednost autentifikacije](/docs/providers#authentication-precedence) za detalje. - ::: - [Saznajte više o konfiguraciji Amazon Bedrock](/docs/providers#amazon-bedrock). + +:::note +Tokeni nosioca (`AWS_BEARER_TOKEN_BEDROCK` ili `/connect`) imaju prednost nad autentifikacijom zasnovanom na profilu. Pogledajte [prednost autentifikacije](/docs/providers#authentication-precedence) za detalje. +::: + +[Saznajte više o konfiguraciji Amazon Bedrock](/docs/providers#amazon-bedrock). --- -### Tema +### Teme -Možete konfigurirati temu koju želite koristiti u svojoj OpenCode konfiguraciji putem opcije `theme`. +Postavite vašu UI temu u `tui.json`. -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", - "theme": "" + "$schema": "https://opencode.ai/tui.json", + "theme": "tokyonight" } ``` @@ -332,6 +351,7 @@ Možete postaviti zadanog agenta koristeći opciju `default_agent`. Ovo određuj ``` Zadani agent mora biti primarni agent (ne podagent). Ovo može biti ugrađeni agent kao što je `"build"` ili `"plan"`, ili [prilagođeni agent](/docs/agents) koji ste definirali. Ako navedeni agent ne postoji ili je podagent, OpenCode će se vratiti na `"build"` s upozorenjem. + Ova postavka se primjenjuje na sva sučelja: TUI, CLI (`opencode run`), desktop aplikaciju i GitHub Action. --- @@ -352,7 +372,8 @@ Ovo prihvata: - `"manual"` - Dozvoli ručno dijeljenje putem naredbi (podrazumevano) - `"auto"` - Automatski dijelite nove razgovore - `"disabled"` - Onemogući dijeljenje u potpunosti - Podrazumevano, dijeljenje je postavljeno na ručni način rada gdje trebate eksplicitno dijeliti razgovore pomoću naredbe `/share`. + +Podrazumevano, dijeljenje je postavljeno na ručni način rada gdje trebate eksplicitno dijeliti razgovore pomoću naredbe `/share`. --- @@ -384,11 +405,11 @@ Također možete definirati naredbe koristeći markdown fajlove u `~/.config/ope ### Prečice tipki -Možete prilagoditi svoje veze tipki putem opcije `keybinds`. +Prilagodite prečice tipki u `tui.json`. -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "keybinds": {} } ``` @@ -442,6 +463,7 @@ Možete konfigurirati formatere koda putem opcije `formatter`. ### Dozvole Prema zadanim postavkama, OpenCode **dopušta sve operacije** bez potrebe za eksplicitnim dopuštenjem. Ovo možete promijeniti koristeći opciju `permission`. + Na primjer, da osigurate da alati `edit` i `bash` zahtijevaju odobrenje korisnika: ```json title="opencode.json" @@ -467,13 +489,15 @@ Možete kontrolirati ponašanje sažimanja konteksta putem opcije `compaction`. "$schema": "https://opencode.ai/config.json", "compaction": { "auto": true, - "prune": true + "prune": true, + "reserved": 10000 } } ``` - `auto` - Automatski sažimanje sesije kada je kontekst pun (podrazumevano: `true`). - `prune` - Uklonite stare izlaze alata da sačuvate tokene (podrazumevano: `true`). +- `reserved` - Token buffer za sažimanje. Ostavlja dovoljno prostora da se izbjegne prelijevanje tokom sažimanja --- @@ -512,6 +536,7 @@ Možete konfigurirati MCP servere koje želite koristiti putem opcije `mcp`. ### Dodaci [Plugins](/docs/plugins) proširuju OpenCode sa prilagođenim alatima, kukicama i integracijama. + Postavite datoteke dodataka u `.opencode/plugins/` ili `~/.config/opencode/plugins/`. Također možete učitati dodatke iz npm-a preko opcije `plugin`. ```json title="opencode.json" @@ -554,6 +579,7 @@ Možete onemogućiti dobavljače koji se automatski učitavaju preko opcije `dis :::note `disabled_providers` ima prioritet nad `enabled_providers`. ::: + Opcija `disabled_providers` prihvata niz ID-ova provajdera. Kada je provajder onemogućen: - Neće se učitati čak i ako su varijable okruženja postavljene. @@ -574,9 +600,11 @@ Možete odrediti listu dozvoljenih dobavljača putem opcije `enabled_providers`. ``` Ovo je korisno kada želite da ograničite OpenCode da koristi samo određene provajdere umjesto da ih onemogućavate jednog po jednog. + :::note `disabled_providers` ima prioritet nad `enabled_providers`. ::: + Ako se provajder pojavljuje i u `enabled_providers` i `disabled_providers`, `disabled_providers` ima prioritet za kompatibilnost unatrag. --- @@ -649,7 +677,9 @@ Putanja fajla mogu biti: - U odnosu na direktorij konfiguracijskih datoteka - Ili apsolutne staze koje počinju sa `/` ili `~` - Ovo je korisno za: + +Ovo je korisno za: + - Pohranjivanje osjetljivih podataka poput API ključeva u odvojenim datotekama. - Uključujući velike datoteke instrukcija bez zatrpavanja vaše konfiguracije. - Dijeljenje zajedničkih isječaka konfiguracije u više konfiguracijskih datoteka. diff --git a/packages/web/src/content/docs/bs/custom-tools.mdx b/packages/web/src/content/docs/bs/custom-tools.mdx index e452ce6a56..e933c7cb12 100644 --- a/packages/web/src/content/docs/bs/custom-tools.mdx +++ b/packages/web/src/content/docs/bs/custom-tools.mdx @@ -79,6 +79,32 @@ Ovo stvara dva alata: `math_add` i `math_multiply`. --- +#### Sukob imena s ugrađenim alatima + +Prilagođeni alati su prepoznati po imenu. Ako prilagođeni alat koristi isto ime kao ugrađeni alat, prilagođeni alat ima prednost. + +Na primjer, ova datoteka zamjenjuje ugrađeni `bash` alat: + +```ts title=".opencode/tools/bash.ts" +import { tool } from "@opencode-ai/plugin" + +export default tool({ + description: "Restricted bash wrapper", + args: { + command: tool.schema.string(), + }, + async execute(args) { + return `blocked: ${args.command}` + }, +}) +``` + +:::note +Preferirajte jedinstvena imena osim ako namjerno ne želite zamijeniti ugrađeni alat. Ako želite onemogućiti ugrađeni alat, ali ne i nadjačati ga, koristite [dozvole](/docs/permissions). +::: + +--- + ### Argumenti Možete koristiti `tool.schema`, što je samo [Zod](https://zod.dev), da definirate tipove argumenata. @@ -166,4 +192,4 @@ export default tool({ }) ``` -Ovdje koristimo [`Bun.$`\_](https://bun.com/docs/runtime/shell) uslužni program za pokretanje Python skripte. +Ovdje koristimo [`Bun.$`](https://bun.com/docs/runtime/shell) uslužni program za pokretanje Python skripte. diff --git a/packages/web/src/content/docs/bs/ecosystem.mdx b/packages/web/src/content/docs/bs/ecosystem.mdx index c7dea0c6e2..ff0fbc1526 100644 --- a/packages/web/src/content/docs/bs/ecosystem.mdx +++ b/packages/web/src/content/docs/bs/ecosystem.mdx @@ -4,45 +4,51 @@ description: Projekti i integracije izgrađeni uz OpenCode. --- Kolekcija projekata zajednice izgrađenih na OpenCode. + :::note Želite li na ovu listu dodati svoj OpenCode projekat? Pošaljite PR. ::: + Također možete pogledati [awesome-opencode](https://github.com/awesome-opencode/awesome-opencode) i [opencode.cafe](https://opencode.cafe), zajednicu koja spaja ekosistem i zajednicu. --- ## Dodaci -| Ime | Opis | -| --------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | --- | ------------------------------------------------------------------- | -------------------------------------------------------------------------------- | -| [opencode-daytona](https://github.com/jamesmurdza/daytona/blob/main/guides/typescript/opencode/README.md) | Automatski pokrenite OpenCode sesije u izoliranim Daytona sandboxovima uz git sinhronizaciju i preglede uživo | -| [opencode-helicone-session](https://github.com/H2Shami/opencode-helicone-session) | Automatski ubacite Helicone zaglavlja sesije za grupisanje zahtjeva | -| [opencode-type-inject](https://github.com/nick-vi/opencode-type-inject) | Automatski ubaci TypeScript/Svelte tipove u čitanje datoteka pomoću alata za pretraživanje | -| [opencode-openai-codex-auth](https://github.com/numman-ali/opencode-openai-codex-auth) | Koristite svoju ChatGPT Plus/Pro pretplatu umjesto API kredita | -| [opencode-gemini-auth](https://github.com/jenslys/opencode-gemini-auth) | Koristite svoj postojeći Gemini plan umjesto API naplate | -| [opencodentigravity-auth](https://github.com/NoeFabris/opencodentigravity-auth) | Koristite besplatne modele Antigravity umjesto API naplate | -| [opencode-devcontainers](https://github.com/athal7/opencode-devcontainers) | Izolacija devcontainer-a s više grana s plitkim klonovima i automatski dodijeljenim portovima | -| [opencode-google-antigravity-auth](https://github.com/shekohex/opencode-google-antigravity-auth) | Google Antigravity OAuth dodatak, s podrškom za Google pretraživanje i robusnijim API rukovanjem | -| [opencode-dynamic-context-pruning](https://github.com/Tarquinen/opencode-dynamic-context-pruning) | Optimizirajte korištenje tokena smanjenjem izlaza zastarjelih alata | -| [opencode-websearch-cited](https://github.com/ghoulr/opencode-websearch-cited.git) | Dodajte podršku za izvorno web pretraživanje za podržane provajdere sa stilom utemeljenim na Googleu | -| [opencode-pty](https://github.com/shekohex/opencode-pty.git) | Omogućuje AI agentima da pokreću pozadinske procese u PTY-u, šalju im interaktivni ulaz. | -| [opencode-shell-strategy](https://github.com/JRedeker/opencode-shell-strategy) | Upute za neinteraktivne naredbe ljuske - sprječava visi od TTY ovisnih operacija | | [opencode-wakatime](https://github.com/angristan/opencode-wakatime) | Pratite upotrebu OpenCode sa Wakatime | -| [opencode-md-table-formatter](https://github.com/franlol/opencode-md-table-formatter/tree/main) | Očistite tabele umanjenja vrijednosti koje su izradili LLM | -| [opencode-morph-fast-apply](https://github.com/JRedeker/opencode-morph-fast-apply) | 10x brže uređivanje koda s Morph Fast Apply API-jem i markerima za lijeno uređivanje | -| [oh-my-opencode](https://github.com/code-yeongyu/oh-my-opencode) | Pozadinski agenti, unapred izgrađeni LSP/AST/MCP alati, kurirani agenti, kompatibilni sa Claude Code | -| [opencode-notificator](https://github.com/panta82/opencode-notificator) | Obavještenja na radnoj površini i zvučna upozorenja za OpenCode sesije | -| [opencode-notifier](https://github.com/mohak34/opencode-notifier) | Obavještenja na radnoj površini i zvučna upozorenja za dozvole, završetak i događaje greške | -| [opencode-zellij-namer](https://github.com/24601/opencode-zellij-namer) | Automatsko imenovanje Zellij sesije na bazi OpenCode konteksta | -| [opencode-skillful](https://github.com/zenobi-us/opencode-skillful) | Dozvolite OpenCode agentima da lijeno učitavaju upite na zahtjev uz otkrivanje vještina i ubrizgavanje | -| [opencode-supermemory](https://github.com/supermemoryai/opencode-supermemory) | Trajna memorija kroz sesije koristeći Supermemory | -| [@plannotator/opencode](https://github.com/backnotprop/plannotator/tree/main/apps/opencode-plugin) | Interaktivni pregled plana s vizualnim napomenama i privatnim/offline dijeljenjem | -| [@openspoon/subtask2](https://github.com/spoons-and-mirrors/subtask2) | Proširite opencode /komande u moćan sistem orkestracije sa granularnom kontrolom toka | -| [opencode-scheduler](https://github.com/different-ai/opencode-scheduler) | Planirajte ponavljajuće poslove koristeći launchd (Mac) ili systemd (Linux) sa cron sintaksom | | [micode](https://github.com/vtemian/micode) | Strukturirana Brainstorm → Plan → Implementacija toka rada uz kontinuitet sesije | -| [octto](https://github.com/vtemian/octto) | Interaktivno korisničko sučelje pretraživača za AI brainstorming sa obrascima za više pitanja | -| [opencode-background-agents](https://github.com/kdcokenny/opencode-background-agents) | Pozadinski agenti u stilu Claudea s asinhroniziranim delegiranjem i postojanošću konteksta | -| [opencode-notify](https://github.com/kdcokenny/opencode-notify) | Notifikacije izvornog OS-a za OpenCode – znajte kada se zadaci dovrše | -| [opencode-workspace](https://github.com/kdcokenny/opencode-workspace) | Uvezeni višeagentni orkestracijski pojas – 16 komponenti, jedna instalacija | -| [opencode-worktree](https://github.com/kdcokenny/opencode-worktree) | Git radna stabla bez trenja za OpenCode | +| Ime | Opis | +| -------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | +| [opencode-daytona](https://github.com/daytonaio/daytona/tree/main/libs/opencode-plugin) | Automatski pokrenite OpenCode sesije u izoliranim Daytona sandboxovima uz git sinhronizaciju i preglede uživo | +| [opencode-helicone-session](https://github.com/H2Shami/opencode-helicone-session) | Automatski ubacite Helicone zaglavlja sesije za grupisanje zahtjeva | +| [opencode-type-inject](https://github.com/nick-vi/opencode-type-inject) | Automatski ubaci TypeScript/Svelte tipove u čitanje datoteka pomoću alata za pretraživanje | +| [opencode-openai-codex-auth](https://github.com/numman-ali/opencode-openai-codex-auth) | Koristite svoju ChatGPT Plus/Pro pretplatu umjesto API kredita | +| [opencode-gemini-auth](https://github.com/jenslys/opencode-gemini-auth) | Koristite svoj postojeći Gemini plan umjesto API naplate | +| [opencode-antigravity-auth](https://github.com/NoeFabris/opencode-antigravity-auth) | Koristite besplatne modele Antigravity umjesto API naplate | +| [opencode-devcontainers](https://github.com/athal7/opencode-devcontainers) | Izolacija devcontainer-a s više grana s plitkim klonovima i automatski dodijeljenim portovima | +| [opencode-google-antigravity-auth](https://github.com/shekohex/opencode-google-antigravity-auth) | Google Antigravity OAuth dodatak, s podrškom za Google pretraživanje i robusnijim API rukovanjem | +| [opencode-dynamic-context-pruning](https://github.com/Tarquinen/opencode-dynamic-context-pruning) | Optimizirajte korištenje tokena smanjenjem izlaza zastarjelih alata | +| [opencode-vibeguard](https://github.com/inkdust2021/opencode-vibeguard) | Redigujte tajne/PII u rezervirana mjesta u stilu VibeGuarda prije LLM poziva; vratite lokalno | +| [opencode-websearch-cited](https://github.com/ghoulr/opencode-websearch-cited.git) | Dodajte podršku za izvorno web pretraživanje za podržane provajdere sa stilom utemeljenim na Googleu | +| [opencode-pty](https://github.com/shekohex/opencode-pty.git) | Omogućuje AI agentima da pokreću pozadinske procese u PTY-u, šalju im interaktivni ulaz. | +| [opencode-shell-strategy](https://github.com/JRedeker/opencode-shell-strategy) | Upute za neinteraktivne naredbe ljuske - sprječava visi od TTY ovisnih operacija | +| [opencode-wakatime](https://github.com/angristan/opencode-wakatime) | Pratite upotrebu OpenCode sa Wakatime | +| [opencode-md-table-formatter](https://github.com/franlol/opencode-md-table-formatter/tree/main) | Očistite tabele umanjenja vrijednosti koje su izradili LLM | +| [opencode-morph-fast-apply](https://github.com/JRedeker/opencode-morph-fast-apply) | 10x brže uređivanje koda s Morph Fast Apply API-jem i markerima za lijeno uređivanje | +| [oh-my-opencode](https://github.com/code-yeongyu/oh-my-opencode) | Pozadinski agenti, unapred izgrađeni LSP/AST/MCP alati, kurirani agenti, kompatibilni sa Claude Code | +| [opencode-notificator](https://github.com/panta82/opencode-notificator) | Obavještenja na radnoj površini i zvučna upozorenja za OpenCode sesije | +| [opencode-notifier](https://github.com/mohak34/opencode-notifier) | Obavještenja na radnoj površini i zvučna upozorenja za dozvole, završetak i događaje greške | +| [opencode-zellij-namer](https://github.com/24601/opencode-zellij-namer) | Automatsko imenovanje Zellij sesije na bazi OpenCode konteksta | +| [opencode-skillful](https://github.com/zenobi-us/opencode-skillful) | Dozvolite OpenCode agentima da lijeno učitavaju upite na zahtjev uz otkrivanje vještina i ubrizgavanje | +| [opencode-supermemory](https://github.com/supermemoryai/opencode-supermemory) | Trajna memorija kroz sesije koristeći Supermemory | +| [@plannotator/opencode](https://github.com/backnotprop/plannotator/tree/main/apps/opencode-plugin) | Interaktivni pregled plana s vizualnim napomenama i privatnim/offline dijeljenjem | +| [@openspoon/subtask2](https://github.com/spoons-and-mirrors/subtask2) | Proširite opencode /komande u moćan sistem orkestracije sa granularnom kontrolom toka | +| [opencode-scheduler](https://github.com/different-ai/opencode-scheduler) | Planirajte ponavljajuće poslove koristeći launchd (Mac) ili systemd (Linux) sa cron sintaksom | +| [micode](https://github.com/vtemian/micode) | Strukturirana Brainstorm → Plan → Implementacija toka rada uz kontinuitet sesije | +| [octto](https://github.com/vtemian/octto) | Interaktivno korisničko sučelje pretraživača za AI brainstorming sa obrascima za više pitanja | +| [opencode-background-agents](https://github.com/kdcokenny/opencode-background-agents) | Pozadinski agenti u stilu Claudea s asinhroniziranim delegiranjem i postojanošću konteksta | +| [opencode-notify](https://github.com/kdcokenny/opencode-notify) | Notifikacije izvornog OS-a za OpenCode – znajte kada se zadaci dovrše | +| [opencode-workspace](https://github.com/kdcokenny/opencode-workspace) | Uvezeni višeagentni orkestracijski pojas – 16 komponenti, jedna instalacija | +| [opencode-worktree](https://github.com/kdcokenny/opencode-worktree) | Git radna stabla bez trenja za OpenCode | +| [opencode-sentry-monitor](https://github.com/stolinski/opencode-sentry-monitor) | Pratite i otklanjajte greške svojih AI agenata uz Sentry AI Monitoring | --- @@ -55,7 +61,7 @@ Također možete pogledati [awesome-opencode](https://github.com/awesome-opencod | [portal](https://github.com/hosenur/portal) | Mobilni korisnički interfejs za OpenCode preko Tailscale/VPN | | [opencode plugin template](https://github.com/zenobi-us/opencode-plugin-template/) | Predložak za izgradnju OpenCode dodataka | | [opencode.nvim](https://github.com/sudo-tee/opencode.nvim) | Neovim frontend za opencode - terminal baziran AI agent za kodiranje | -| [ai-sdk-provider-opencode-sdk](https://github.com/ben-vargas/ai-sdk-provider-opencode-sdk) | Vercel AI SDK dobavljač za korištenje OpenCode putem @opencodei/sdk | +| [ai-sdk-provider-opencode-sdk](https://github.com/ben-vargas/ai-sdk-provider-opencode-sdk) | Vercel AI SDK dobavljač za korištenje OpenCode putem @opencode-ai/sdk | | [OpenChamber](https://github.com/btriapitsyn/openchamber) | Web / Desktop App i VS Code Extension za OpenCode | | [OpenCode-Obsidian](https://github.com/mtymek/opencode-obsidian) | Obsidian dodatak koji ugrađuje OpenCode u Obsidian-ov UI | | [OpenWork](https://github.com/different-ai/openwork) | Alternativa otvorenog koda Claudeu Coworku, pokretana pomoću OpenCode | @@ -66,7 +72,7 @@ Također možete pogledati [awesome-opencode](https://github.com/awesome-opencod ## Agenti -| Ime | Opis | -| ------------------------------------------------------------- | --------------------------------------------------------------- | -| [Agentic](https://github.com/Cluster444/agentic) | Modularni AI agenti i komande za strukturirani razvoj | -| [opencodegents](https://github.com/darrenhinde/opencodegents) | Konfiguracije, upiti, agenti i dodaci za poboljšane tokove rada | +| Ime | Opis | +| ----------------------------------------------------------------- | --------------------------------------------------------------- | +| [Agentic](https://github.com/Cluster444/agentic) | Modularni AI agenti i komande za strukturirani razvoj | +| [opencode-agents](https://github.com/darrenhinde/opencode-agents) | Konfiguracije, upiti, agenti i dodaci za poboljšane tokove rada | diff --git a/packages/web/src/content/docs/bs/go.mdx b/packages/web/src/content/docs/bs/go.mdx new file mode 100644 index 0000000000..ec7bf25945 --- /dev/null +++ b/packages/web/src/content/docs/bs/go.mdx @@ -0,0 +1,159 @@ +--- +title: Go +description: Povoljna pretplata za otvorene modele kodiranja. +--- + +import config from "../../../../config.mjs" +export const console = config.console +export const email = `mailto:${config.email}` + +OpenCode Go je povoljna pretplata od **$10/mjesečno** koja vam daje pouzdan pristup popularnim otvorenim modelima kodiranja. + +:::note +OpenCode Go je trenutno u beta fazi. +::: + +Go funkcioniše kao bilo koji drugi pružatelj usluga u OpenCode-u. Pretplatite se na OpenCode Go i +dobijete svoj API ključ. To je **potpuno opcionalno** i ne morate ga koristiti da biste +koristili OpenCode. + +Dizajniran je prvenstveno za međunarodne korisnike, sa modelima hostovanim u SAD-u, EU i Singapuru za stabilan globalni pristup. + +--- + +## Pozadina + +Otvoreni modeli su postali zaista dobri. Sada dostižu performanse bliske +vlasničkim modelima za zadatke kodiranja. A budući da ih mnogi pružatelji usluga mogu posluživati +konkurentno, obično su daleko jeftiniji. + +Međutim, dobivanje pouzdanog pristupa s malim kašnjenjem može biti teško. Pružatelji usluga +variraju u kvaliteti i dostupnosti. + +:::tip +Testirali smo odabranu grupu modela i pružatelja usluga koji dobro rade sa OpenCode-om. +::: + +Da bismo ovo riješili, uradili smo nekoliko stvari: + +1. Testirali smo odabranu grupu otvorenih modela i razgovarali sa njihovim timovima o tome kako ih + najbolje pokrenuti. +2. Zatim smo radili sa nekoliko pružatelja usluga kako bismo bili sigurni da su ispravno + posluživani. +3. Konačno, benchmarkirali smo kombinaciju modela/pružatelja usluga i došli do + liste koju se osjećamo dobro preporučiti. + +OpenCode Go vam daje pristup ovim modelima za **$10/mjesečno**. + +--- + +## Kako to funkcioniše + +OpenCode Go funkcioniše kao bilo koji drugi pružatelj usluga u OpenCode-u. + +1. Prijavite se na **<a href={console}>OpenCode Zen</a>**, pretplatite se na Go i + kopirajte svoj API ključ. +2. Pokrenite `/connect` komandu u TUI-ju, odaberite `OpenCode Go` i zalijepite + svoj API ključ. +3. Pokrenite `/models` u TUI-ju da vidite listu modela dostupnih putem Go. + +:::note +Samo jedan član po radnom prostoru se može pretplatiti na OpenCode Go. +::: + +Trenutna lista modela uključuje: + +- **GLM-5** +- **Kimi K2.5** +- **MiniMax M2.5** + +Lista modela se može mijenjati kako testiramo i dodajemo nove. + +--- + +## Ograničenja korištenja + +OpenCode Go uključuje sljedeća ograničenja: + +- **Limit od 5 sati** — $12 korištenja +- **Sedmični limit** — $30 korištenja +- **Mjesečni limit** — $60 korištenja + +Limiti su definisani u dolarskoj vrijednosti. To znači da vaš stvarni broj zahtjeva zavisi od modela koji koristite. Jeftiniji modeli kao što je MiniMax M2.5 omogućavaju više zahtjeva, dok skuplji modeli kao što je GLM-5 omogućavaju manje. + +Tabela ispod pruža procijenjeni broj zahtjeva na osnovu tipičnih Go obrazaca korištenja: + +| | GLM-5 | Kimi K2.5 | MiniMax M2.5 | +| ------------------ | ----- | --------- | ------------ | +| zahtjeva po 5 sati | 1,150 | 1,850 | 30,000 | +| zahtjeva sedmično | 2,880 | 4,630 | 75,000 | +| zahtjeva mjesečno | 5,750 | 9,250 | 150,000 | + +Procjene su zasnovane na uočenim prosječnim obrascima zahtjeva: + +- GLM-5 — 700 ulaznih, 52,000 keširanih, 150 izlaznih tokena po zahtjevu +- Kimi K2.5 — 870 ulaznih, 55,000 keširanih, 200 izlaznih tokena po zahtjevu +- MiniMax M2.5 — 300 ulaznih, 55,000 keširanih, 125 izlaznih tokena po zahtjevu + +Možete pratiti svoje trenutno korištenje u **<a href={console}>konzoli</a>**. + +:::tip +Ako dosegnete limit korištenja, možete nastaviti koristiti besplatne modele. +::: + +Ograničenja korištenja se mogu mijenjati kako učimo iz rane upotrebe i povratnih informacija. + +--- + +### Cijene + +OpenCode Go je pretplatnički plan od **$10/mjesečno**. Ispod su cijene **po 1M tokena**. + +| Model | Ulaz | Izlaz | Keširano čitanje | +| ------------ | ----- | ----- | ---------------- | +| GLM-5 | $1.00 | $3.20 | $0.20 | +| Kimi K2.5 | $0.60 | $3.00 | $0.10 | +| MiniMax M2.5 | $0.30 | $1.20 | $0.03 | + +--- + +### Korištenje izvan limita + +Ako također imate kredita na svom Zen saldu, možete omogućiti opciju **Use balance** +u konzoli. Kada je omogućeno, Go će se prebaciti na vaš Zen saldo +nakon što dosegnete limite korištenja umjesto blokiranja zahtjeva. + +--- + +## Endpointi + +Također možete pristupiti Go modelima putem sljedećih API endpointa. + +| Model | ID modela | Endpoint | AI SDK Paket | +| ------------ | ------------ | ------------------------------------------------ | --------------------------- | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | + +[Model id](/docs/config/#models) u vašoj OpenCode konfiguraciji +koristi format `opencode-go/<model-id>`. Na primjer, za Kimi K2.5, biste +koristili `opencode-go/kimi-k2.5` u vašoj konfiguraciji. + +--- + +## Privatnost + +Plan je dizajniran prvenstveno za međunarodne korisnike, sa modelima hostovanim u SAD-u, EU i Singapuru za stabilan globalni pristup. + +<a href={email}>Kontaktirajte nas</a> ako imate bilo kakvih pitanja. + +--- + +## Ciljevi + +Kreirali smo OpenCode Go da: + +1. Učinimo AI kodiranje **pristupačnim** većem broju ljudi uz povoljnu pretplatu. +2. Pružimo **pouzdan** pristup najboljim otvorenim modelima kodiranja. +3. Kurišemo modele koji su **testirani i benchmarkirani** za upotrebu agenata za kodiranje. +4. Nemamo **zaključavanja (lock-in)** omogućavajući vam da koristite bilo kojeg drugog pružatelja usluga sa OpenCode-om također. diff --git a/packages/web/src/content/docs/bs/index.mdx b/packages/web/src/content/docs/bs/index.mdx index 5d21e994f9..4af699485a 100644 --- a/packages/web/src/content/docs/bs/index.mdx +++ b/packages/web/src/content/docs/bs/index.mdx @@ -80,9 +80,10 @@ Također ga možete instalirati pomoću sljedećih naredbi: - **Korištenje Parua na Arch Linuxu** -```bash - paru -S opencode-bin -``` + ```bash + sudo pacman -S opencode # Arch Linux (Stable) + paru -S opencode-bin # Arch Linux (Latest from AUR) + ``` #### Windows diff --git a/packages/web/src/content/docs/bs/keybinds.mdx b/packages/web/src/content/docs/bs/keybinds.mdx index f35dd38525..a70fdedaef 100644 --- a/packages/web/src/content/docs/bs/keybinds.mdx +++ b/packages/web/src/content/docs/bs/keybinds.mdx @@ -3,11 +3,11 @@ title: Prečice tipki description: Prilagodite svoje veze tipki. --- -OpenCode ima listu veza tipki koje možete prilagoditi preko OpenCode konfiguracije. +OpenCode ima listu veza tipki koje možete prilagoditi putem `tui.json`. -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "keybinds": { "leader": "ctrl+x", "app_exit": "ctrl+c,ctrl+d,<leader>q", @@ -28,6 +28,7 @@ OpenCode ima listu veza tipki koje možete prilagoditi preko OpenCode konfigurac "session_unshare": "none", "session_interrupt": "escape", "session_compact": "<leader>c", + "session_child_first": "<leader>down", "session_child_cycle": "<leader>right", "session_child_cycle_reverse": "<leader>left", "session_parent": "<leader>up", @@ -108,18 +109,20 @@ OpenCode ima listu veza tipki koje možete prilagoditi preko OpenCode konfigurac ## Leader tipka OpenCode koristi `leader` (vodeću) tipku za većinu povezivanja tipki. Ovo izbjegava sukobe u vašem terminalu. + Prema zadanim postavkama, `ctrl+x` je vodeća tipka i većina radnji zahtijeva da prvo pritisnete vodeću tipku, a zatim i prečicu. Na primjer, da biste započeli novu sesiju, prvo pritisnite `ctrl+x`, a zatim pritisnite `n`. + Ne morate koristiti vodeću tipku za svoje veze tipki, ali preporučujemo da to učinite. --- ## Onemogućavanje prečica tipki -Možete onemogućiti spajanje tipki dodavanjem ključa u svoju konfiguraciju s vrijednošću "none". +Možete onemogućiti spajanje tipki dodavanjem ključa u `tui.json` s vrijednošću "none". -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "keybinds": { "session_compact": "none" } diff --git a/packages/web/src/content/docs/bs/lsp.mdx b/packages/web/src/content/docs/bs/lsp.mdx index 463d9a0ad9..8f52f3bf61 100644 --- a/packages/web/src/content/docs/bs/lsp.mdx +++ b/packages/web/src/content/docs/bs/lsp.mdx @@ -8,40 +8,43 @@ OpenCode se integriše sa vašim Language Server Protocol (LSP) serverima kako b ## Ugrađeni OpenCode dolazi sa nekoliko ugrađenih LSP servera za popularne jezike: -| LSP server | Ekstenzije | Zahtjevi -|------------------ | ------------------------------------------------------------------- | ------------------------------------------------------------ | -| astro | .astro | Automatske instalacije za Astro projekte | -| bash | .sh, .bash, .zsh, .ksh | Automatski instalira bash-language-server | -| clangd | .c, .cpp, .cc, .cxx, .c++, .h, .hpp, .hh, .hxx, .h++ | Automatske instalacije za C/C++ projekte | -| csharp | .cs | `.NET SDK` instaliran | -| clojure-lsp | .clj, .cljs, .cljc, .edn | `clojure-lsp` komanda dostupna | -| dart | .dart | `dart` komanda dostupna | -| deno | .ts, .tsx, .js, .jsx, .mjs | `deno` komanda dostupna (automatski detektuje deno.json/deno.jsonc) | -| elixir-ls | .ex, .exs | `elixir` komanda dostupna | -| eslint | .ts, .tsx, .js, .jsx, .mjs, .cjs, .mts, .cts, .vue | `eslint` ovisnost u projektu | -| fsharp | .fs, .fsi, .fsx, .fsscript | `.NET SDK` instaliran | -| gleam | .bleam | `gleam` komanda dostupna | -| gopls | .go | `go` komanda dostupna | -| hls | .hs, .lhs | `haskell-language-server-wrapper` komanda dostupna | -| jdtls | .java | `Java SDK (version 21+)` instaliran | -| kotlin-ls | .kt, .kts | Automatske instalacije za Kotlin projekte | -| lua-ls | .lua | Automatske instalacije za Lua projekte | -| nixd | .nix | `nixd` komanda dostupna | -| ocaml-lsp | .ml, .mli | `ocamllsp` komanda dostupna | -| oxlint | .ts, .tsx, .js, .jsx, .mjs, .cjs, .mts, .cts, .vue, .astro, .svelte | `oxlint` zavisnost u projektu | -| php intelephense | .php | Automatske instalacije za PHP projekte | -| prisma | .prisma | `prisma` komanda dostupna | -| pyright | .py, .pyi | `pyright` ovisnost instalirana | -| ruby-lsp (rubocop) | .rb, .rake, .gemspec, .ru | `ruby` i `gem` komande dostupne | -| rust | .rs | `rust-analyzer` komanda dostupna | -| sourcekit-lsp | .swift, .objc, .objcpp | `swift` instaliran (`xcode` na macOS-u) | -| svelte | .svelte | Automatske instalacije za Svelte projekte | -| terraform | .tf, .tfvars | Automatske instalacije iz GitHub izdanja | -| tinymist | .typ, .typc | Automatske instalacije iz GitHub izdanja | -| typescript | .ts, .tsx, .js, .jsx, .mjs, .cjs, .mts, .cts | `typescript` zavisnost u projektu | -| vue | .vue | Automatske instalacije za Vue projekte | -| yaml-ls | .yaml, .yml | Automatski instalira Red Hat yaml-language-server | -| zls | .zig, .zon | `zig` komanda dostupna | + +| LSP server | Ekstenzije | Zahtjevi | +| ------------------ | ------------------------------------------------------------------- | -------------------------------------------------------- | +| astro | .astro | Automatske instalacije za Astro projekte | +| bash | .sh, .bash, .zsh, .ksh | Automatski instalira bash-language-server | +| clangd | .c, .cpp, .cc, .cxx, .c++, .h, .hpp, .hh, .hxx, .h++ | Automatske instalacije za C/C++ projekte | +| csharp | .cs | `.NET SDK` instaliran | +| clojure-lsp | .clj, .cljs, .cljc, .edn | `clojure-lsp` komanda dostupna | +| dart | .dart | `dart` komanda dostupna | +| deno | .ts, .tsx, .js, .jsx, .mjs | `deno` komanda dostupna (automatski detektuje deno.json) | +| elixir-ls | .ex, .exs | `elixir` komanda dostupna | +| eslint | .ts, .tsx, .js, .jsx, .mjs, .cjs, .mts, .cts, .vue | `eslint` ovisnost u projektu | +| fsharp | .fs, .fsi, .fsx, .fsscript | `.NET SDK` instaliran | +| gleam | .gleam | `gleam` komanda dostupna | +| gopls | .go | `go` komanda dostupna | +| hls | .hs, .lhs | `haskell-language-server-wrapper` komanda dostupna | +| jdtls | .java | `Java SDK (version 21+)` instaliran | +| julials | .jl | `julia` i `LanguageServer.jl` instalirani | +| kotlin-ls | .kt, .kts | Automatske instalacije za Kotlin projekte | +| lua-ls | .lua | Automatske instalacije za Lua projekte | +| nixd | .nix | `nixd` komanda dostupna | +| ocaml-lsp | .ml, .mli | `ocamllsp` komanda dostupna | +| oxlint | .ts, .tsx, .js, .jsx, .mjs, .cjs, .mts, .cts, .vue, .astro, .svelte | `oxlint` zavisnost u projektu | +| php intelephense | .php | Automatske instalacije za PHP projekte | +| prisma | .prisma | `prisma` komanda dostupna | +| pyright | .py, .pyi | `pyright` ovisnost instalirana | +| ruby-lsp (rubocop) | .rb, .rake, .gemspec, .ru | `ruby` i `gem` komande dostupne | +| rust | .rs | `rust-analyzer` komanda dostupna | +| sourcekit-lsp | .swift, .objc, .objcpp | `swift` instaliran (`xcode` na macOS-u) | +| svelte | .svelte | Automatske instalacije za Svelte projekte | +| terraform | .tf, .tfvars | Automatske instalacije iz GitHub izdanja | +| tinymist | .typ, .typc | Automatske instalacije iz GitHub izdanja | +| typescript | .ts, .tsx, .js, .jsx, .mjs, .cjs, .mts, .cts | `typescript` zavisnost u projektu | +| vue | .vue | Automatske instalacije za Vue projekte | +| yaml-ls | .yaml, .yml | Automatski instalira Red Hat yaml-language-server | +| zls | .zig, .zon | `zig` komanda dostupna | + LSP serveri su automatski omogućeni kada se otkrije jedna od gore navedenih ekstenzija datoteke i zahtjevi su ispunjeni. :::note Možete onemogućiti automatska preuzimanja LSP servera tako što ćete postaviti varijablu okruženja `OPENCODE_DISABLE_LSP_DOWNLOAD` na `true`. @@ -70,13 +73,15 @@ Možete prilagoditi LSP servere kroz `lsp` odjeljak u vašoj opencode konfigurac ``` Svaki LSP server podržava sljedeće: -| Svojstvo | Vrsta | Opis -|---------------- | -------- | ------------------------------------------------- | -| `disabled` | boolean | Postavite ovo na `true` da onemogućite LSP server | -| `command` | string[] | Naredba za pokretanje LSP servera | -| `extensions` | string[] | Ekstenzije datoteka koje ovaj LSP server treba da rukuje | -| `env` | objekt | Varijable okruženja koje treba postaviti prilikom pokretanja servera | -| `initialization` | objekt | Opcije inicijalizacije za slanje na LSP server | + +| Svojstvo | Vrsta | Opis | +| ---------------- | -------- | -------------------------------------------------------------------- | +| `disabled` | boolean | Postavite ovo na `true` da onemogućite LSP server | +| `command` | string[] | Naredba za pokretanje LSP servera | +| `extensions` | string[] | Ekstenzije datoteka koje ovaj LSP server treba da rukuje | +| `env` | objekt | Varijable okruženja koje treba postaviti prilikom pokretanja servera | +| `initialization` | objekt | Opcije inicijalizacije za slanje na LSP server | + Pogledajmo neke primjere. --- diff --git a/packages/web/src/content/docs/bs/plugins.mdx b/packages/web/src/content/docs/bs/plugins.mdx index 9b7e9f12b7..7e046cb83d 100644 --- a/packages/web/src/content/docs/bs/plugins.mdx +++ b/packages/web/src/content/docs/bs/plugins.mdx @@ -225,7 +225,7 @@ export const NotificationPlugin = async ({ project, client, $, directory, worktr Koristimo `osascript` za pokretanje AppleScript-a na macOS-u. Ovdje ga koristimo za slanje obavještenja. :::note -Ako koristite desktop aplikaciju OpenCode, ona može automatski slati sistemske obavijesti kada je odgovor spreman ili kada dođe do greške u sesiji. +Ako alat dodatka koristi isto ime kao ugrađeni alat, alat dodatka ima prednost. ::: --- diff --git a/packages/web/src/content/docs/bs/providers.mdx b/packages/web/src/content/docs/bs/providers.mdx index 2415cda277..6bdcf45778 100644 --- a/packages/web/src/content/docs/bs/providers.mdx +++ b/packages/web/src/content/docs/bs/providers.mdx @@ -84,6 +84,37 @@ Radi kao i svaki drugi provajder u OpenCode i potpuno je opcionalan za korišten --- +## OpenCode Go + +OpenCode Go je jeftin plan pretplate koji pruža pouzdan pristup popularnim modelima otvorenog kodiranja koje pruža OpenCode tim i koji su testirani i verificirani da dobro rade s OpenCode-om. + +1. Pokrenite naredbu `/connect` u TUI-u, odaberite `OpenCode Go` i idite na [opencode.ai/auth](https://opencode.ai/zen). + + ```txt + /connect + ``` + +2. Prijavite se, dodajte svoje detalje naplate i kopirajte svoj API ključ. + +3. Zalijepite svoj API ključ. + + ```txt + ┌ API key + │ + │ + └ enter + ``` + +4. Pokrenite naredbu `/models` u TUI da vidite listu modela koje preporučujemo. + + ```txt + /models + ``` + +Radi kao i svaki drugi provajder u OpenCode i potpuno je opcionalan za korištenje. + +--- + ## Direktorij Pogledajmo neke od provajdera detaljno. Ako želite dodati provajdera na @@ -1479,9 +1510,42 @@ Ove postavke su opcione i treba ih konfigurirati u skladu s vašim SAP AI Core p 5. Pokrenite naredbu `/models` da odaberete između 40+ dostupnih modela. -```txt + ```txt /models -``` + ``` + +--- + +### STACKIT + +STACKIT AI Model Serving pruža potpuno upravljano suvereno hosting okruženje za AI modele, fokusirajući se na LLM-ove kao što su Llama, Mistral i Qwen, uz maksimalan suverenitet podataka na evropskoj infrastrukturi. + +1. Idite na [STACKIT Portal](https://portal.stackit.cloud), idite na **AI Model Serving** i kreirajte token za autentifikaciju za svoj projekat. + + :::tip + Potreban vam je STACKIT korisnički račun, korisnički nalog i projekat prije kreiranja tokena za autentifikaciju. + ::: + +2. Pokrenite naredbu `/connect` i potražite **STACKIT**. + + ```txt + /connect + ``` + +3. Unesite svoj STACKIT AI Model Serving token za autentifikaciju. + + ```txt + ┌ API key + │ + │ + └ enter + ``` + +4. Pokrenite naredbu `/models` da odaberete dostupne modele kao što su _Qwen3-VL 235B_ ili _Llama 3.3 70B_. + + ```txt + /models + ``` --- diff --git a/packages/web/src/content/docs/bs/sdk.mdx b/packages/web/src/content/docs/bs/sdk.mdx index fe6ab4ef14..cc9c2b3bf4 100644 --- a/packages/web/src/content/docs/bs/sdk.mdx +++ b/packages/web/src/content/docs/bs/sdk.mdx @@ -117,6 +117,78 @@ try { --- +## Strukturirani izlaz + +Možete zatražiti strukturirani JSON izlaz od modela specificiranjem `format` sa JSON šemom. Model će koristiti `StructuredOutput` alat da vrati validirani JSON koji odgovara vašoj šemi. + +### Osnovna upotreba + +```typescript +const result = await client.session.prompt({ + path: { id: sessionId }, + body: { + parts: [{ type: "text", text: "Research Anthropic and provide company info" }], + format: { + type: "json_schema", + schema: { + type: "object", + properties: { + company: { type: "string", description: "Company name" }, + founded: { type: "number", description: "Year founded" }, + products: { + type: "array", + items: { type: "string" }, + description: "Main products", + }, + }, + required: ["company", "founded"], + }, + }, + }, +}) + +// Access the structured output +console.log(result.data.info.structured_output) +// { company: "Anthropic", founded: 2021, products: ["Claude", "Claude API"] } +``` + +### Tipovi formata izlaza + +| Tip | Opis | +| ------------- | ------------------------------------------------------------------- | +| `text` | Default. Standardni tekstualni odgovor (nema strukturiranog izlaza) | +| `json_schema` | Vraća validirani JSON koji odgovara pruženoj šemi | + +### Format JSON šeme + +Kada koristite `type: 'json_schema'`, navedite: + +| Polje | Tip | Opis | +| ------------ | --------------- | ----------------------------------------------------------- | +| `type` | `'json_schema'` | Obavezno. Određuje JSON schema način rada | +| `schema` | `object` | Obavezno. JSON Schema objekt koji definira strukturu izlaza | +| `retryCount` | `number` | Opcionalno. Broj ponovnih pokušaja validacije (default: 2) | + +### Rukovanje greškama + +Ako model ne uspije proizvesti validan strukturirani izlaz nakon svih ponovnih pokušaja, odgovor će uključivati `StructuredOutputError`: + +```typescript +if (result.data.info.error?.name === "StructuredOutputError") { + console.error("Failed to produce structured output:", result.data.info.error.message) + console.error("Attempts:", result.data.info.error.retries) +} +``` + +### Najbolje prakse + +1. **Navedite jasne opise** u svojstvima vaše šeme kako biste pomogli modelu da razumije koje podatke treba izdvojiti +2. **Koristite `required`** da odredite koja polja moraju biti prisutna +3. **Držite šeme fokusiranim** - složene ugniježđene šeme modelu mogu biti teže za ispravno popunjavanje +4. **Postavite odgovarajući `retryCount`** - povećajte za složene šeme, smanjite za jednostavne + +--- + ## API-ji SDK izlaže sve server API-je kroz type-safe klijent. @@ -226,27 +298,27 @@ const { providers, default: defaults } = await client.config.providers() ### Sesije -| Metoda | Opis | Napomene | -| ---------------------------------------------------------- | ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | -| `session.list()` | List sessions | Returns <a href={typesUrl}><code>Session[]</code></a> | -| `session.get({ path })` | Get session | Returns <a href={typesUrl}><code>Session</code></a> | -| `session.children({ path })` | List child sessions | Returns <a href={typesUrl}><code>Session[]</code></a> | -| `session.create({ body })` | Create session | Returns <a href={typesUrl}><code>Session</code></a> | -| `session.delete({ path })` | Delete session | Returns `boolean` | -| `session.update({ path, body })` | Update session properties | Returns <a href={typesUrl}><code>Session</code></a> | -| `session.init({ path, body })` | Analyze app and create `AGENTS.md` | Returns `boolean` | -| `session.abort({ path })` | Abort a running session | Returns `boolean` | -| `session.share({ path })` | Share session | Returns <a href={typesUrl}><code>Session</code></a> | -| `session.unshare({ path })` | Unshare session | Returns <a href={typesUrl}><code>Session</code></a> | -| `session.summarize({ path, body })` | Summarize session | Returns `boolean` | -| `session.messages({ path })` | List messages in a session | Returns `{ info: `<a href={typesUrl}><code>Message</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}[]` | -| `session.message({ path })` | Get message details | Returns `{ info: `<a href={typesUrl}><code>Message</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}` | -| `session.prompt({ path, body })` | Send prompt message | `body.noReply: true` returns UserMessage (context only). Default returns <a href={typesUrl}><code>AssistantMessage</code></a> with AI response | -| `session.command({ path, body })` | Send command to session | Returns `{ info: `<a href={typesUrl}><code>AssistantMessage</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}` | -| `session.shell({ path, body })` | Run a shell command | Returns <a href={typesUrl}><code>AssistantMessage</code></a> | -| `session.revert({ path, body })` | Revert a message | Returns <a href={typesUrl}><code>Session</code></a> | -| `session.unrevert({ path })` | Restore reverted messages | Returns <a href={typesUrl}><code>Session</code></a> | -| `postSessionByIdPermissionsByPermissionId({ path, body })` | Respond to a permission request | Returns `boolean` | +| Metoda | Opis | Napomene | +| ---------------------------------------------------------- | ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `session.list()` | List sessions | Returns <a href={typesUrl}><code>Session[]</code></a> | +| `session.get({ path })` | Get session | Returns <a href={typesUrl}><code>Session</code></a> | +| `session.children({ path })` | List child sessions | Returns <a href={typesUrl}><code>Session[]</code></a> | +| `session.create({ body })` | Create session | Returns <a href={typesUrl}><code>Session</code></a> | +| `session.delete({ path })` | Delete session | Returns `boolean` | +| `session.update({ path, body })` | Update session properties | Returns <a href={typesUrl}><code>Session</code></a> | +| `session.init({ path, body })` | Analyze app and create `AGENTS.md` | Returns `boolean` | +| `session.abort({ path })` | Abort a running session | Returns `boolean` | +| `session.share({ path })` | Share session | Returns <a href={typesUrl}><code>Session</code></a> | +| `session.unshare({ path })` | Unshare session | Returns <a href={typesUrl}><code>Session</code></a> | +| `session.summarize({ path, body })` | Summarize session | Returns `boolean` | +| `session.messages({ path })` | List messages in a session | Returns `{ info: `<a href={typesUrl}><code>Message</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}[]` | +| `session.message({ path })` | Get message details | Returns `{ info: `<a href={typesUrl}><code>Message</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}` | +| `session.prompt({ path, body })` | Send prompt message | `body.noReply: true` returns UserMessage (context only). Default returns <a href={typesUrl}><code>AssistantMessage</code></a> with AI response. Supports `body.outputFormat` for [structured output](#strukturirani-izlaz) | +| `session.command({ path, body })` | Send command to session | Returns `{ info: `<a href={typesUrl}><code>AssistantMessage</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}` | +| `session.shell({ path, body })` | Run a shell command | Returns <a href={typesUrl}><code>AssistantMessage</code></a> | +| `session.revert({ path, body })` | Revert a message | Returns <a href={typesUrl}><code>Session</code></a> | +| `session.unrevert({ path })` | Restore reverted messages | Returns <a href={typesUrl}><code>Session</code></a> | +| `postSessionByIdPermissionsByPermissionId({ path, body })` | Respond to a permission request | Returns `boolean` | --- diff --git a/packages/web/src/content/docs/bs/server.mdx b/packages/web/src/content/docs/bs/server.mdx index 7d270fb4aa..5237873d5f 100644 --- a/packages/web/src/content/docs/bs/server.mdx +++ b/packages/web/src/content/docs/bs/server.mdx @@ -86,116 +86,116 @@ opencode server izlaže sljedece API-je. ### Globalno -| Metoda | Putanja | Opis | Odgovor | -| ------ | ---------------- | ------------------------------ | ------------------------------------ | -| `GET` | `/global/health` | Get server health and version | `{ healthy: true, version: string }` | -| `GET` | `/global/event` | Get global events (SSE stream) | Event stream | +| Metoda | Putanja | Opis | Odgovor | +| ------ | ---------------- | ----------------------------------- | ------------------------------------ | +| `GET` | `/global/health` | Dohvati zdravlje i verziju servera | `{ healthy: true, version: string }` | +| `GET` | `/global/event` | Dohvati globalne događaje (SSE tok) | Event stream | --- ### Projekt -| Metoda | Putanja | Opis | Odgovor | -| ------ | ------------------ | ----------------------- | --------------------------------------------- | -| `GET` | `/project` | List all projects | <a href={typesUrl}><code>Project[]</code></a> | -| `GET` | `/project/current` | Get the current project | <a href={typesUrl}><code>Project</code></a> | +| Metoda | Putanja | Opis | Odgovor | +| ------ | ------------------ | ------------------------ | --------------------------------------------- | +| `GET` | `/project` | Izlistaj sve projekte | <a href={typesUrl}><code>Project[]</code></a> | +| `GET` | `/project/current` | Dohvati trenutni projekt | <a href={typesUrl}><code>Project</code></a> | --- ### Putanja i VCS -| Metoda | Putanja | Opis | Odgovor | -| ------ | ------- | ------------------------------------ | ------------------------------------------- | -| `GET` | `/path` | Get the current path | <a href={typesUrl}><code>Path</code></a> | -| `GET` | `/vcs` | Get VCS info for the current project | <a href={typesUrl}><code>VcsInfo</code></a> | +| Metoda | Putanja | Opis | Odgovor | +| ------ | ------- | ------------------------------------------- | ------------------------------------------- | +| `GET` | `/path` | Dohvati trenutnu putanju | <a href={typesUrl}><code>Path</code></a> | +| `GET` | `/vcs` | Dohvati VCS informacije za trenutni projekt | <a href={typesUrl}><code>VcsInfo</code></a> | --- ### Instanca -| Metoda | Putanja | Opis | Odgovor | -| ------ | ------------------- | ---------------------------- | --------- | -| `POST` | `/instance/dispose` | Dispose the current instance | `boolean` | +| Metoda | Putanja | Opis | Odgovor | +| ------ | ------------------- | ----------------------- | --------- | +| `POST` | `/instance/dispose` | Ugasi trenutnu instancu | `boolean` | --- ### Konfiguracija -| Metoda | Putanja | Opis | Odgovor | -| ------- | ------------------- | --------------------------------- | ---------------------------------------------------------------------------------------- | -| `GET` | `/config` | Get config info | <a href={typesUrl}><code>Config</code></a> | -| `PATCH` | `/config` | Update config | <a href={typesUrl}><code>Config</code></a> | -| `GET` | `/config/providers` | List providers and default models | `{ providers: `<a href={typesUrl}>Provider[]</a>`, default: { [key: string]: string } }` | +| Metoda | Putanja | Opis | Odgovor | +| ------- | ------------------- | ----------------------------------- | ---------------------------------------------------------------------------------------- | +| `GET` | `/config` | Dohvati informacije o konfiguraciji | <a href={typesUrl}><code>Config</code></a> | +| `PATCH` | `/config` | Ažuriraj konfiguraciju | <a href={typesUrl}><code>Config</code></a> | +| `GET` | `/config/providers` | Izlistaj provajdere i zadane modele | `{ providers: `<a href={typesUrl}>Provider[]</a>`, default: { [key: string]: string } }` | --- ### Provajder -| Metoda | Putanja | Opis | Odgovor | -| ------ | -------------------------------- | ------------------------------------ | ----------------------------------------------------------------------------------- | -| `GET` | `/provider` | List all providers | `{ all: `<a href={typesUrl}>Provider[]</a>`, default: {...}, connected: string[] }` | -| `GET` | `/provider/auth` | Get provider authentication methods | `{ [providerID: string]: `<a href={typesUrl}>ProviderAuthMethod[]</a>` }` | -| `POST` | `/provider/{id}/oauth/authorize` | Authorize a provider using OAuth | <a href={typesUrl}><code>ProviderAuthAuthorization</code></a> | -| `POST` | `/provider/{id}/oauth/callback` | Handle OAuth callback for a provider | `boolean` | +| Metoda | Putanja | Opis | Odgovor | +| ------ | -------------------------------- | ----------------------------------------- | ----------------------------------------------------------------------------------- | +| `GET` | `/provider` | Izlistaj sve provajdere | `{ all: `<a href={typesUrl}>Provider[]</a>`, default: {...}, connected: string[] }` | +| `GET` | `/provider/auth` | Dohvati metode autentifikacije provajdera | `{ [providerID: string]: `<a href={typesUrl}>ProviderAuthMethod[]</a>` }` | +| `POST` | `/provider/{id}/oauth/authorize` | Autoriziraj provajdera koristeći OAuth | <a href={typesUrl}><code>ProviderAuthAuthorization</code></a> | +| `POST` | `/provider/{id}/oauth/callback` | Obradi OAuth povratni poziv za provajdera | `boolean` | --- ### Sesije -| Metoda | Putanja | Opis | Napomene | -| -------- | ---------------------------------------- | ------------------------------------- | ---------------------------------------------------------------------------------- | -| `GET` | `/session` | List all sessions | Returns <a href={typesUrl}><code>Session[]</code></a> | -| `POST` | `/session` | Create a new session | body: `{ parentID?, title? }`, returns <a href={typesUrl}><code>Session</code></a> | -| `GET` | `/session/status` | Get session status for all sessions | Returns `{ [sessionID: string]: `<a href={typesUrl}>SessionStatus</a>` }` | -| `GET` | `/session/:id` | Get session details | Returns <a href={typesUrl}><code>Session</code></a> | -| `DELETE` | `/session/:id` | Delete a session and all its data | Returns `boolean` | -| `PATCH` | `/session/:id` | Update session properties | body: `{ title? }`, returns <a href={typesUrl}><code>Session</code></a> | -| `GET` | `/session/:id/children` | Get a session's child sessions | Returns <a href={typesUrl}><code>Session[]</code></a> | -| `GET` | `/session/:id/todo` | Get the todo list for a session | Returns <a href={typesUrl}><code>Todo[]</code></a> | -| `POST` | `/session/:id/init` | Analyze app and create `AGENTS.md` | body: `{ messageID, providerID, modelID }`, returns `boolean` | -| `POST` | `/session/:id/fork` | Fork an existing session at a message | body: `{ messageID? }`, returns <a href={typesUrl}><code>Session</code></a> | -| `POST` | `/session/:id/abort` | Abort a running session | Returns `boolean` | -| `POST` | `/session/:id/share` | Share a session | Returns <a href={typesUrl}><code>Session</code></a> | -| `DELETE` | `/session/:id/share` | Unshare a session | Returns <a href={typesUrl}><code>Session</code></a> | -| `GET` | `/session/:id/diff` | Get the diff for this session | query: `messageID?`, returns <a href={typesUrl}><code>FileDiff[]</code></a> | -| `POST` | `/session/:id/summarize` | Summarize the session | body: `{ providerID, modelID }`, returns `boolean` | -| `POST` | `/session/:id/revert` | Revert a message | body: `{ messageID, partID? }`, returns `boolean` | -| `POST` | `/session/:id/unrevert` | Restore all reverted messages | Returns `boolean` | -| `POST` | `/session/:id/permissions/:permissionID` | Respond to a permission request | body: `{ response, remember? }`, returns `boolean` | +| Metoda | Putanja | Opis | Napomene | +| -------- | ---------------------------------------- | ------------------------------------------- | ---------------------------------------------------------------------------------- | +| `GET` | `/session` | Izlistaj sve sesije | Returns <a href={typesUrl}><code>Session[]</code></a> | +| `POST` | `/session` | Kreiraj novu sesiju | body: `{ parentID?, title? }`, returns <a href={typesUrl}><code>Session</code></a> | +| `GET` | `/session/status` | Dohvati status sesije za sve sesije | Returns `{ [sessionID: string]: `<a href={typesUrl}>SessionStatus</a>` }` | +| `GET` | `/session/:id` | Dohvati detalje sesije | Returns <a href={typesUrl}><code>Session</code></a> | +| `DELETE` | `/session/:id` | Obriši sesiju i sve njene podatke | Returns `boolean` | +| `PATCH` | `/session/:id` | Ažuriraj svojstva sesije | body: `{ title? }`, returns <a href={typesUrl}><code>Session</code></a> | +| `GET` | `/session/:id/children` | Dohvati pod-sesije sesije | Returns <a href={typesUrl}><code>Session[]</code></a> | +| `GET` | `/session/:id/todo` | Dohvati listu zadataka za sesiju | Returns <a href={typesUrl}><code>Todo[]</code></a> | +| `POST` | `/session/:id/init` | Analiziraj aplikaciju i kreiraj `AGENTS.md` | body: `{ messageID, providerID, modelID }`, returns `boolean` | +| `POST` | `/session/:id/fork` | Granaj postojeću sesiju na poruci | body: `{ messageID? }`, returns <a href={typesUrl}><code>Session</code></a> | +| `POST` | `/session/:id/abort` | Prekini sesiju u toku | Returns `boolean` | +| `POST` | `/session/:id/share` | Podijeli sesiju | Returns <a href={typesUrl}><code>Session</code></a> | +| `DELETE` | `/session/:id/share` | Prestani dijeliti sesiju | Returns <a href={typesUrl}><code>Session</code></a> | +| `GET` | `/session/:id/diff` | Dohvati razlike za ovu sesiju | query: `messageID?`, returns <a href={typesUrl}><code>FileDiff[]</code></a> | +| `POST` | `/session/:id/summarize` | Rezimiraj sesiju | body: `{ providerID, modelID }`, returns `boolean` | +| `POST` | `/session/:id/revert` | Vrati poruku | body: `{ messageID, partID? }`, returns `boolean` | +| `POST` | `/session/:id/unrevert` | Vrati sve vraćene poruke | Returns `boolean` | +| `POST` | `/session/:id/permissions/:permissionID` | Odgovori na zahtjev za dozvolu | body: `{ response, remember? }`, returns `boolean` | --- ### Poruke -| Metoda | Putanja | Opis | Napomene | -| ------ | --------------------------------- | --------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `GET` | `/session/:id/message` | List messages in a session | query: `limit?`, returns `{ info: `<a href={typesUrl}>Message</a>`, parts: `<a href={typesUrl}>Part[]</a>`}[]` | -| `POST` | `/session/:id/message` | Send a message and wait for response | body: `{ messageID?, model?, agent?, noReply?, system?, tools?, parts }`, returns `{ info: `<a href={typesUrl}>Message</a>`, parts: `<a href={typesUrl}>Part[]</a>`}` | -| `GET` | `/session/:id/message/:messageID` | Get message details | Returns `{ info: `<a href={typesUrl}>Message</a>`, parts: `<a href={typesUrl}>Part[]</a>`}` | -| `POST` | `/session/:id/prompt_async` | Send a message asynchronously (no wait) | body: same as `/session/:id/message`, returns `204 No Content` | -| `POST` | `/session/:id/command` | Execute a slash command | body: `{ messageID?, agent?, model?, command, arguments }`, returns `{ info: `<a href={typesUrl}>Message</a>`, parts: `<a href={typesUrl}>Part[]</a>`}` | -| `POST` | `/session/:id/shell` | Run a shell command | body: `{ agent, model?, command }`, returns `{ info: `<a href={typesUrl}>Message</a>`, parts: `<a href={typesUrl}>Part[]</a>`}` | +| Metoda | Putanja | Opis | Napomene | +| ------ | --------------------------------- | -------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `GET` | `/session/:id/message` | Izlistaj poruke u sesiji | query: `limit?`, returns `{ info: `<a href={typesUrl}>Message</a>`, parts: `<a href={typesUrl}>Part[]</a>`}[]` | +| `POST` | `/session/:id/message` | Pošalji poruku i čekaj odgovor | body: `{ messageID?, model?, agent?, noReply?, system?, tools?, parts }`, returns `{ info: `<a href={typesUrl}>Message</a>`, parts: `<a href={typesUrl}>Part[]</a>`}` | +| `GET` | `/session/:id/message/:messageID` | Dohvati detalje poruke | Returns `{ info: `<a href={typesUrl}>Message</a>`, parts: `<a href={typesUrl}>Part[]</a>`}` | +| `POST` | `/session/:id/prompt_async` | Pošalji poruku asinkrono (bez čekanja) | body: same as `/session/:id/message`, returns `204 No Content` | +| `POST` | `/session/:id/command` | Izvrši slash naredbu | body: `{ messageID?, agent?, model?, command, arguments }`, returns `{ info: `<a href={typesUrl}>Message</a>`, parts: `<a href={typesUrl}>Part[]</a>`}` | +| `POST` | `/session/:id/shell` | Pokreni shell naredbu | body: `{ agent, model?, command }`, returns `{ info: `<a href={typesUrl}>Message</a>`, parts: `<a href={typesUrl}>Part[]</a>`}` | --- ### Naredbe -| Metoda | Putanja | Opis | Odgovor | -| ------ | ---------- | ----------------- | --------------------------------------------- | -| `GET` | `/command` | List all commands | <a href={typesUrl}><code>Command[]</code></a> | +| Metoda | Putanja | Opis | Odgovor | +| ------ | ---------- | -------------------- | --------------------------------------------- | +| `GET` | `/command` | Izlistaj sve naredbe | <a href={typesUrl}><code>Command[]</code></a> | --- ### Datoteke -| Metoda | Putanja | Opis | Odgovor | -| ------ | ------------------------ | ---------------------------------- | ------------------------------------------------------------------------------------------- | -| `GET` | `/find?pattern=<pat>` | Search for text in files | Array of match objects with `path`, `lines`, `line_number`, `absolute_offset`, `submatches` | -| `GET` | `/find/file?query=<q>` | Find files and directories by name | `string[]` (paths) | -| `GET` | `/find/symbol?query=<q>` | Find workspace symbols | <a href={typesUrl}><code>Symbol[]</code></a> | -| `GET` | `/file?path=<path>` | List files and directories | <a href={typesUrl}><code>FileNode[]</code></a> | -| `GET` | `/file/content?path=<p>` | Read a file | <a href={typesUrl}><code>FileContent</code></a> | -| `GET` | `/file/status` | Get status for tracked files | <a href={typesUrl}><code>File[]</code></a> | +| Metoda | Putanja | Opis | Odgovor | +| ------ | ------------------------ | --------------------------------------- | ------------------------------------------------------------------------------------------- | +| `GET` | `/find?pattern=<pat>` | Traži tekst u datotekama | Array of match objects with `path`, `lines`, `line_number`, `absolute_offset`, `submatches` | +| `GET` | `/find/file?query=<q>` | Pronađi datoteke i direktorije po imenu | `string[]` (paths) | +| `GET` | `/find/symbol?query=<q>` | Pronađi simbole radnog prostora | <a href={typesUrl}><code>Symbol[]</code></a> | +| `GET` | `/file?path=<path>` | Izlistaj datoteke i direktorije | <a href={typesUrl}><code>FileNode[]</code></a> | +| `GET` | `/file/content?path=<p>` | Pročitaj datoteku | <a href={typesUrl}><code>FileContent</code></a> | +| `GET` | `/file/status` | Dohvati status za praćene datoteke | <a href={typesUrl}><code>File[]</code></a> | #### `/find/file` parametri upita @@ -209,10 +209,10 @@ opencode server izlaže sljedece API-je. ### Alati (Eksperimentalno) -| Metoda | Putanja | Opis | Odgovor | -| ------ | ------------------------------------------- | ---------------------------------------- | -------------------------------------------- | -| `GET` | `/experimental/tool/ids` | List all tool IDs | <a href={typesUrl}><code>ToolIDs</code></a> | -| `GET` | `/experimental/tool?provider=<p>&model=<m>` | List tools with JSON schemas for a model | <a href={typesUrl}><code>ToolList</code></a> | +| Metoda | Putanja | Opis | Odgovor | +| ------ | ------------------------------------------- | -------------------------------------- | -------------------------------------------- | +| `GET` | `/experimental/tool/ids` | Izlistaj sve ID-ove alata | <a href={typesUrl}><code>ToolIDs</code></a> | +| `GET` | `/experimental/tool?provider=<p>&model=<m>` | Izlistaj alate sa JSON šemama za model | <a href={typesUrl}><code>ToolList</code></a> | --- @@ -220,65 +220,65 @@ opencode server izlaže sljedece API-je. | Metoda | Putanja | Opis | Odgovor | | ------ | ------------ | -------------------------- | -------------------------------------------------------- | -| `GET` | `/lsp` | Get LSP server status | <a href={typesUrl}><code>LSPStatus[]</code></a> | -| `GET` | `/formatter` | Get formatter status | <a href={typesUrl}><code>FormatterStatus[]</code></a> | -| `GET` | `/mcp` | Get MCP server status | `{ [name: string]: `<a href={typesUrl}>MCPStatus</a>` }` | -| `POST` | `/mcp` | Add MCP server dynamically | body: `{ name, config }`, returns MCP status object | +| `GET` | `/lsp` | Dohvati status LSP servera | <a href={typesUrl}><code>LSPStatus[]</code></a> | +| `GET` | `/formatter` | Dohvati status formatera | <a href={typesUrl}><code>FormatterStatus[]</code></a> | +| `GET` | `/mcp` | Dohvati status MCP servera | `{ [name: string]: `<a href={typesUrl}>MCPStatus</a>` }` | +| `POST` | `/mcp` | Dodaj MCP server dinamički | body: `{ name, config }`, returns MCP status object | --- ### Agenti -| Metoda | Putanja | Opis | Odgovor | -| ------ | -------- | ------------------------- | ------------------------------------------- | -| `GET` | `/agent` | List all available agents | <a href={typesUrl}><code>Agent[]</code></a> | +| Metoda | Putanja | Opis | Odgovor | +| ------ | -------- | ---------------------------- | ------------------------------------------- | +| `GET` | `/agent` | Izlistaj sve dostupne agente | <a href={typesUrl}><code>Agent[]</code></a> | --- ### Bilježenje -| Metoda | Putanja | Opis | Odgovor | -| ------ | ------- | ------------------------------------------------------------ | --------- | -| `POST` | `/log` | Write log entry. Body: `{ service, level, message, extra? }` | `boolean` | +| Metoda | Putanja | Opis | Odgovor | +| ------ | ------- | ------------------------------------------------------------------- | --------- | +| `POST` | `/log` | Upiši zapis dnevnika. Tijelo: `{ service, level, message, extra? }` | `boolean` | --- ### TUI -| Metoda | Putanja | Opis | Odgovor | -| ------ | ----------------------- | ------------------------------------------- | ---------------------- | -| `POST` | `/tui/append-prompt` | Append text to the prompt | `boolean` | -| `POST` | `/tui/open-help` | Open the help dialog | `boolean` | -| `POST` | `/tui/open-sessions` | Open the session selector | `boolean` | -| `POST` | `/tui/open-themes` | Open the theme selector | `boolean` | -| `POST` | `/tui/open-models` | Open the model selector | `boolean` | -| `POST` | `/tui/submit-prompt` | Submit the current prompt | `boolean` | -| `POST` | `/tui/clear-prompt` | Clear the prompt | `boolean` | -| `POST` | `/tui/execute-command` | Execute a command (`{ command }`) | `boolean` | -| `POST` | `/tui/show-toast` | Show toast (`{ title?, message, variant }`) | `boolean` | -| `GET` | `/tui/control/next` | Wait for the next control request | Control request object | -| `POST` | `/tui/control/response` | Respond to a control request (`{ body }`) | `boolean` | +| Metoda | Putanja | Opis | Odgovor | +| ------ | ----------------------- | -------------------------------------------------------- | ---------------------- | +| `POST` | `/tui/append-prompt` | Dodaj tekst na prompt | `boolean` | +| `POST` | `/tui/open-help` | Otvori dijalog za pomoć | `boolean` | +| `POST` | `/tui/open-sessions` | Otvori selektor sesija | `boolean` | +| `POST` | `/tui/open-themes` | Otvori selektor tema | `boolean` | +| `POST` | `/tui/open-models` | Otvori selektor modela | `boolean` | +| `POST` | `/tui/submit-prompt` | Pošalji trenutni prompt | `boolean` | +| `POST` | `/tui/clear-prompt` | Očisti prompt | `boolean` | +| `POST` | `/tui/execute-command` | Izvrši naredbu (`{ command }`) | `boolean` | +| `POST` | `/tui/show-toast` | Prikaži toast obavijest (`{ title?, message, variant }`) | `boolean` | +| `GET` | `/tui/control/next` | Čekaj sljedeći kontrolni zahtjev | Control request object | +| `POST` | `/tui/control/response` | Odgovori na kontrolni zahtjev (`{ body }`) | `boolean` | --- ### Autentifikacija -| Metoda | Putanja | Opis | Odgovor | -| ------ | ----------- | --------------------------------------------------------------- | --------- | -| `PUT` | `/auth/:id` | Set authentication credentials. Body must match provider schema | `boolean` | +| Metoda | Putanja | Opis | Odgovor | +| ------ | ----------- | ------------------------------------------------------------------------------- | --------- | +| `PUT` | `/auth/:id` | Postavi autentifikacijske vjerodajnice. Tijelo mora odgovarati shemi provajdera | `boolean` | --- ### Događaji -| Metoda | Putanja | Opis | Odgovor | -| ------ | -------- | ----------------------------------------------------------------------------- | ------------------------- | -| `GET` | `/event` | Server-sent events stream. First event is `server.connected`, then bus events | Server-sent events stream | +| Metoda | Putanja | Opis | Odgovor | +| ------ | -------- | -------------------------------------------------------------------------------------- | ------------------------- | +| `GET` | `/event` | Tok događaja koje šalje server. Prvi događaj je `server.connected`, zatim bus događaji | Server-sent events stream | --- ### Dokumentacija -| Metoda | Putanja | Opis | Odgovor | -| ------ | ------- | ------------------------- | --------------------------- | -| `GET` | `/doc` | OpenAPI 3.1 specification | HTML page with OpenAPI spec | +| Metoda | Putanja | Opis | Odgovor | +| ------ | ------- | ------------------------- | --------------------------------------- | +| `GET` | `/doc` | OpenAPI 3.1 specifikacija | HTML stranica sa OpenAPI specifikacijom | diff --git a/packages/web/src/content/docs/bs/share.mdx b/packages/web/src/content/docs/bs/share.mdx index a15e150743..b0760ee0c1 100644 --- a/packages/web/src/content/docs/bs/share.mdx +++ b/packages/web/src/content/docs/bs/share.mdx @@ -41,7 +41,7 @@ Da eksplicitno postavite rucni nacin u [config datoteci](/docs/config): ```json title="opencode.json" { - "$schema": "https://opncd.ai/config.json", + "$schema": "https://opencode.ai/config.json", "share": "manual" } ``` @@ -54,7 +54,7 @@ Mozete ukljuciti automatsko dijeljenje za sve nove razgovore tako sto `share` po ```json title="opencode.json" { - "$schema": "https://opncd.ai/config.json", + "$schema": "https://opencode.ai/config.json", "share": "auto" } ``` @@ -69,7 +69,7 @@ Dijeljenje mozete potpuno iskljuciti tako sto `share` postavite na `"disabled"` ```json title="opencode.json" { - "$schema": "https://opncd.ai/config.json", + "$schema": "https://opencode.ai/config.json", "share": "disabled" } ``` diff --git a/packages/web/src/content/docs/bs/themes.mdx b/packages/web/src/content/docs/bs/themes.mdx index a513e5a209..edb17e6fa4 100644 --- a/packages/web/src/content/docs/bs/themes.mdx +++ b/packages/web/src/content/docs/bs/themes.mdx @@ -61,11 +61,11 @@ System tema je za korisnike koji: ## Korištenje teme -Temu mozete izabrati preko selektora tema komandom `/theme`. Mozete je navesti i u [configu](/docs/config). +Temu mozete izabrati preko selektora tema komandom `/theme`. Ili je možete navesti u `tui.json`. -```json title="opencode.json" {3} +```json title="tui.json" {3} { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "theme": "tokyonight" } ``` diff --git a/packages/web/src/content/docs/bs/tui.mdx b/packages/web/src/content/docs/bs/tui.mdx index 96b075aa13..ef09a4caa0 100644 --- a/packages/web/src/content/docs/bs/tui.mdx +++ b/packages/web/src/content/docs/bs/tui.mdx @@ -235,7 +235,7 @@ Podijelite trenutnu sesiju. [Saznajte više](/docs/share). Navedite dostupne teme. ```bash frame="none" -/theme +/themes ``` **Tastatura:** `ctrl+x t` @@ -358,24 +358,34 @@ Nekim uređivačima su potrebni argumenti komandne linije da bi se pokrenuli u n ## Konfiguracija -Možete prilagoditi TUI ponašanje putem vašeg OpenCode konfiguracionog fajla. +Možete prilagoditi TUI ponašanje putem `tui.json` (ili `tui.jsonc`). -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", - "tui": { - "scroll_speed": 3, - "scroll_acceleration": { - "enabled": true - } - } + "$schema": "https://opencode.ai/tui.json", + "theme": "opencode", + "keybinds": { + "leader": "ctrl+x" + }, + "scroll_speed": 3, + "scroll_acceleration": { + "enabled": true + }, + "diff_style": "auto" } ``` +Ovo je odvojeno od `opencode.json`, koji konfiguriše ponašanje servera/izvršavanja. + ### Opcije -- `scroll_acceleration` - ​​Omogućite ubrzanje pomicanja u macOS stilu za glatko, prirodno pomicanje. Kada je omogućeno, brzina pomicanja se povećava brzim pokretima pomicanja i ostaje precizna za sporije pokrete. **Ova postavka ima prednost nad `scroll_speed` i nadjačava je kada je omogućena.** -- `scroll_speed` - ​​Kontrolira koliko brzo TUI skroluje kada se koriste komande za pomeranje (minimalno: `1`). Podrazumevano je `3`. **Napomena: Ovo se zanemaruje ako je `scroll_acceleration.enabled` postavljeno na `true`.** +- `theme` - Postavlja vašu UI temu. [Saznajte više](/docs/themes). +- `keybinds` - Prilagođava prečice na tastaturi. [Saznajte više](/docs/keybinds). +- `scroll_acceleration.enabled` - ​​Omogućite ubrzanje pomicanja u macOS stilu za glatko, prirodno pomicanje. Kada je omogućeno, brzina pomicanja se povećava brzim pokretima pomicanja i ostaje precizna za sporije pokrete. **Ova postavka ima prednost nad `scroll_speed` i nadjačava je kada je omogućena.** +- `scroll_speed` - ​​Kontrolira koliko brzo TUI skroluje kada se koriste komande za pomeranje (minimum: `0.001`, podržava decimalne vrijednosti). Podrazumevano je `3`. **Napomena: Ovo se zanemaruje ako je `scroll_acceleration.enabled` postavljeno na `true`.** +- `diff_style` - Kontrolira prikazivanje razlike. `"auto"` se prilagođava širini terminala, `"stacked"` uvijek prikazuje raspored u jednoj koloni. + +Koristite `OPENCODE_TUI_CONFIG` da učitate prilagođenu putanju TUI konfiguracije. --- diff --git a/packages/web/src/content/docs/bs/zen.mdx b/packages/web/src/content/docs/bs/zen.mdx index f973337086..8da6697d09 100644 --- a/packages/web/src/content/docs/bs/zen.mdx +++ b/packages/web/src/content/docs/bs/zen.mdx @@ -55,6 +55,8 @@ Nasim modelima mozete pristupiti i preko sljedecih API endpointa. | Model | Model ID | Endpoint | AI SDK Package | | ------------------ | ------------------ | -------------------------------------------------- | --------------------------- | +| GPT 5.4 | gpt-5.4 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| GPT 5.3 Codex | gpt-5.3-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.2 | gpt-5.2 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.2 Codex | gpt-5.2-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.1 | gpt-5.1 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | @@ -64,22 +66,24 @@ Nasim modelima mozete pristupiti i preko sljedecih API endpointa. | GPT 5 | gpt-5 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5 Codex | gpt-5-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5 Nano | gpt-5-nano | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| Claude Opus 4.6 | claude-opus-4-6 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Opus 4.5 | claude-opus-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Opus 4.1 | claude-opus-4-1 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Sonnet 4.6 | claude-sonnet-4-6 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Sonnet 4.5 | claude-sonnet-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Sonnet 4 | claude-sonnet-4 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Haiku 4.5 | claude-haiku-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Haiku 3.5 | claude-3-5-haiku | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| Claude Opus 4.6 | claude-opus-4-6 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| Claude Opus 4.5 | claude-opus-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| Claude Opus 4.1 | claude-opus-4-1 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Gemini 3.1 Pro | gemini-3.1-pro | `https://opencode.ai/zen/v1/models/gemini-3.1-pro` | `@ai-sdk/google` | | Gemini 3 Pro | gemini-3-pro | `https://opencode.ai/zen/v1/models/gemini-3-pro` | `@ai-sdk/google` | | Gemini 3 Flash | gemini-3-flash | `https://opencode.ai/zen/v1/models/gemini-3-flash` | `@ai-sdk/google` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.5 Free | minimax-m2.5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.1 | minimax-m2.1 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.1 Free | minimax-m2.1-free | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| GLM 5 | glm-5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | GLM 4.7 | glm-4.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM 4.7 Free | glm-4.7-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | GLM 4.6 | glm-4.6 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 Free | kimi-k2.5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2 Thinking | kimi-k2-thinking | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2 | kimi-k2 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Qwen3 Coder 480B | qwen3-coder | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -106,29 +110,35 @@ Podrzavamo pay-as-you-go model. Ispod su cijene **po 1M tokena**. | Model | Input | Output | Cached Read | Cached Write | | --------------------------------- | ------ | ------ | ----------- | ------------ | | Big Pickle | Free | Free | Free | - | -| MiniMax M2.1 Free | Free | Free | Free | - | +| MiniMax M2.5 Free | Free | Free | Free | - | +| MiniMax M2.5 | $0.30 | $1.20 | $0.06 | - | | MiniMax M2.1 | $0.30 | $1.20 | $0.10 | - | -| GLM 4.7 Free | Free | Free | Free | - | +| GLM 5 | $1.00 | $3.20 | $0.20 | - | | GLM 4.7 | $0.60 | $2.20 | $0.10 | - | | GLM 4.6 | $0.60 | $2.20 | $0.10 | - | -| Kimi K2.5 Free | Free | Free | Free | - | | Kimi K2.5 | $0.60 | $3.00 | $0.08 | - | | Kimi K2 Thinking | $0.40 | $2.50 | - | - | | Kimi K2 | $0.40 | $2.50 | - | - | | Qwen3 Coder 480B | $0.45 | $1.50 | - | - | +| Claude Opus 4.6 (≤ 200K tokens) | $5.00 | $25.00 | $0.50 | $6.25 | +| Claude Opus 4.6 (> 200K tokens) | $10.00 | $37.50 | $1.00 | $12.50 | +| Claude Opus 4.5 | $5.00 | $25.00 | $0.50 | $6.25 | +| Claude Opus 4.1 | $15.00 | $75.00 | $1.50 | $18.75 | +| Claude Sonnet 4.6 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 | +| Claude Sonnet 4.6 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 | | Claude Sonnet 4.5 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 | | Claude Sonnet 4.5 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 | | Claude Sonnet 4 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 | | Claude Sonnet 4 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 | | Claude Haiku 4.5 | $1.00 | $5.00 | $0.10 | $1.25 | | Claude Haiku 3.5 | $0.80 | $4.00 | $0.08 | $1.00 | -| Claude Opus 4.6 (≤ 200K tokens) | $5.00 | $25.00 | $0.50 | $6.25 | -| Claude Opus 4.6 (> 200K tokens) | $10.00 | $37.50 | $1.00 | $12.50 | -| Claude Opus 4.5 | $5.00 | $25.00 | $0.50 | $6.25 | -| Claude Opus 4.1 | $15.00 | $75.00 | $1.50 | $18.75 | +| Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | +| Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | | Gemini 3 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | +| GPT 5.4 | $2.50 | $15.00 | $0.25 | - | +| GPT 5.3 Codex | $1.75 | $14.00 | $0.175 | - | | GPT 5.2 | $1.75 | $14.00 | $0.175 | - | | GPT 5.2 Codex | $1.75 | $14.00 | $0.175 | - | | GPT 5.1 | $1.07 | $8.50 | $0.107 | - | @@ -147,10 +157,8 @@ Naknade kartica se prenose po stvarnom trosku (4.4% + $0.30 po transakciji) i ne Besplatni modeli: -- GLM 4.7 Free je dostupan na OpenCode ograniceno vrijeme. Tim koristi taj period za prikupljanje feedbacka i unapredenje modela. -- Kimi K2.5 Free je dostupan na OpenCode ograniceno vrijeme. Tim koristi taj period za prikupljanje feedbacka i unapredenje modela. -- MiniMax M2.1 Free je dostupan na OpenCode ograniceno vrijeme. Tim koristi taj period za prikupljanje feedbacka i unapredenje modela. -- Big Pickle je stealth model koji je besplatan na OpenCode ograniceno vrijeme. Tim koristi taj period za prikupljanje feedbacka i unapredenje modela. +- MiniMax M2.5 Free je dostupan na OpenCode ograniceno vrijeme. Tim koristi taj period za prikupljanje povratnih informacija i poboljsanje modela. +- Big Pickle je stealth model koji je besplatan na OpenCode ograniceno vrijeme. Tim koristi taj period za prikupljanje povratnih informacija i poboljsanje modela. Ako imate pitanja, <a href={email}>kontaktirajte nas</a>. @@ -172,16 +180,27 @@ Na primjer, ako postavite mjesecni limit na $20, Zen nece potrositi vise od $20 --- +### Zastarjeli modeli + +| Model | Datum ukidanja | +| ---------------- | -------------- | +| Qwen3 Coder 480B | 6. feb. 2026. | +| Kimi K2 Thinking | 6. mart 2026. | +| Kimi K2 | 6. mart 2026. | +| MiniMax M2.1 | 15. mart 2026. | +| GLM 4.7 | 15. mart 2026. | +| GLM 4.6 | 15. mart 2026. | + +--- + ## Privatnost Svi nasi modeli su hostovani u SAD-u. Provajderi prate zero-retention politiku i ne koriste vase podatke za treniranje modela, uz sljedece izuzetke: - Big Pickle: Tokom besplatnog perioda, prikupljeni podaci mogu se koristiti za poboljsanje modela. -- GLM 4.7 Free: Tokom besplatnog perioda, prikupljeni podaci mogu se koristiti za poboljsanje modela. -- Kimi K2.5 Free: Tokom besplatnog perioda, prikupljeni podaci mogu se koristiti za poboljsanje modela. -- MiniMax M2.1 Free: Tokom besplatnog perioda, prikupljeni podaci mogu se koristiti za poboljsanje modela. -- OpenAI API-ji: Zahtjevi se cuvaju 30 dana prema [OpenAI Data Policies](https://platform.openai.com/docs/guides/your-data). -- Anthropic API-ji: Zahtjevi se cuvaju 30 dana prema [Anthropic Data Policies](https://docs.anthropic.com/en/docs/claude-code/data-usage). +- MiniMax M2.5 Free: Tokom besplatnog perioda, prikupljeni podaci mogu se koristiti za poboljsanje modela. +- OpenAI API-ji: Zahtjevi se cuvaju 30 dana prema [OpenAI's Data Policies](https://platform.openai.com/docs/guides/your-data). +- Anthropic API-ji: Zahtjevi se cuvaju 30 dana prema [Anthropic's Data Policies](https://docs.anthropic.com/en/docs/claude-code/data-usage). --- diff --git a/packages/web/src/content/docs/cli.mdx b/packages/web/src/content/docs/cli.mdx index c504f734fa..6b1c3dee57 100644 --- a/packages/web/src/content/docs/cli.mdx +++ b/packages/web/src/content/docs/cli.mdx @@ -558,6 +558,7 @@ OpenCode can be configured using environment variables. | `OPENCODE_AUTO_SHARE` | boolean | Automatically share sessions | | `OPENCODE_GIT_BASH_PATH` | string | Path to Git Bash executable on Windows | | `OPENCODE_CONFIG` | string | Path to config file | +| `OPENCODE_TUI_CONFIG` | string | Path to TUI config file | | `OPENCODE_CONFIG_DIR` | string | Path to config directory | | `OPENCODE_CONFIG_CONTENT` | string | Inline json config content | | `OPENCODE_DISABLE_AUTOUPDATE` | boolean | Disable automatic update checks | diff --git a/packages/web/src/content/docs/config.mdx b/packages/web/src/content/docs/config.mdx index eeccde2f79..038f253274 100644 --- a/packages/web/src/content/docs/config.mdx +++ b/packages/web/src/content/docs/config.mdx @@ -14,10 +14,11 @@ OpenCode supports both **JSON** and **JSONC** (JSON with Comments) formats. ```jsonc title="opencode.jsonc" { "$schema": "https://opencode.ai/config.json", - // Theme configuration - "theme": "opencode", "model": "anthropic/claude-sonnet-4-5", "autoupdate": true, + "server": { + "port": 4096, + }, } ``` @@ -34,7 +35,7 @@ Configuration files are **merged together**, not replaced. Configuration files are merged together, not replaced. Settings from the following config locations are combined. Later configs override earlier ones only for conflicting keys. Non-conflicting settings from all configs are preserved. -For example, if your global config sets `theme: "opencode"` and `autoupdate: true`, and your project config sets `model: "anthropic/claude-sonnet-4-5"`, the final configuration will include all three settings. +For example, if your global config sets `autoupdate: true` and your project config sets `model: "anthropic/claude-sonnet-4-5"`, the final configuration will include both settings. --- @@ -95,7 +96,9 @@ You can enable specific servers in your local config: ### Global -Place your global OpenCode config in `~/.config/opencode/opencode.json`. Use global config for user-wide preferences like themes, providers, or keybinds. +Place your global OpenCode config in `~/.config/opencode/opencode.json`. Use global config for user-wide server/runtime preferences like providers, models, and permissions. + +For TUI-specific settings, use `~/.config/opencode/tui.json`. Global config overrides remote organizational defaults. @@ -105,6 +108,8 @@ Global config overrides remote organizational defaults. Add `opencode.json` in your project root. Project config has the highest precedence among standard config files - it overrides both global and remote configs. +For project-specific TUI settings, add `tui.json` alongside it. + :::tip Place project specific config in the root of your project. ::: @@ -146,7 +151,9 @@ The custom directory is loaded after the global config and `.opencode` directori ## Schema -The config file has a schema that's defined in [**`opencode.ai/config.json`**](https://opencode.ai/config.json). +The server/runtime config schema is defined in [**`opencode.ai/config.json`**](https://opencode.ai/config.json). + +TUI config uses [**`opencode.ai/tui.json`**](https://opencode.ai/tui.json). Your editor should be able to validate and autocomplete based on the schema. @@ -154,28 +161,24 @@ Your editor should be able to validate and autocomplete based on the schema. ### TUI -You can configure TUI-specific settings through the `tui` option. +Use a dedicated `tui.json` (or `tui.jsonc`) file for TUI-specific settings. -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", - "tui": { - "scroll_speed": 3, - "scroll_acceleration": { - "enabled": true - }, - "diff_style": "auto" - } + "$schema": "https://opencode.ai/tui.json", + "scroll_speed": 3, + "scroll_acceleration": { + "enabled": true + }, + "diff_style": "auto" } ``` -Available options: +Use `OPENCODE_TUI_CONFIG` to point to a custom TUI config file. -- `scroll_acceleration.enabled` - Enable macOS-style scroll acceleration. **Takes precedence over `scroll_speed`.** -- `scroll_speed` - Custom scroll speed multiplier (default: `3`, minimum: `1`). Ignored if `scroll_acceleration.enabled` is `true`. -- `diff_style` - Control diff rendering. `"auto"` adapts to terminal width, `"stacked"` always shows single column. +Legacy `theme`, `keybinds`, and `tui` keys in `opencode.json` are deprecated and automatically migrated when possible. -[Learn more about using the TUI here](/docs/tui). +[Learn more about TUI configuration here](/docs/tui#configure). --- @@ -301,12 +304,12 @@ Bearer tokens (`AWS_BEARER_TOKEN_BEDROCK` or `/connect`) take precedence over pr ### Themes -You can configure the theme you want to use in your OpenCode config through the `theme` option. +Set your UI theme in `tui.json`. -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", - "theme": "" + "$schema": "https://opencode.ai/tui.json", + "theme": "tokyonight" } ``` @@ -406,11 +409,11 @@ You can also define commands using markdown files in `~/.config/opencode/command ### Keybinds -You can customize your keybinds through the `keybinds` option. +Customize keybinds in `tui.json`. -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "keybinds": {} } ``` diff --git a/packages/web/src/content/docs/da/cli.mdx b/packages/web/src/content/docs/da/cli.mdx index c29559df26..5eece6fd0a 100644 --- a/packages/web/src/content/docs/da/cli.mdx +++ b/packages/web/src/content/docs/da/cli.mdx @@ -558,6 +558,7 @@ OpenCode kan konfigureres ved hjælp af miljøvariabler. | `OPENCODE_AUTO_SHARE` | boolean | Del automatisk session | | `OPENCODE_GIT_BASH_PATH` | string | Sti til Git Bash eksekverbar på Windows | | `OPENCODE_CONFIG` | string | Sti til konfigurationsfil | +| `OPENCODE_TUI_CONFIG` | string | Sti til TUI-konfigurationsfil | | `OPENCODE_CONFIG_DIR` | string | Sti til konfigurationsmappe | | `OPENCODE_CONFIG_CONTENT` | string | Indbygget json-konfigurationsindhold | | `OPENCODE_DISABLE_AUTOUPDATE` | boolean | Deaktiver automatisk opdateringskontrol | @@ -582,7 +583,7 @@ OpenCode kan konfigureres ved hjælp af miljøvariabler. --- -### Flag +### Eksperimentel Disse miljøvariabler muliggør eksperimentelle funktioner, der kan ændres eller fjernes. diff --git a/packages/web/src/content/docs/da/config.mdx b/packages/web/src/content/docs/da/config.mdx index 5b45f8b048..18b462580b 100644 --- a/packages/web/src/content/docs/da/config.mdx +++ b/packages/web/src/content/docs/da/config.mdx @@ -14,10 +14,11 @@ OpenCode understøtter både **JSON** og **JSONC** (JSON med kommentarer) format ```jsonc title="opencode.jsonc" { "$schema": "https://opencode.ai/config.json", - // Theme configuration - "theme": "opencode", "model": "anthropic/claude-sonnet-4-5", "autoupdate": true, + "server": { + "port": 4096, + }, } ``` @@ -34,7 +35,7 @@ Konfigurationsfiler **flettes sammen**, erstattes ikke. Konfigurationsfiler flettes sammen, erstattes ikke. Indstillinger fra følgende konfigurationssteder kombineret. Senere konfigurationer tilsidesætter kun tidligere konfigurationer for modstridende nøgler. Ikke-modstridende indstillinger fra alle konfigurationer bevares. -For eksempel, hvis dine globale konfigurationssæt `theme: "opencode"` og `autoupdate: true`, og dine projektkonfigurationssæt `model: "anthropic/claude-sonnet-4-5"`, vil den endelige konfiguration integrere alle tre indstillinger. +For eksempel, hvis dine globale konfigurationssæt `autoupdate: true`, og dine projektkonfigurationssæt `model: "anthropic/claude-sonnet-4-5"`, vil den endelige konfiguration integrere begge indstillinger. --- @@ -490,13 +491,15 @@ Du kan styre kontekstkomprimeringsadfærd gennem indstillingen `compaction`. "$schema": "https://opencode.ai/config.json", "compaction": { "auto": true, - "prune": true + "prune": true, + "reserved": 10000 } } ``` - `auto` - Komprimer automatisk sessionen, når konteksten er fuld (standard: `true`). - `prune` - Fjern gamle værktøjsudgange for at gemme tokens (standard: `true`). +- `reserved` - Tokenbuffer til komprimering. Efterlader nok vindue til at undgå overløb under komprimering --- @@ -582,8 +585,8 @@ Du kan deaktivere udbydere, der indlæses automatisk gennem `disabled_providers` Indstillingen `disabled_providers` accepterer en række udbyder-id'er. Når en udbyder er deaktiveret: -- Det vil ikke blive indlæst, omgivelserne miljøvariabler er indstillet. -- Den vil ikke blive indlæst, gennem API-nøgler er konfigureret kommandoen `/connect`. +- Den vil ikke blive indlæst, selvom miljøvariabler er indstillet. +- Den vil ikke blive indlæst, selvom API-nøgler er konfigureret via `/connect`-kommandoen. - Udbyderens modeller vises ikke på modelvalgslisten. --- diff --git a/packages/web/src/content/docs/da/custom-tools.mdx b/packages/web/src/content/docs/da/custom-tools.mdx index b0839b649c..75746dcb49 100644 --- a/packages/web/src/content/docs/da/custom-tools.mdx +++ b/packages/web/src/content/docs/da/custom-tools.mdx @@ -79,6 +79,32 @@ Dette skaber værktøjer: `math_add` og `math_multiply`. --- +#### Navnekollisioner med indbyggede værktøjer + +Brugerdefinerede værktøjer er identificeret ved værktøjsnavn. Hvis et brugerdefineret værktøj bruger samme navn som et indbygget værktøj, har det brugerdefinerede værktøj forrang. + +For eksempel erstatter denne fil det indbyggede `bash` værktøj: + +```ts title=".opencode/tools/bash.ts" +import { tool } from "@opencode-ai/plugin" + +export default tool({ + description: "Restricted bash wrapper", + args: { + command: tool.schema.string(), + }, + async execute(args) { + return `blocked: ${args.command}` + }, +}) +``` + +:::note +Foretræk unikke navne, medmindre du bevidst ønsker at erstatte et indbygget værktøj. Hvis du vil deaktivere et indbygget værktøj, men ikke overskrive det, skal du bruge [tilladelser](/docs/permissions). +::: + +--- + ### Argumenter Du kan bruge `tool.schema`, som kun er [Zod](https://zod.dev), til at definere argumenttyper. diff --git a/packages/web/src/content/docs/da/ecosystem.mdx b/packages/web/src/content/docs/da/ecosystem.mdx index 8da7e42d10..0bba6ecddd 100644 --- a/packages/web/src/content/docs/da/ecosystem.mdx +++ b/packages/web/src/content/docs/da/ecosystem.mdx @@ -15,38 +15,40 @@ Du kan også tjekke [awesome-opencode](https://github.com/awesome-opencode/aweso ## Plugins -| Navn | Beskrivelse | -| --------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | -| [opencode-daytona](https://github.com/jamesmurdza/daytona/blob/main/guides/typescript/opencode/README.md) | Kør automatisk OpenCode-sessioner i isolerede Daytona-sandkasser med git-synkronisering og live forhåndsvisninger | -| [opencode-helicone-session](https://github.com/H2Shami/opencode-helicone-session) | Injicer automatisk Helicone-sessionsoverskrifter til anmodningsgruppering | -| [opencode-type-inject](https://github.com/nick-vi/opencode-type-inject) | Autoinjicer TypeScript/Svelte-typer i fillæsninger med opslagsværktøjer | -| [opencode-openai-codex-auth](https://github.com/numman-ali/opencode-openai-codex-auth) | Brug dit ChatGPT Plus/Pro abonnement i stedet for API kreditter | -| [opencode-gemini-auth](https://github.com/jenslys/opencode-gemini-auth) | Brug din eksisterende Gemini-plan i stedet for API fakturering | -| [opencode-antigravity-auth](https://github.com/NoeFabris/opencode-antigravity-auth) | Brug Antigravitys gratis modeller i stedet for API fakturering | -| [opencode-devcontainers](https://github.com/athal7/opencode-devcontainers) | Multi-branch devcontainer isolation med lavvandede kloner og automatisk tildelte porte | -| [opencode-google-antigravity-auth](https://github.com/shekohex/opencode-google-antigravity-auth) | Google Antigravity OAuth Plugin, med understøttelse af Google søgning og mere robust API håndtering | -| [opencode-dynamic-context-pruning](https://github.com/Tarquinen/opencode-dynamic-context-pruning) | Optimer tokenbrug ved at beskære forældede værktøjsoutput | -| [opencode-websearch-cited](https://github.com/ghoulr/opencode-websearch-cited.git) | Tilføj native websearch-understøttelse for understøttede udbydere med Google jordet stil | -| [opencode-pty](https://github.com/shekohex/opencode-pty.git) | Gør det muligt for AI-agenter at køre baggrundsprocesser i en PTY, send interaktive input til dem. | -| [opencode-shell-strategy](https://github.com/JRedeker/opencode-shell-strategy) | Instruktioner til ikke-interaktive shell-kommandoer - forhindrer hænger fra TTY-afhængige operationer | -| [opencode-wakatime](https://github.com/angristan/opencode-wakatime) | Spor OpenCode brug med Wakatime | -| [opencode-md-table-formatter](https://github.com/franlol/opencode-md-table-formatter/tree/main) | Ryd op afmærkningstabeller produceret af LLMs | -| [opencode-morph-fast-apply](https://github.com/JRedeker/opencode-morph-fast-apply) | 10x hurtigere koderedigering med Morph Fast Apply API og dovne redigeringsmarkører | -| [oh-my-opencode](https://github.com/code-yeongyu/oh-my-opencode) | Baggrundsagenter, præbyggede LSP/AST/MCP værktøjer, kuraterede agenter, Claude Kodekompatibel | -| [opencode-notificator](https://github.com/panta82/opencode-notificator) | Skrivebordsmeddelelser og lydadvarsler for OpenCode-sessioner | -| [opencode-notifier](https://github.com/mohak34/opencode-notifier) | Skrivebordsmeddelelser og lydadvarsler for tilladelser, fuldførelse og fejlhændelser | -| [opencode-zellij-namer](https://github.com/24601/opencode-zellij-namer) | AI-drevet automatisk Zellij-sessionsnavngivning baseret på OpenCode-kontekst | -| [opencode-skillful](https://github.com/zenobi-us/opencode-skillful) | Tillad OpenCode-agenter til dovne load-prompter på efterspørgsel med færdighedsopdagelse og -injektion | -| [opencode-supermemory](https://github.com/supermemoryai/opencode-supermemory) | Vedvarende hukommelse på tværs af sessioner ved hjælp af Supermemory | -| [@plannotator/opencode](https://github.com/backnotprop/plannotator/tree/main/apps/opencode-plugin) | Interaktiv plangennemgang med visuel annotering og private/offline deling | -| [@openspoon/subtask2](https://github.com/spoons-and-mirrors/subtask2) | Udvid opencode /commands til et kraftfuldt orkestreringssystem med granulær flowkontrol | -| [opencode-scheduler](https://github.com/different-ai/opencode-scheduler) | Planlæg tilbagevendende job ved hjælp af launchd (Mac) eller systemd (Linux) med cron-syntaks | -| [micode](https://github.com/vtemian/micode) | Struktureret brainstorm → Plan → Implementer workflow med session kontinuitet | -| [octto](https://github.com/vtemian/octto) | Interaktiv browser-UI til AI-brainstorming med formularer med flere spørgsmål | -| [opencode-background-agents](https://github.com/kdcokenny/opencode-background-agents) | Claude Baggrundsagenter i kodestil med asynkron-delegering og kontekstvedholdenhed | -| [opencode-notify](https://github.com/kdcokenny/opencode-notify) | Native OS-meddelelser for OpenCode – ved, hvornår opgaver er fuldført | -| [opencode-workspace](https://github.com/kdcokenny/opencode-workspace) | Bundled multi-agent orkestreringssele – 16 komponenter, én installation | -| [opencode-worktree](https://github.com/kdcokenny/opencode-worktree) | Nulfriktions git-arbejdstræer for OpenCode | +| Navn | Beskrivelse | +| -------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | +| [opencode-daytona](https://github.com/daytonaio/daytona/tree/main/libs/opencode-plugin) | Kør automatisk OpenCode-sessioner i isolerede Daytona-sandkasser med git-synkronisering og live forhåndsvisninger | +| [opencode-helicone-session](https://github.com/H2Shami/opencode-helicone-session) | Injicer automatisk Helicone-sessionsoverskrifter til anmodningsgruppering | +| [opencode-type-inject](https://github.com/nick-vi/opencode-type-inject) | Autoinjicer TypeScript/Svelte-typer i fillæsninger med opslagsværktøjer | +| [opencode-openai-codex-auth](https://github.com/numman-ali/opencode-openai-codex-auth) | Brug dit ChatGPT Plus/Pro abonnement i stedet for API kreditter | +| [opencode-gemini-auth](https://github.com/jenslys/opencode-gemini-auth) | Brug din eksisterende Gemini-plan i stedet for API fakturering | +| [opencode-antigravity-auth](https://github.com/NoeFabris/opencode-antigravity-auth) | Brug Antigravitys gratis modeller i stedet for API fakturering | +| [opencode-devcontainers](https://github.com/athal7/opencode-devcontainers) | Multi-branch devcontainer isolation med lavvandede kloner og automatisk tildelte porte | +| [opencode-google-antigravity-auth](https://github.com/shekohex/opencode-google-antigravity-auth) | Google Antigravity OAuth Plugin, med understøttelse af Google søgning og mere robust API håndtering | +| [opencode-dynamic-context-pruning](https://github.com/Tarquinen/opencode-dynamic-context-pruning) | Optimer tokenbrug ved at beskære forældede værktøjsoutput | +| [opencode-vibeguard](https://github.com/inkdust2021/opencode-vibeguard) | Masker hemmeligheder/PII til pladsholdere i VibeGuard-stil før LLM-kald; gendan lokalt | +| [opencode-websearch-cited](https://github.com/ghoulr/opencode-websearch-cited.git) | Tilføj native websearch-understøttelse for understøttede udbydere med Google jordet stil | +| [opencode-pty](https://github.com/shekohex/opencode-pty.git) | Gør det muligt for AI-agenter at køre baggrundsprocesser i en PTY, send interaktive input til dem. | +| [opencode-shell-strategy](https://github.com/JRedeker/opencode-shell-strategy) | Instruktioner til ikke-interaktive shell-kommandoer - forhindrer hænger fra TTY-afhængige operationer | +| [opencode-wakatime](https://github.com/angristan/opencode-wakatime) | Spor OpenCode brug med Wakatime | +| [opencode-md-table-formatter](https://github.com/franlol/opencode-md-table-formatter/tree/main) | Ryd op afmærkningstabeller produceret af LLMs | +| [opencode-morph-fast-apply](https://github.com/JRedeker/opencode-morph-fast-apply) | 10x hurtigere koderedigering med Morph Fast Apply API og dovne redigeringsmarkører | +| [oh-my-opencode](https://github.com/code-yeongyu/oh-my-opencode) | Baggrundsagenter, præbyggede LSP/AST/MCP værktøjer, kuraterede agenter, Claude Kodekompatibel | +| [opencode-notificator](https://github.com/panta82/opencode-notificator) | Skrivebordsmeddelelser og lydadvarsler for OpenCode-sessioner | +| [opencode-notifier](https://github.com/mohak34/opencode-notifier) | Skrivebordsmeddelelser og lydadvarsler for tilladelser, fuldførelse og fejlhændelser | +| [opencode-zellij-namer](https://github.com/24601/opencode-zellij-namer) | AI-drevet automatisk Zellij-sessionsnavngivning baseret på OpenCode-kontekst | +| [opencode-skillful](https://github.com/zenobi-us/opencode-skillful) | Tillad OpenCode-agenter til dovne load-prompter på efterspørgsel med færdighedsopdagelse og -injektion | +| [opencode-supermemory](https://github.com/supermemoryai/opencode-supermemory) | Vedvarende hukommelse på tværs af sessioner ved hjælp af Supermemory | +| [@plannotator/opencode](https://github.com/backnotprop/plannotator/tree/main/apps/opencode-plugin) | Interaktiv plangennemgang med visuel annotering og private/offline deling | +| [@openspoon/subtask2](https://github.com/spoons-and-mirrors/subtask2) | Udvid opencode /commands til et kraftfuldt orkestreringssystem med granulær flowkontrol | +| [opencode-scheduler](https://github.com/different-ai/opencode-scheduler) | Planlæg tilbagevendende job ved hjælp af launchd (Mac) eller systemd (Linux) med cron-syntaks | +| [micode](https://github.com/vtemian/micode) | Struktureret brainstorm → Plan → Implementer workflow med session kontinuitet | +| [octto](https://github.com/vtemian/octto) | Interaktiv browser-UI til AI-brainstorming med formularer med flere spørgsmål | +| [opencode-background-agents](https://github.com/kdcokenny/opencode-background-agents) | Claude Baggrundsagenter i kodestil med asynkron-delegering og kontekstvedholdenhed | +| [opencode-notify](https://github.com/kdcokenny/opencode-notify) | Native OS-meddelelser for OpenCode – ved, hvornår opgaver er fuldført | +| [opencode-workspace](https://github.com/kdcokenny/opencode-workspace) | Bundled multi-agent orkestreringssele – 16 komponenter, én installation | +| [opencode-worktree](https://github.com/kdcokenny/opencode-worktree) | Nulfriktions git-arbejdstræer for OpenCode | +| [opencode-sentry-monitor](https://github.com/stolinski/opencode-sentry-monitor) | Spor og fejlfind dine AI-agenter med Sentry AI Monitoring | --- diff --git a/packages/web/src/content/docs/da/go.mdx b/packages/web/src/content/docs/da/go.mdx new file mode 100644 index 0000000000..4d6ca61acc --- /dev/null +++ b/packages/web/src/content/docs/da/go.mdx @@ -0,0 +1,145 @@ +--- +title: Go +description: Lavprisabonnement for åbne kodningsmodeller. +--- + +import config from "../../../../config.mjs" +export const console = config.console +export const email = `mailto:${config.email}` + +OpenCode Go er et billigt **$10/måned** abonnement, der giver dig pålidelig adgang til populære åbne kodningsmodeller. + +:::note +OpenCode Go er i øjeblikket i beta. +::: + +Go fungerer ligesom enhver anden udbyder i OpenCode. Du abonnerer på OpenCode Go og får din API-nøgle. Det er **helt valgfrit**, og du behøver ikke at bruge det for at bruge OpenCode. + +Det er primært designet til internationale brugere, med modeller hostet i USA, EU og Singapore for stabil global adgang. + +--- + +## Baggrund + +Åbne modeller er blevet virkelig gode. De når nu en ydeevne tæt på proprietære modeller til kodningsopgaver. Og fordi mange udbydere kan tilbyde dem konkurrencedygtigt, er de normalt langt billigere. + +Det kan dog være svært at få pålidelig adgang med lav latenstid til dem. Udbydere varierer i kvalitet og tilgængelighed. + +:::tip +Vi testede en udvalgt gruppe af modeller og udbydere, der fungerer godt med OpenCode. +::: + +For at løse dette gjorde vi et par ting: + +1. Vi testede en udvalgt gruppe af åbne modeller og talte med deres teams om, hvordan man bedst kører dem. +2. Vi arbejdede derefter sammen med nogle få udbydere for at sikre, at disse blev leveret korrekt. +3. Endelig benchmarkede vi kombinationen af model/udbyder og kom frem til en liste, som vi har det godt med at anbefale. + +OpenCode Go giver dig adgang til disse modeller for **$10/måned**. + +--- + +## Sådan fungerer det + +OpenCode Go fungerer ligesom enhver anden udbyder i OpenCode. + +1. Du logger ind på **<a href={console}>OpenCode Zen</a>**, abonnerer på Go, og kopierer din API-nøgle. +2. Du kører kommandoen `/connect` i TUI'en, vælger `OpenCode Go`, og indsætter din API-nøgle. +3. Kør `/models` i TUI'en for at se listen over modeller, der er tilgængelige gennem Go. + +:::note +Kun ét medlem pr. workspace kan abonnere på OpenCode Go. +::: + +Den nuværende liste over modeller inkluderer: + +- **GLM-5** +- **Kimi K2.5** +- **MiniMax M2.5** + +Listen over modeller kan ændre sig, efterhånden som vi tester og tilføjer nye. + +--- + +## Forbrugsgrænser + +OpenCode Go inkluderer følgende grænser: + +- **5 timers grænse** — $12 forbrug +- **Ugentlig grænse** — $30 forbrug +- **Månedlig grænse** — $60 forbrug + +Grænser er defineret i dollarværdi. Det betyder, at dit faktiske antal forespørgsler afhænger af den model, du bruger. Billigere modeller som MiniMax M2.5 tillader flere forespørgsler, mens dyrere modeller som GLM-5 tillader færre. + +Tabellen nedenfor giver et estimeret antal forespørgsler baseret på typiske Go-brugsmønstre: + +| | GLM-5 | Kimi K2.5 | MiniMax M2.5 | +| ------------------------- | ----- | --------- | ------------ | +| forespørgsler pr. 5 timer | 1.150 | 1.850 | 30.000 | +| forespørgsler pr. uge | 2.880 | 4.630 | 75.000 | +| forespørgsler pr. måned | 5.750 | 9.250 | 150.000 | + +Estimater er baseret på observerede gennemsnitlige forespørgselsmønstre: + +- GLM-5 — 700 input, 52.000 cached, 150 output tokens pr. forespørgsel +- Kimi K2.5 — 870 input, 55.000 cached, 200 output tokens pr. forespørgsel +- MiniMax M2.5 — 300 input, 55.000 cached, 125 output tokens pr. forespørgsel + +Du kan spore dit nuværende forbrug i **<a href={console}>konsollen</a>**. + +:::tip +Hvis du når forbrugsgrænsen, kan du fortsætte med at bruge de gratis modeller. +::: + +Forbrugsgrænser kan ændre sig, efterhånden som vi lærer fra tidlig brug og feedback. + +--- + +### Priser + +OpenCode Go er en **$10/måned** abonnementsplan. Nedenfor er priserne **pr. 1M tokens**. + +| Model | Input | Output | Cached Læsning | +| ------------ | ----- | ------ | -------------- | +| GLM-5 | $1,00 | $3,20 | $0,20 | +| Kimi K2.5 | $0,60 | $3,00 | $0,10 | +| MiniMax M2.5 | $0,30 | $1,20 | $0,03 | + +--- + +### Forbrug ud over grænser + +Hvis du også har kreditter på din Zen-saldo, kan du aktivere **Brug saldo**-indstillingen i konsollen. Når den er aktiveret, vil Go falde tilbage på din Zen-saldo, efter du har nået dine forbrugsgrænser, i stedet for at blokere forespørgsler. + +--- + +## Endepunkter + +Du kan også få adgang til Go-modeller gennem følgende API-endepunkter. + +| Model | Model ID | Endpoint | AI SDK Pakke | +| ------------ | ------------ | ------------------------------------------------ | --------------------------- | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | + +[Model-id'et](/docs/config/#models) i din OpenCode-konfiguration bruger formatet `opencode-go/<model-id>`. For eksempel, for Kimi K2.5, ville du bruge `opencode-go/kimi-k2.5` i din konfiguration. + +--- + +## Privatliv + +Planen er primært designet til internationale brugere, med modeller hostet i USA, EU og Singapore for stabil global adgang. + +<a href={email}>Kontakt os</a> hvis du har spørgsmål. + +--- + +## Mål + +Vi skabte OpenCode Go for at: + +1. Gøre AI-kodning **tilgængelig** for flere mennesker med et billigt abonnement. +2. Tilbyde **pålidelig** adgang til de bedste åbne kodningsmodeller. +3. Udvælge modeller, der er **testet og benchmarked** til brug med kodningsagenter. +4. Have **ingen lock-in** ved at tillade dig også at bruge enhver anden udbyder med OpenCode. diff --git a/packages/web/src/content/docs/da/keybinds.mdx b/packages/web/src/content/docs/da/keybinds.mdx index 2da3ff9426..237c36f775 100644 --- a/packages/web/src/content/docs/da/keybinds.mdx +++ b/packages/web/src/content/docs/da/keybinds.mdx @@ -3,11 +3,11 @@ title: Tastebindinger description: Tilpas dine nøglebindinger. --- -OpenCode har en liste over nøglebindinger, som du kan tilpasse gennem OpenCode-konfigurationen. +OpenCode har en liste over nøglebindinger, som du kan tilpasse gennem `tui.json`. -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "keybinds": { "leader": "ctrl+x", "app_exit": "ctrl+c,ctrl+d,<leader>q", @@ -28,6 +28,7 @@ OpenCode har en liste over nøglebindinger, som du kan tilpasse gennem OpenCode- "session_unshare": "none", "session_interrupt": "escape", "session_compact": "<leader>c", + "session_child_first": "<leader>down", "session_child_cycle": "<leader>right", "session_child_cycle_reverse": "<leader>left", "session_parent": "<leader>up", @@ -117,11 +118,11 @@ Du behøver ikke bruge en ledernøgle til dine nøglebindinger, men vi anbefaler ## Deaktiver tastebinding -Du kan deaktivere en nøglebinding ved at tilføje nøglen til din konfiguration med værdien "ingen". +Du kan deaktivere en nøglebinding ved at tilføje nøglen til `tui.json` med værdien "none". -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "keybinds": { "session_compact": "none" } diff --git a/packages/web/src/content/docs/da/lsp.mdx b/packages/web/src/content/docs/da/lsp.mdx index b0e0d35372..27d43b192b 100644 --- a/packages/web/src/content/docs/da/lsp.mdx +++ b/packages/web/src/content/docs/da/lsp.mdx @@ -20,13 +20,14 @@ OpenCode leveres med flere indbyggede LSP-servere til populære sprog: | clojure-lsp | .clj,.cljs,.cljc,.edn | `clojure-lsp` kommando tilgængelig | | dart | .dart | `dart` kommando tilgængelig | | deno | .ts,.tsx,.js,.jsx,.mjs | `deno` kommando tilgængelig (auto-detects deno.json/deno.jsonc) | -| eliksir-ls | .ex,.exs | `elixir` kommando tilgængelig | +| elixir-ls | .ex,.exs | `elixir` kommando tilgængelig | | eslint | .ts,.tsx,.js,.jsx,.mjs,.cjs,.mts,.cts,.vue | `eslint` afhængighed i projekt | | fsharp | .fs,.fsi,.fsx,.fsscript | `.NET SDK` installere | | gleam | .gleam | `gleam` kommando tilgængelig | | gopls | .go | `go` kommando tilgængelig | | hls | .hs,.lhs | `haskell-language-server-wrapper` kommando tilgængelig | | jdtls | .java | `Java SDK (version 21+)` installere | +| julials | .jl | `julia` og `LanguageServer.jl` installeret | | kotlin-ls | .kt,.kts | Autoinstallationer til Kotlin-projekter | | lua-ls | .lua | Autoinstallationer til Lua-projekter | | nixd | .nix | `nixd` kommando tilgængelig | @@ -46,7 +47,7 @@ OpenCode leveres med flere indbyggede LSP-servere til populære sprog: | yaml-ls | .yaml,.yml | Autoinstallerer Red Hat yaml-language-server | | zls | .zig,.zon | `zig` kommando tilgængelig | -LSP-servere aktiveres automatisk, når en af ​​ovnstående filtypenavne opdages, og kravene er opfyldt. +LSP-servere aktiveres automatisk, når en af ​​ovenstående filtypenavne opdages, og kravene er opfyldt. :::note Du kan deaktivere automatisk LSP-serverdownloads ved at indstille miljøvariablen `OPENCODE_DISABLE_LSP_DOWNLOAD` til `true`. diff --git a/packages/web/src/content/docs/da/plugins.mdx b/packages/web/src/content/docs/da/plugins.mdx index a8532d599c..908c6e1111 100644 --- a/packages/web/src/content/docs/da/plugins.mdx +++ b/packages/web/src/content/docs/da/plugins.mdx @@ -119,7 +119,7 @@ Plugin-funktionen modtager: - `directory`: Den aktuelle arbejdsmappe. - `worktree`: Git worktree-stien. - `client`: En opencode SDK klient til interaktion med AI. -- `-: Buns [shell API](https://bun.com/docs/runtime/shell) til udførelse af kommandoer. +- `$`: Buns [shell API](https://bun.com/docs/runtime/shell) til udførelse af kommandoer. --- @@ -308,6 +308,10 @@ export const CustomToolsPlugin: Plugin = async (ctx) => { Dine tilpassede værktøjer vil være tilgængelige for opencode sammen med indbyggede værktøjer. +:::note +Hvis et plugin-værktøj bruger samme navn som et indbygget værktøj, har plugin-værktøjet forrang. +::: + --- ### Logning diff --git a/packages/web/src/content/docs/da/providers.mdx b/packages/web/src/content/docs/da/providers.mdx index 829ae46134..c5cfe23fa8 100644 --- a/packages/web/src/content/docs/da/providers.mdx +++ b/packages/web/src/content/docs/da/providers.mdx @@ -81,6 +81,37 @@ Det fungerer som alle andre udbydere i OpenCode og er helt valgfrit at bruge. --- +## OpenCode Go + +OpenCode Go er en billig abonnementsplan, der giver pålidelig adgang til populære åbne kodningsmodeller leveret af OpenCode-teamet, som er testet og verificeret til at fungere godt med OpenCode. + +1. Kør kommandoen `/connect` i TUI, vælg `OpenCode Go`, og gå til [opencode.ai/auth](https://opencode.ai/zen). + + ```txt + /connect + ``` + +2. Log ind, tilføj dine faktureringsoplysninger og kopier din API-nøgle. + +3. Indsæt din API-nøgle. + + ```txt + ┌ API key + │ + │ + └ enter + ``` + +4. Kør `/models` i TUI for at se listen over modeller, vi anbefaler. + + ```txt + /models + ``` + +Det fungerer som alle andre udbydere i OpenCode og er helt valgfrit at bruge. + +--- + ## Katalog Lad os se på nogle af udbyderne i detaljer. Hvis du vil tilføje en udbyder til listen, er du velkommen til at åbne en PR. @@ -1474,6 +1505,39 @@ SAP AI Core giver adgang til 40+ modeller fra OpenAI, Anthropic, Google, Amazon, --- +### STACKIT + +STACKIT AI Model Serving leverer fuldt administreret suverænt hostingmiljø til AI-modeller, med fokus på LLM'er som Llama, Mistral og Qwen, med maksimal datasuverænitet på europæisk infrastruktur. + +1. Gå til [STACKIT Portal](https://portal.stackit.cloud), naviger til **AI Model Serving**, og opret en auth-token til dit projekt. + + :::tip + Du skal have en STACKIT-kundekonto, brugerkonto og projekt, før du opretter auth-tokens. + ::: + +2. Kør kommandoen `/connect` og søg efter **STACKIT**. + + ```txt + /connect + ``` + +3. Indtast din STACKIT AI Model Serving auth-token. + + ```txt + ┌ API key + │ + │ + └ enter + ``` + +4. Kør kommandoen `/models` for at vælge fra tilgængelige modeller som _Qwen3-VL 235B_ eller _Llama 3.3 70B_. + + ```txt + /models + ``` + +--- + ### OVHcloud AI Endpoints 1. Gå til [OVHcloud-panelet](https://ovh.com/manager). Naviger til `Public Cloud`-delen, `AI & Machine Learning` > `AI Endpoints` og i `API Keys`-fanen klikker du på **Opret en ny API-nøgle**. diff --git a/packages/web/src/content/docs/da/sdk.mdx b/packages/web/src/content/docs/da/sdk.mdx index 3feff27b3b..cde874d5a2 100644 --- a/packages/web/src/content/docs/da/sdk.mdx +++ b/packages/web/src/content/docs/da/sdk.mdx @@ -117,6 +117,78 @@ try { --- +## Struktureret output + +Du kan anmode om struktureret JSON-output fra modellen ved at angive et `format` med et JSON-skema. Modellen vil bruge et `StructuredOutput`-værktøj til at returnere valideret JSON, der matcher dit skema. + +### Grundlæggende brug + +```typescript +const result = await client.session.prompt({ + path: { id: sessionId }, + body: { + parts: [{ type: "text", text: "Research Anthropic and provide company info" }], + format: { + type: "json_schema", + schema: { + type: "object", + properties: { + company: { type: "string", description: "Company name" }, + founded: { type: "number", description: "Year founded" }, + products: { + type: "array", + items: { type: "string" }, + description: "Main products", + }, + }, + required: ["company", "founded"], + }, + }, + }, +}) + +// Access the structured output +console.log(result.data.info.structured_output) +// { company: "Anthropic", founded: 2021, products: ["Claude", "Claude API"] } +``` + +### Outputformat-typer + +| Type | Beskrivelse | +| ------------- | -------------------------------------------------------- | +| `text` | Standard. Standard tekstsvar (intet struktureret output) | +| `json_schema` | Returnerer valideret JSON, der matcher det angivne skema | + +### JSON-skemaformat + +Når du bruger `type: 'json_schema'`, skal du angive: + +| Felt | Type | Beskrivelse | +| ------------ | --------------- | ---------------------------------------------------------- | +| `type` | `'json_schema'` | Påkrævet. Angiver JSON-skematilstand | +| `schema` | `object` | Påkrævet. JSON-skemaobjekt, der definerer outputstrukturen | +| `retryCount` | `number` | Valgfri. Antal valideringsforsøg (standard: 2) | + +### Fejlhåndtering + +Hvis modellen ikke formår at producere gyldigt struktureret output efter alle forsøg, vil svaret inkludere en `StructuredOutputError`: + +```typescript +if (result.data.info.error?.name === "StructuredOutputError") { + console.error("Failed to produce structured output:", result.data.info.error.message) + console.error("Attempts:", result.data.info.error.retries) +} +``` + +### Bedste praksis + +1. **Giv klare beskrivelser** i dine skemaegenskaber for at hjælpe modellen med at forstå, hvilke data der skal udtrækkes +2. **Brug `required`** til at angive, hvilke felter der skal være til stede +3. **Hold skemaer fokuserede** - komplekse indlejrede skemaer kan være sværere for modellen at udfylde korrekt +4. **Indstil passende `retryCount`** - øg for komplekse skemaer, sænk for enkle + +--- + ## API'er SDK avslører alle server-APIer gjennom en typesikker klient. @@ -226,27 +298,27 @@ const { providers, default: defaults } = await client.config.providers() ### Sessioner -| Metode | Beskrivelse | Noter | -| ---------------------------------------------------------- | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | -| `session.list()` | Liste sessioner | Returnerer <a href={typesUrl}><code>Session[]</code></a> | -| `session.get({ path })` | Få session | Returnerer <a href={typesUrl}><code>Session</code></a> | -| `session.children({ path })` | Liste over barnesessioner | Returnerer <a href={typesUrl}><code>Session[]</code></a> | -| `session.create({ body })` | Opret session | Returnerer <a href={typesUrl}><code>Session</code></a> | -| `session.delete({ path })` | Slett session | Returnerer `boolean` | -| `session.update({ path, body })` | Opdater sessionegenskaper | Returnerer <a href={typesUrl}><code>Session</code></a> | -| `session.init({ path, body })` | Analyser appen og lag `AGENTS.md` | Returnerer `boolean` | -| `session.abort({ path })` | Avbryt en løpesession | Returnerer `boolean` | -| `session.share({ path })` | Del sessionen | Returnerer <a href={typesUrl}><code>Session</code></a> | -| `session.unshare({ path })` | Slutt at dele sessionen | Returnerer <a href={typesUrl}><code>Session</code></a> | -| `session.summarize({ path, body })` | Oppsummer sessionen | Returnerer `boolean` | -| `session.messages({ path })` | Liste meldinger i en session | Returnerer `{ info: `<a href={typesUrl}><code>Message</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}[]` | -| `session.message({ path })` | Få meldingsdetaljer | Returnerer `{ info: `<a href={typesUrl}><code>Message</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}` | -| `session.prompt({ path, body })` | Send melding | `body.noReply: true` returnerer UserMessage (kun kontekst). Standard returnerer <a href={typesUrl}><code>AssistantMessage</code></a> med AI svar | -| `session.command({ path, body })` | Send kommando til session | Returnerer `{ info: `<a href={typesUrl}><code>AssistantMessage</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}` | -| `session.shell({ path, body })` | Kjør en shell-kommando | Returnerer <a href={typesUrl}><code>AssistantMessage</code></a> | -| `session.revert({ path, body })` | Tilbakestill en melding | Returnerer <a href={typesUrl}><code>Session</code></a> | -| `session.unrevert({ path })` | Gjenopret nulstillete meldinger | Returnerer <a href={typesUrl}><code>Session</code></a> | -| `postSessionByIdPermissionsByPermissionId({ path, body })` | Svar på en tillatelsesforespørsel | Returnerer `boolean` | +| Metode | Beskrivelse | Noter | +| ---------------------------------------------------------- | --------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `session.list()` | Liste sessioner | Returnerer <a href={typesUrl}><code>Session[]</code></a> | +| `session.get({ path })` | Få session | Returnerer <a href={typesUrl}><code>Session</code></a> | +| `session.children({ path })` | Liste over barnesessioner | Returnerer <a href={typesUrl}><code>Session[]</code></a> | +| `session.create({ body })` | Opret session | Returnerer <a href={typesUrl}><code>Session</code></a> | +| `session.delete({ path })` | Slett session | Returnerer `boolean` | +| `session.update({ path, body })` | Opdater sessionegenskaper | Returnerer <a href={typesUrl}><code>Session</code></a> | +| `session.init({ path, body })` | Analyser appen og lag `AGENTS.md` | Returnerer `boolean` | +| `session.abort({ path })` | Avbryt en løpesession | Returnerer `boolean` | +| `session.share({ path })` | Del sessionen | Returnerer <a href={typesUrl}><code>Session</code></a> | +| `session.unshare({ path })` | Slutt at dele sessionen | Returnerer <a href={typesUrl}><code>Session</code></a> | +| `session.summarize({ path, body })` | Oppsummer sessionen | Returnerer `boolean` | +| `session.messages({ path })` | Liste meldinger i en session | Returnerer `{ info: `<a href={typesUrl}><code>Message</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}[]` | +| `session.message({ path })` | Få meldingsdetaljer | Returnerer `{ info: `<a href={typesUrl}><code>Message</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}` | +| `session.prompt({ path, body })` | Send melding | `body.noReply: true` returnerer UserMessage (kun kontekst). Standard returnerer <a href={typesUrl}><code>AssistantMessage</code></a> med AI svar. Understøtter `body.outputFormat` for [struktureret output](#struktureret-output) | +| `session.command({ path, body })` | Send kommando til session | Returnerer `{ info: `<a href={typesUrl}><code>AssistantMessage</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}` | +| `session.shell({ path, body })` | Kjør en shell-kommando | Returnerer <a href={typesUrl}><code>AssistantMessage</code></a> | +| `session.revert({ path, body })` | Tilbakestill en melding | Returnerer <a href={typesUrl}><code>Session</code></a> | +| `session.unrevert({ path })` | Gjenopret nulstillete meldinger | Returnerer <a href={typesUrl}><code>Session</code></a> | +| `postSessionByIdPermissionsByPermissionId({ path, body })` | Svar på en tillatelsesforespørsel | Returnerer `boolean` | --- diff --git a/packages/web/src/content/docs/da/share.mdx b/packages/web/src/content/docs/da/share.mdx index 1ac2094ca7..80b9f0959e 100644 --- a/packages/web/src/content/docs/da/share.mdx +++ b/packages/web/src/content/docs/da/share.mdx @@ -41,7 +41,7 @@ For at eksplisitt angi manuell modus i [konfigurasjonsfilen](/docs/config): ```json title="opencode.json" { - "$schema": "https://opncd.ai/config.json", + "$schema": "https://opencode.ai/config.json", "share": "manual" } ``` @@ -54,7 +54,7 @@ Du kan aktivere automatisk deling for alle nye samtaler ved at sette alternative ```json title="opencode.json" { - "$schema": "https://opncd.ai/config.json", + "$schema": "https://opencode.ai/config.json", "share": "auto" } ``` @@ -69,7 +69,7 @@ Du kan deaktivere deling helt ved at sette alternativet `share` til `"disabled"` ```json title="opencode.json" { - "$schema": "https://opncd.ai/config.json", + "$schema": "https://opencode.ai/config.json", "share": "disabled" } ``` diff --git a/packages/web/src/content/docs/da/themes.mdx b/packages/web/src/content/docs/da/themes.mdx index 533bef30eb..d250e7f02f 100644 --- a/packages/web/src/content/docs/da/themes.mdx +++ b/packages/web/src/content/docs/da/themes.mdx @@ -61,11 +61,11 @@ Systemtemaet er for brugere som: ## Brug et tema -Du kan velge et tema ved at hente frem temavalg med kommandoen `/theme`. Eller du kan spesifisere det i [config](/docs/config). +Du kan velge et tema ved at hente frem temavalg med kommandoen `/theme`. Eller du kan angive det i `tui.json`. -```json title="opencode.json" {3} +```json title="tui.json" {3} { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "theme": "tokyonight" } ``` diff --git a/packages/web/src/content/docs/da/tui.mdx b/packages/web/src/content/docs/da/tui.mdx index 21cdbe320e..c1c0de0fd2 100644 --- a/packages/web/src/content/docs/da/tui.mdx +++ b/packages/web/src/content/docs/da/tui.mdx @@ -352,24 +352,34 @@ Nogle editorer kræver kommandolinjeargumenter for at køre i blokeringstilstand ## Konfigurer -Du kan tilpasse TUI-adfærden gennem OpenCode-konfigurationsfilen. +Du kan tilpasse TUI-adfærd gennem `tui.json` (eller `tui.jsonc`). -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", - "tui": { - "scroll_speed": 3, - "scroll_acceleration": { - "enabled": true - } - } + "$schema": "https://opencode.ai/tui.json", + "theme": "opencode", + "keybinds": { + "leader": "ctrl+x" + }, + "scroll_speed": 3, + "scroll_acceleration": { + "enabled": true + }, + "diff_style": "auto" } ``` +Dette er adskilt fra `opencode.json`, som konfigurerer server-/kørselstidsadfærd. + ### Indstillinger -- `scroll_acceleration` - Aktiver rulleacceleration i macOS-stil for jævn, naturlig rulning. Når aktiveret, øger rullehastigheden med hurtige rullebevægelser og forbliver præcis for langsommere bevægelser. **Denne indstilling har forrang over `scroll_speed` og tilsidesætter den, når den er aktiveret.** -- `scroll_speed` - Styrer hvor hurtigt TUI ruller, når du bruger rullekommandoer (minimum: `1`). Standard er `3`. **Bemærk: Dette ignoreres hvis `scroll_acceleration.enabled` er sat til `true`.** +- `theme` - Indstiller dit brugergrænsefladetema. [Læs mere](/docs/themes). +- `keybinds` - Tilpasser tastaturgenveje. [Læs mere](/docs/keybinds). +- `scroll_acceleration.enabled` - Aktiver rulleacceleration i macOS-stil for jævn, naturlig rulning. Når aktiveret, øger rullehastigheden med hurtige rullebevægelser og forbliver præcis for langsommere bevægelser. **Denne indstilling har forrang over `scroll_speed` og tilsidesætter den, når den er aktiveret.** +- `scroll_speed` - Styrer hvor hurtigt TUI ruller, når du bruger rullekommandoer (minimum: `0.001`, understøtter decimalværdier). Standard er `3`. **Bemærk: Dette ignoreres hvis `scroll_acceleration.enabled` er sat til `true`.** +- `diff_style` - Styrer diff-gengivelse. `"auto"` tilpasser sig terminalbredde, `"stacked"` viser altid et enkeltkolonne-layout. + +Brug `OPENCODE_TUI_CONFIG` til at indlæse en brugerdefineret TUI-konfigurationssti. --- diff --git a/packages/web/src/content/docs/da/zen.mdx b/packages/web/src/content/docs/da/zen.mdx index 128583ad7a..dee93e3bea 100644 --- a/packages/web/src/content/docs/da/zen.mdx +++ b/packages/web/src/content/docs/da/zen.mdx @@ -64,6 +64,8 @@ Du kan også få adgang til vores modeller gennem følgende API-endpoints. | Model | Model ID | Endpoint | AI SDK Pakke | | ------------------- | ------------------ | -------------------------------------------------- | --------------------------- | +| GPT 5.4 | gpt-5.4 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| GPT 5.3 Codex | gpt-5.3-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.2 | gpt-5.2 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.2 Codex | gpt-5.2-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.1 | gpt-5.1 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | @@ -73,22 +75,24 @@ Du kan også få adgang til vores modeller gennem følgende API-endpoints. | GPT 5 | gpt-5 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5 Codex | gpt-5-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5 Nano | gpt-5-nano | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | -| Claude Sonnet 4.5 | claude-sonnett-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| Claude Sonnet 4 | claude-sonnett-4 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| Claude Haiku 4.5 | claude-haiku-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| Claude Haiku 3.5 | claude-3-5-haiku | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Opus 4.6 | claude-opus-4-6 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Opus 4.5 | claude-opus-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Opus 4.1 | claude-opus-4-1 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Sonnet 4.6 | claude-sonnet-4-6 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Sonnet 4.5 | claude-sonnet-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Sonnet 4 | claude-sonnet-4 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Haiku 4.5 | claude-haiku-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Haiku 3.5 | claude-3-5-haiku | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Gemini 3.1 Pro | gemini-3.1-pro | `https://opencode.ai/zen/v1/models/gemini-3.1-pro` | `@ai-sdk/google` | | Gemini 3 Pro | gemini-3-pro | `https://opencode.ai/zen/v1/models/gemini-3-pro` | `@ai-sdk/google` | | Gemini 3 Flash | gemini-3-flash | `https://opencode.ai/zen/v1/models/gemini-3-flash` | `@ai-sdk/google` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.5 Gratis | minimax-m2.5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.1 | minimax-m2.1 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.1 Gratis | minimax-m2.1-free | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| GLM 5 | glm-5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | GLM 4.7 | glm-4.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM 4.7 Gratis | glm-4.7-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | GLM 4.6 | glm-4.6 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 Gratis | kimi-k2.5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2 Tenker | kimi-k2-thinking | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2 | kimi-k2 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Qwen3-koder 480B | qwen3-coder | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -117,29 +121,35 @@ Vi støtter en pay-as-you-go-model. Nedenfor er priserne **per 1 million tokens* | Model | Input | Output | Cached Læs | Cached Skriv | | --------------------------------- | ------ | ------ | ---------- | ------------ | | Stor sylteagurk | Gratis | Gratis | Gratis | - | -| MiniMax M2.1 Gratis | Gratis | Gratis | Gratis | - | +| MiniMax M2.5 Gratis | Gratis | Gratis | Gratis | - | +| MiniMax M2.5 | $0,30 | $1,20 | $0,06 | - | | MiniMax M2.1 | $0,30 | $1,20 | $0,10 | - | -| GLM 4.7 Gratis | Gratis | Gratis | Gratis | - | +| GLM 5 | $1,00 | $3,20 | $0,20 | - | | GLM 4.7 | $0,60 | $2,20 | $0,10 | - | | GLM 4.6 | $0,60 | $2,20 | $0,10 | - | -| Kimi K2.5 Gratis | Gratis | Gratis | Gratis | - | | Kimi K2.5 | $0,60 | $3,00 | $0,08 | - | | Kimi K2 Tenker | $0,40 | $2,50 | - | - | | Kimi K2 | $0,40 | $2,50 | - | - | | Qwen3-koder 480B | $0,45 | $1,50 | - | - | +| Claude Opus 4.6 (≤ 200K tokens) | $5,00 | $25,00 | $0,50 | $6,25 | +| Claude Opus 4.6 (> 200K tokens) | $10,00 | $37,50 | $1,00 | $12,50 | +| Claude Opus 4.5 | $5,00 | $25,00 | $0,50 | $6,25 | +| Claude Opus 4.1 | $15,00 | $75,00 | $1,50 | $18,75 | +| Claude Sonnet 4.6 (≤ 200K tokens) | $3,00 | $15,00 | $0,30 | $3,75 | +| Claude Sonnet 4.6 (> 200K tokens) | $6,00 | $22,50 | $0,60 | $7,50 | | Claude Sonnet 4.5 (≤ 200K tokens) | $3,00 | $15,00 | $0,30 | $3,75 | | Claude Sonnet 4.5 (> 200K tokens) | $6,00 | $22,50 | $0,60 | $7,50 | | Claude Sonnet 4 (≤ 200K tokens) | $3,00 | $15,00 | $0,30 | $3,75 | | Claude Sonnet 4 (> 200K tokens) | $6,00 | $22,50 | $0,60 | $7,50 | | Claude Haiku 4.5 | $1,00 | $5,00 | $0,10 | $1,25 | | Claude Haiku 3.5 | $0,80 | $4,00 | $0,08 | $1,00 | -| Claude Opus 4.6 (≤ 200K tokens) | $5,00 | $25,00 | $0,50 | $6,25 | -| Claude Opus 4.6 (> 200K tokens) | $10,00 | $37,50 | $1,00 | $12,50 | -| Claude Opus 4.5 | $5,00 | $25,00 | $0,50 | $6,25 | -| Claude Opus 4.1 | $15,00 | $75,00 | $1,50 | $18,75 | +| Gemini 3.1 Pro (≤ 200K tokens) | $2,00 | $12,00 | $0,20 | - | +| Gemini 3.1 Pro (> 200K tokens) | $4,00 | $18,00 | $0,40 | - | | Gemini 3 Pro (≤ 200K tokens) | $2,00 | $12,00 | $0,20 | - | | Gemini 3 Pro (> 200K tokens) | $4,00 | $18,00 | $0,40 | - | | Gemini 3 Flash | $0,50 | $3,00 | $0,05 | - | +| GPT 5.4 | $2,50 | $15,00 | $0,25 | - | +| GPT 5.3 Codex | $1,75 | $14,00 | $0,175 | - | | GPT 5.2 | $1,75 | $14,00 | $0,175 | - | | GPT 5.2 Codex | $1,75 | $14,00 | $0,175 | - | | GPT 5.1 | $1,07 | $8,50 | $0,107 | - | @@ -158,9 +168,7 @@ Kreditkortgebyrer overføres til kostpris (4,4 % + $0,30 per transaktion); vi op De gratis modeller: -- GLM 4.7 Gratis er tilgængelig på OpenCode i en begrænset periode. Teamet bruger denne tid til at samle feedback og forbedre modellen. -- Kimi K2.5 Gratis er tilgængelig på OpenCode i en begrænset periode. Teamet bruger denne tid til at samle feedback og forbedre modellen. -- MiniMax M2.1 Gratis er tilgængelig på OpenCode i en begrænset periode. Teamet bruger denne tid til at samle feedback og forbedre modellen. +- MiniMax M2.5 Gratis er tilgængelig på OpenCode i en begrænset periode. Teamet bruger denne tid til at samle feedback og forbedre modellen. - Stor sylteagurk er en stealth-model som er gratis på OpenCode i en begrænset periode. Teamet bruger denne tid til at samle feedback og forbedre modellen. <a href={email}>Kontakt os</a> hvis du har spørgsmål. @@ -186,14 +194,25 @@ at opkræve dig mere end $20, hvis din saldo går under $5. --- +### Udfasede modeller + +| Model | Udfasningsdato | +| ---------------- | -------------- | +| Qwen3-koder 480B | 6. feb. 2026 | +| Kimi K2 Tenker | 6. marts 2026 | +| Kimi K2 | 6. marts 2026 | +| MiniMax M2.1 | 15. marts 2026 | +| GLM 4.7 | 15. marts 2026 | +| GLM 4.6 | 15. marts 2026 | + +--- + ## Privatliv Alle vores modeller er hostet i USA. Vores udbydere følger en nul-opbevaringspolitik og bruger ikke dine data til modeltræning, med følgende undtagelser: - Stor sylteagurk: I løbet af gratisperioden kan indsamlede data bruges til at forbedre modellen. -- GLM 4.7 Gratis: I løbet af gratisperioden kan indsamlede data bruges til at forbedre modellen. -- Kimi K2.5 Gratis: I løbet af gratisperioden kan indsamlede data bruges til at forbedre modellen. -- MiniMax M2.1 Gratis: I løbet af gratisperioden kan indsamlede data bruges til at forbedre modellen. +- MiniMax M2.5 Gratis: I løbet af gratisperioden kan indsamlede data bruges til at forbedre modellen. - OpenAI API'er: Anmodninger opbevares i 30 dage i overensstemmelse med [OpenAIs datapolitikker](https://platform.openai.com/docs/guides/your-data). - Anthropic API'er: Anmodninger opbevares i 30 dage i overensstemmelse med [Anthropics datapolitikker](https://docs.anthropic.com/en/docs/claude-code/data-usage). diff --git a/packages/web/src/content/docs/de/ecosystem.mdx b/packages/web/src/content/docs/de/ecosystem.mdx index ea1bc589a4..c9ffcf9c68 100644 --- a/packages/web/src/content/docs/de/ecosystem.mdx +++ b/packages/web/src/content/docs/de/ecosystem.mdx @@ -15,38 +15,40 @@ Sie können sich auch [awesome-opencode](https://github.com/awesome-opencode/awe ## Plugins -| Name | Beschreibung | -| --------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | -| [opencode-daytona](https://github.com/jamesmurdza/daytona/blob/main/guides/typescript/opencode/README.md) | Führen Sie OpenCode-Sitzungen automatisch in isolierten Daytona-Sandboxes mit Git-Synchronisierung und Live-Vorschauen aus | -| [opencode-helicone-session](https://github.com/H2Shami/opencode-helicone-session) | Helicone-Sitzungsheader für die Anforderungsgruppierung automatisch einfügen | -| [opencode-type-inject](https://github.com/nick-vi/opencode-type-inject) | TypeScript/Svelte-Typen mit Suchtools automatisch in Dateilesevorgänge einfügen | -| [opencode-openai-codex-auth](https://github.com/numman-ali/opencode-openai-codex-auth) | Verwenden Sie Ihr ChatGPT Plus/Pro-Abonnement anstelle von API Credits | -| [opencode-gemini-auth](https://github.com/jenslys/opencode-gemini-auth) | Verwenden Sie Ihren bestehenden Gemini-Plan anstelle der API-Abrechnung | -| [opencode-antigravity-auth](https://github.com/NoeFabris/opencode-antigravity-auth) | Nutzen Sie die kostenlosen Modelle von Antigravity anstelle der API-Abrechnung | -| [opencode-devcontainers](https://github.com/athal7/opencode-devcontainers) | Multi-Branch-Devcontainer-Isolierung mit flachen Klonen und automatisch zugewiesenen Ports | -| [opencode-google-antigravity-auth](https://github.com/shekohex/opencode-google-antigravity-auth) | Google Antigravity OAuth-Plugin mit Unterstützung für die Google-Suche und robustere API-Verarbeitung | -| [opencode-dynamic-context-pruning](https://github.com/Tarquinen/opencode-dynamic-context-pruning) | Optimieren Sie die Token-Nutzung, indem Sie veraltete Tool-Ausgaben bereinigen | -| [opencode-websearch-cited](https://github.com/ghoulr/opencode-websearch-cited.git) | Fügen Sie native Websuchunterstützung für unterstützte Anbieter mit Google Grounded Style hinzu | -| [opencode-pty](https://github.com/shekohex/opencode-pty.git) | Ermöglicht AI-Agenten, Hintergrundprozesse in einem PTY auszuführen und ihnen interaktive Eingaben zu senden. | -| [opencode-shell-strategy](https://github.com/JRedeker/opencode-shell-strategy) | Anweisungen für nicht interaktive Shell-Befehle – verhindert Abstürze bei TTY-abhängigen Vorgängen | -| [opencode-wakatime](https://github.com/angristan/opencode-wakatime) | Verfolgen Sie die Nutzung von OpenCode mit Wakatime | -| [opencode-md-table-formatter](https://github.com/franlol/opencode-md-table-formatter/tree/main) | Von LLMs erstellte Abschriftentabellen bereinigen | -| [opencode-morph-fast-apply](https://github.com/JRedeker/opencode-morph-fast-apply) | 10x schnellere Codebearbeitung mit Morph Fast Apply API und Lazy-Edit-Markern | -| [oh-my-opencode](https://github.com/code-yeongyu/oh-my-opencode) | Hintergrundagenten, vorgefertigte LSP/AST/MCP-Tools, kuratierte Agenten, Claude Code-kompatibel | -| [opencode-notificator](https://github.com/panta82/opencode-notificator) | Desktop-Benachrichtigungen und akustische Warnungen für OpenCode-Sitzungen | -| [opencode-notifier](https://github.com/mohak34/opencode-notifier) | Desktop-Benachrichtigungen und akustische Warnungen für Berechtigungs-, Abschluss- und Fehlerereignisse | -| [opencode-zellij-namer](https://github.com/24601/opencode-zellij-namer) | AI-gestützte automatische Benennung von Zellij-Sitzungen basierend auf dem OpenCode-Kontext | -| [opencode-skillful](https://github.com/zenobi-us/opencode-skillful) | Ermöglichen Sie OpenCode-Agenten das verzögerte Laden von Eingabeaufforderungen bei Bedarf mit Skill-Erkennung und -Injektion | -| [opencode-supermemory](https://github.com/supermemoryai/opencode-supermemory) | Persistenter Speicher über Sitzungen hinweg mit Supermemory | -| [@plannotator/opencode](https://github.com/backnotprop/plannotator/tree/main/apps/opencode-plugin) | Interaktive Planüberprüfung mit visueller Anmerkung und private/offline-Freigabe | -| [@openspoon/subtask2](https://github.com/spoons-and-mirrors/subtask2) | Erweitern Sie OpenCode /commands zu einem leistungsstarken Orchestrierungssystem mit granularer Flusskontrolle | -| [opencode-scheduler](https://github.com/different-ai/opencode-scheduler) | Planen Sie wiederkehrende Jobs mit launchd (Mac) oder systemd (Linux) mit Cron-Syntax | -| [micode](https://github.com/vtemian/micode) | Strukturiertes Brainstorming → Planen → Workflow mit Sitzungskontinuität Implementierung | -| [octto](https://github.com/vtemian/octto) | Interaktiver Browser UI für AI Brainstorming mit Formularen mit mehreren Fragen | -| [opencode-background-agents](https://github.com/kdcokenny/opencode-background-agents) | Hintergrundagenten im Claude Code-Stil mit asynchroner Delegation und Kontextpersistenz | -| [opencode-notify](https://github.com/kdcokenny/opencode-notify) | Native OS-Benachrichtigungen für OpenCode – wissen, wann Aufgaben erledigt sind | -| [opencode-workspace](https://github.com/kdcokenny/opencode-workspace) | Gebündelter Multi-Agent-Orchestrierungs-Harness – 16 Komponenten, eine Installation | -| [opencode-worktree](https://github.com/kdcokenny/opencode-worktree) | Reibungslose Git-Arbeitsbäume für OpenCode | +| Name | Beschreibung | +| -------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | +| [opencode-daytona](https://github.com/daytonaio/daytona/tree/main/libs/opencode-plugin) | Führen Sie OpenCode-Sitzungen automatisch in isolierten Daytona-Sandboxes mit Git-Synchronisierung und Live-Vorschauen aus | +| [opencode-helicone-session](https://github.com/H2Shami/opencode-helicone-session) | Helicone-Sitzungsheader für die Anforderungsgruppierung automatisch einfügen | +| [opencode-type-inject](https://github.com/nick-vi/opencode-type-inject) | TypeScript/Svelte-Typen mit Suchtools automatisch in Dateilesevorgänge einfügen | +| [opencode-openai-codex-auth](https://github.com/numman-ali/opencode-openai-codex-auth) | Verwenden Sie Ihr ChatGPT Plus/Pro-Abonnement anstelle von API Credits | +| [opencode-gemini-auth](https://github.com/jenslys/opencode-gemini-auth) | Verwenden Sie Ihren bestehenden Gemini-Plan anstelle der API-Abrechnung | +| [opencode-antigravity-auth](https://github.com/NoeFabris/opencode-antigravity-auth) | Nutzen Sie die kostenlosen Modelle von Antigravity anstelle der API-Abrechnung | +| [opencode-devcontainers](https://github.com/athal7/opencode-devcontainers) | Multi-Branch-Devcontainer-Isolierung mit flachen Klonen und automatisch zugewiesenen Ports | +| [opencode-google-antigravity-auth](https://github.com/shekohex/opencode-google-antigravity-auth) | Google Antigravity OAuth-Plugin mit Unterstützung für die Google-Suche und robustere API-Verarbeitung | +| [opencode-dynamic-context-pruning](https://github.com/Tarquinen/opencode-dynamic-context-pruning) | Optimieren Sie die Token-Nutzung, indem Sie veraltete Tool-Ausgaben bereinigen | +| [opencode-vibeguard](https://github.com/inkdust2021/opencode-vibeguard) | Schwärzen Sie Geheimnisse/PII in VibeGuard-ähnliche Platzhalter vor LLM-Aufrufen; lokal wiederherstellen | +| [opencode-websearch-cited](https://github.com/ghoulr/opencode-websearch-cited.git) | Fügen Sie native Websuchunterstützung für unterstützte Anbieter mit Google Grounded Style hinzu | +| [opencode-pty](https://github.com/shekohex/opencode-pty.git) | Ermöglicht AI-Agenten, Hintergrundprozesse in einem PTY auszuführen und ihnen interaktive Eingaben zu senden. | +| [opencode-shell-strategy](https://github.com/JRedeker/opencode-shell-strategy) | Anweisungen für nicht interaktive Shell-Befehle – verhindert Abstürze bei TTY-abhängigen Vorgängen | +| [opencode-wakatime](https://github.com/angristan/opencode-wakatime) | Verfolgen Sie die Nutzung von OpenCode mit Wakatime | +| [opencode-md-table-formatter](https://github.com/franlol/opencode-md-table-formatter/tree/main) | Von LLMs erstellte Abschriftentabellen bereinigen | +| [opencode-morph-fast-apply](https://github.com/JRedeker/opencode-morph-fast-apply) | 10x schnellere Codebearbeitung mit Morph Fast Apply API und Lazy-Edit-Markern | +| [oh-my-opencode](https://github.com/code-yeongyu/oh-my-opencode) | Hintergrundagenten, vorgefertigte LSP/AST/MCP-Tools, kuratierte Agenten, Claude Code-kompatibel | +| [opencode-notificator](https://github.com/panta82/opencode-notificator) | Desktop-Benachrichtigungen und akustische Warnungen für OpenCode-Sitzungen | +| [opencode-notifier](https://github.com/mohak34/opencode-notifier) | Desktop-Benachrichtigungen und akustische Warnungen für Berechtigungs-, Abschluss- und Fehlerereignisse | +| [opencode-zellij-namer](https://github.com/24601/opencode-zellij-namer) | AI-gestützte automatische Benennung von Zellij-Sitzungen basierend auf dem OpenCode-Kontext | +| [opencode-skillful](https://github.com/zenobi-us/opencode-skillful) | Ermöglichen Sie OpenCode-Agenten das verzögerte Laden von Eingabeaufforderungen bei Bedarf mit Skill-Erkennung und -Injektion | +| [opencode-supermemory](https://github.com/supermemoryai/opencode-supermemory) | Persistenter Speicher über Sitzungen hinweg mit Supermemory | +| [@plannotator/opencode](https://github.com/backnotprop/plannotator/tree/main/apps/opencode-plugin) | Interaktive Planüberprüfung mit visueller Anmerkung und private/offline-Freigabe | +| [@openspoon/subtask2](https://github.com/spoons-and-mirrors/subtask2) | Erweitern Sie OpenCode /commands zu einem leistungsstarken Orchestrierungssystem mit granularer Flusskontrolle | +| [opencode-scheduler](https://github.com/different-ai/opencode-scheduler) | Planen Sie wiederkehrende Jobs mit launchd (Mac) oder systemd (Linux) mit Cron-Syntax | +| [micode](https://github.com/vtemian/micode) | Strukturiertes Brainstorming → Planen → Workflow mit Sitzungskontinuität Implementierung | +| [octto](https://github.com/vtemian/octto) | Interaktiver Browser UI für AI Brainstorming mit Formularen mit mehreren Fragen | +| [opencode-background-agents](https://github.com/kdcokenny/opencode-background-agents) | Hintergrundagenten im Claude Code-Stil mit asynchroner Delegation und Kontextpersistenz | +| [opencode-notify](https://github.com/kdcokenny/opencode-notify) | Native OS-Benachrichtigungen für OpenCode – wissen, wann Aufgaben erledigt sind | +| [opencode-workspace](https://github.com/kdcokenny/opencode-workspace) | Gebündelter Multi-Agent-Orchestrierungs-Harness – 16 Komponenten, eine Installation | +| [opencode-worktree](https://github.com/kdcokenny/opencode-worktree) | Reibungslose Git-Arbeitsbäume für OpenCode | +| [opencode-sentry-monitor](https://github.com/stolinski/opencode-sentry-monitor) | Tracen und debuggen Sie Ihre AI-Agenten mit Sentry AI Monitoring | --- diff --git a/packages/web/src/content/docs/de/go.mdx b/packages/web/src/content/docs/de/go.mdx new file mode 100644 index 0000000000..fe4a600cd9 --- /dev/null +++ b/packages/web/src/content/docs/de/go.mdx @@ -0,0 +1,145 @@ +--- +title: Go +description: Kostengünstiges Abonnement für Open-Coding-Modelle. +--- + +import config from "../../../../config.mjs" +export const console = config.console +export const email = `mailto:${config.email}` + +OpenCode Go ist ein kostengünstiges Abonnement für **10 $/Monat**, das dir zuverlässigen Zugriff auf beliebte Open-Coding-Modelle bietet. + +:::note +OpenCode Go befindet sich derzeit in der Beta-Phase. +::: + +Go funktioniert wie jeder andere Anbieter in OpenCode. Du abonnierst OpenCode Go und erhältst deinen API-Schlüssel. Es ist **völlig optional** und du musst es nicht nutzen, um OpenCode zu verwenden. + +Es wurde primär für internationale Nutzer entwickelt, mit Modellen, die in den USA, der EU und Singapur gehostet werden, um einen stabilen weltweiten Zugriff zu gewährleisten. + +--- + +## Hintergrund + +Offene Modelle sind wirklich gut geworden. Sie erreichen bei Coding-Aufgaben mittlerweile eine Leistung, die der von proprietären Modellen nahekommt. Und da viele Anbieter sie wettbewerbsfähig bereitstellen können, sind sie in der Regel deutlich günstiger. + +Es kann jedoch schwierig sein, einen zuverlässigen Zugang mit niedriger Latenz zu erhalten. Die Anbieter variieren in Qualität und Verfügbarkeit. + +:::tip +Wir haben eine ausgewählte Gruppe von Modellen und Anbietern getestet, die gut mit OpenCode funktionieren. +::: + +Um dies zu lösen, haben wir einige Dinge getan: + +1. Wir haben eine ausgewählte Gruppe offener Modelle getestet und mit deren Teams darüber gesprochen, wie man sie am besten betreibt. +2. Anschließend haben wir mit einigen Anbietern zusammengearbeitet, um sicherzustellen, dass diese korrekt bereitgestellt werden. +3. Schließlich haben wir die Kombination aus Modell und Anbieter einem Benchmark unterzogen und eine Liste erstellt, die wir guten Gewissens empfehlen können. + +OpenCode Go gibt dir Zugriff auf diese Modelle für **10 $/Monat**. + +--- + +## Wie es funktioniert + +OpenCode Go funktioniert wie jeder andere Anbieter in OpenCode. + +1. Du meldest dich bei **<a href={console}>OpenCode Zen</a>** an, abonnierst Go und kopierst deinen API-Schlüssel. +2. Du führst den Befehl `/connect` in der TUI aus, wählst `OpenCode Go` und fügst deinen API-Schlüssel ein. +3. Führe `/models` in der TUI aus, um die Liste der über Go verfügbaren Modelle zu sehen. + +:::note +Nur ein Mitglied pro Workspace kann OpenCode Go abonnieren. +::: + +Die aktuelle Liste der Modelle umfasst: + +- **GLM-5** +- **Kimi K2.5** +- **MiniMax M2.5** + +Die Liste der Modelle kann sich ändern, wenn wir neue testen und hinzufügen. + +--- + +## Nutzungslimits + +OpenCode Go beinhaltet die folgenden Limits: + +- **5-Stunden-Limit** — 12 $ Nutzung +- **Wöchentliches Limit** — 30 $ Nutzung +- **Monatliches Limit** — 60 $ Nutzung + +Die Limits sind in Dollarwerten definiert. Das bedeutet, dass deine tatsächliche Anzahl an Anfragen von dem verwendeten Modell abhängt. Günstigere Modelle wie MiniMax M2.5 ermöglichen mehr Anfragen, während kostenintensivere Modelle wie GLM-5 weniger zulassen. + +Die untenstehende Tabelle bietet eine geschätzte Anzahl an Anfragen basierend auf typischen Go-Nutzungsmustern: + +| | GLM-5 | Kimi K2.5 | MiniMax M2.5 | +| ------------------- | ----- | --------- | ------------ | +| Anfragen pro 5 Std. | 1.150 | 1.850 | 30.000 | +| Anfragen pro Woche | 2.880 | 4.630 | 75.000 | +| Anfragen pro Monat | 5.750 | 9.250 | 150.000 | + +Die Schätzungen basieren auf beobachteten durchschnittlichen Nutzungsmustern: + +- GLM-5 — 700 Input-, 52.000 Cached-, 150 Output-Token pro Anfrage +- Kimi K2.5 — 870 Input-, 55.000 Cached-, 200 Output-Token pro Anfrage +- MiniMax M2.5 — 300 Input-, 55.000 Cached-, 125 Output-Token pro Anfrage + +Du kannst deine aktuelle Nutzung in der **<a href={console}>Konsole</a>** verfolgen. + +:::tip +Wenn du das Nutzungslimit erreichst, kannst du weiterhin die kostenlosen Modelle verwenden. +::: + +Nutzungslimits können sich ändern, da wir aus der frühen Nutzung und dem Feedback lernen. + +--- + +### Preise + +OpenCode Go ist ein Abonnementplan für **10 $/Monat**. Unten stehen die Preise **pro 1 Mio. Token**. + +| Modell | Input | Output | Cached Read | +| ------------ | ------ | ------ | ----------- | +| GLM-5 | 1,00 $ | 3,20 $ | 0,20 $ | +| Kimi K2.5 | 0,60 $ | 3,00 $ | 0,10 $ | +| MiniMax M2.5 | 0,30 $ | 1,20 $ | 0,03 $ | + +--- + +### Nutzung über Limits hinaus + +Wenn du auch Guthaben auf deinem Zen-Konto hast, kannst du die Option **Use balance** in der Konsole aktivieren. Wenn aktiviert, greift Go auf dein Zen-Guthaben zurück, nachdem du deine Nutzungslimits erreicht hast, anstatt Anfragen zu blockieren. + +--- + +## Endpunkte + +Du kannst auch über die folgenden API-Endpunkte auf Go-Modelle zugreifen. + +| Modell | Modell-ID | Endpunkt | AI SDK Paket | +| ------------ | ------------ | ------------------------------------------------ | --------------------------- | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | + +Die [Modell-ID](/docs/config/#models) in deiner OpenCode-Konfiguration verwendet das Format `opencode-go/<model-id>`. Zum Beispiel würdest du für Kimi K2.5 `opencode-go/kimi-k2.5` in deiner Konfiguration verwenden. + +--- + +## Datenschutz + +Der Plan wurde primär für internationale Nutzer entwickelt, mit Modellen, die in den USA, der EU und Singapur gehostet werden, um einen stabilen weltweiten Zugriff zu gewährleisten. + +<a href={email}>Kontaktiere uns</a>, wenn du Fragen hast. + +--- + +## Ziele + +Wir haben OpenCode Go erstellt, um: + +1. AI-Coding für mehr Menschen durch ein kostengünstiges Abonnement **zugänglich** zu machen. +2. **Zuverlässigen** Zugriff auf die besten Open-Coding-Modelle zu bieten. +3. Modelle zu kuratieren, die für den Einsatz von Coding-Agents **getestet und gebenchmarkt** sind. +4. **Keinen Lock-in** zu haben, indem wir dir ermöglichen, jeden anderen Anbieter ebenfalls mit OpenCode zu nutzen. diff --git a/packages/web/src/content/docs/de/keybinds.mdx b/packages/web/src/content/docs/de/keybinds.mdx index d575800805..628c65006d 100644 --- a/packages/web/src/content/docs/de/keybinds.mdx +++ b/packages/web/src/content/docs/de/keybinds.mdx @@ -3,11 +3,11 @@ title: Tastenkombinationen description: Passen Sie Ihre Tastenkombinationen an. --- -OpenCode verfügt über eine Liste von Tastenkombinationen, die Sie über die OpenCode-Konfiguration anpassen können. +OpenCode verfügt über eine Liste von Tastenkombinationen, die Sie über `tui.json` anpassen können. -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "keybinds": { "leader": "ctrl+x", "app_exit": "ctrl+c,ctrl+d,<leader>q", @@ -28,6 +28,7 @@ OpenCode verfügt über eine Liste von Tastenkombinationen, die Sie über die Op "session_unshare": "none", "session_interrupt": "escape", "session_compact": "<leader>c", + "session_child_first": "<leader>down", "session_child_cycle": "<leader>right", "session_child_cycle_reverse": "<leader>left", "session_parent": "<leader>up", @@ -117,11 +118,11 @@ Sie müssen für Ihre Keybinds keinen Leader Key verwenden, wir empfehlen jedoch ## Keybind deaktivieren -Sie können eine Keybind deaktivieren, indem Sie den Schlüssel mit dem Wert „none“ zu Ihrer Konfiguration hinzufügen. +Sie können eine Keybind deaktivieren, indem Sie den Schlüssel mit dem Wert „none“ zu `tui.json` hinzufügen. -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "keybinds": { "session_compact": "none" } diff --git a/packages/web/src/content/docs/de/providers.mdx b/packages/web/src/content/docs/de/providers.mdx index d72ac5af3d..fa447594d6 100644 --- a/packages/web/src/content/docs/de/providers.mdx +++ b/packages/web/src/content/docs/de/providers.mdx @@ -84,6 +84,37 @@ Es funktioniert wie jeder andere Anbieter in OpenCode und ist völlig optional. --- +## OpenCode Go + +OpenCode Go ist ein kostenguenstiges Abonnement, das zuverlaessigen Zugriff auf beliebte Open-Coding-Modelle bietet, die vom OpenCode-Team getestet und verifiziert wurden, dass sie gut mit OpenCode funktionieren. + +1. Führen Sie den Befehl `/connect` in der TUI aus, waehlen Sie `OpenCode Go` und gehen Sie zu [opencode.ai/auth](https://opencode.ai/zen). + + ```txt + /connect + ``` + +2. Melden Sie sich an, geben Sie Ihre Rechnungsdaten ein und kopieren Sie Ihren API-Schlüssel. + +3. Fügen Sie Ihren API-Schlüssel ein. + + ```txt + ┌ API key + │ + │ + └ enter + ``` + +4. Führen Sie `/models` in der TUI aus, um die Liste der empfohlenen Modelle zu sehen. + + ```txt + /models + ``` + +Es funktioniert wie jeder andere Anbieter in OpenCode und ist völlig optional. + +--- + ## Verzeichnis Schauen wir uns einige der Anbieter im Detail an. Wenn Sie einen Anbieter hinzufügen möchten @@ -1480,6 +1511,39 @@ SAP AI Core bietet Zugriff auf 40+ Modelle von OpenAI, Anthropic, Google, Amazon --- +### STACKIT + +STACKIT AI Model Serving bietet eine voll verwaltete, souveraene Hosting-Umgebung fuer AI-Modelle, mit Fokus auf LLMs wie Llama, Mistral und Qwen, mit maximaler Datensouveraenitaet auf europaeischer Infrastruktur. + +1. Gehen Sie zum [STACKIT Portal](https://portal.stackit.cloud), navigieren Sie zu **AI Model Serving** und erstellen Sie ein Auth-Token fuer Ihr Projekt. + + :::tip + Sie benoetigen ein STACKIT-Kundenkonto, Benutzerkonto und Projekt, bevor Sie Auth-Tokens erstellen koennen. + ::: + +2. Führen Sie den Befehl `/connect` aus und suchen Sie nach **STACKIT**. + + ```txt + /connect + ``` + +3. Geben Sie Ihr STACKIT AI Model Serving Auth-Token ein. + + ```txt + ┌ API key + │ + │ + └ enter + ``` + +4. Führen Sie den Befehl `/models` aus, um aus verfügbaren Modellen wie _Qwen3-VL 235B_ oder _Llama 3.3 70B_ auszuwählen. + + ```txt + /models + ``` + +--- + ### OVHcloud AI Endpoints 1. Gehen Sie zum [OVHcloud panel](https://ovh.com/manager). Navigieren Sie zum Abschnitt `Public Cloud`, `AI & Machine Learning` > `AI Endpoints` und klicken Sie auf der Registerkarte `API Keys` auf **Neuen API-Schlüssel erstellen**. diff --git a/packages/web/src/content/docs/de/sdk.mdx b/packages/web/src/content/docs/de/sdk.mdx index 21791db05d..22e70071d6 100644 --- a/packages/web/src/content/docs/de/sdk.mdx +++ b/packages/web/src/content/docs/de/sdk.mdx @@ -119,6 +119,78 @@ try { --- +## Structured Output + +Du kannst eine strukturierte JSON-Ausgabe vom Modell anfordern, indem du ein `format` mit einem JSON-Schema angibst. Das Modell verwendet dann ein `StructuredOutput`-Tool, um validiertes JSON zurueckzugeben, das deinem Schema entspricht. + +### Grundlegende Verwendung + +```typescript +const result = await client.session.prompt({ + path: { id: sessionId }, + body: { + parts: [{ type: "text", text: "Recherchiere Anthropic und gib Firmeninfos zurueck" }], + format: { + type: "json_schema", + schema: { + type: "object", + properties: { + company: { type: "string", description: "Firmenname" }, + founded: { type: "number", description: "Gruendungsjahr" }, + products: { + type: "array", + items: { type: "string" }, + description: "Hauptprodukte", + }, + }, + required: ["company", "founded"], + }, + }, + }, +}) + +// Zugriff auf die strukturierte Ausgabe +console.log(result.data.info.structured_output) +// { company: "Anthropic", founded: 2021, products: ["Claude", "Claude API"] } +``` + +### Ausgabeformate + +| Type | Description | +| ------------- | ----------------------------------------------------------- | +| `text` | Standard. Normale Textantwort (keine strukturierte Ausgabe) | +| `json_schema` | Gibt validiertes JSON zurueck, das dem Schema entspricht | + +### JSON-Schema-Format + +Bei Verwendung von `type: 'json_schema'` musst du Folgendes angeben: + +| Field | Type | Description | +| ------------ | --------------- | ------------------------------------------------------------- | +| `type` | `'json_schema'` | Erforderlich. Gibt den JSON-Schema-Modus an | +| `schema` | `object` | Erforderlich. JSON-Schema-Objekt, das die Struktur definiert | +| `retryCount` | `number` | Optional. Anzahl der Validierungswiederholungen (Standard: 2) | + +### Fehlerbehandlung + +Wenn das Modell nach allen Wiederholungen keine valide strukturierte Ausgabe liefert, enthaelt die Antwort einen `StructuredOutputError`: + +```typescript +if (result.data.info.error?.name === "StructuredOutputError") { + console.error("Strukturierte Ausgabe fehlgeschlagen:", result.data.info.error.message) + console.error("Versuche:", result.data.info.error.retries) +} +``` + +### Best Practices + +1. **Klare Beschreibungen**: Gib in deinen Schema-Properties klare Beschreibungen an, damit das Modell versteht, welche Daten extrahiert werden sollen. +2. **`required` nutzen**: Definiere, welche Felder zwingend vorhanden sein muessen. +3. **Schemas einfach halten**: Komplexe verschachtelte Schemas sind fuer das Modell schwerer korrekt auszufuellen. +4. **`retryCount` anpassen**: Erhoehe den Wert bei komplexen Schemas, verringere ihn bei einfachen. + +--- + ## APIs Das SDK stellt alle Server-APIs ueber einen typsicheren Client bereit. @@ -127,9 +199,9 @@ Das SDK stellt alle Server-APIs ueber einen typsicheren Client bereit. ### Global -| Method | Description | Response | -| ----------------- | ------------------------------- | ------------------------------------ | -| `global.health()` | Check server health and version | `{ healthy: true, version: string }` | +| Method | Description | Response | +| ----------------- | -------------------------------- | ------------------------------------ | +| `global.health()` | Prueft Server-Status und Version | `{ healthy: true, version: string }` | --- @@ -144,10 +216,10 @@ console.log(health.data.version) ### App -| Method | Description | Response | -| -------------- | ------------------------- | ------------------------------------------- | -| `app.log()` | Write a log entry | `boolean` | -| `app.agents()` | List all available agents | <a href={typesUrl}><code>Agent[]</code></a> | +| Method | Description | Response | +| -------------- | -------------------------------- | ------------------------------------------- | +| `app.log()` | Schreibt einen Log-Eintrag | `boolean` | +| `app.agents()` | Listet alle verfuegbaren Agenten | <a href={typesUrl}><code>Agent[]</code></a> | --- @@ -171,10 +243,10 @@ const agents = await client.app.agents() ### Project -| Method | Description | Response | -| ------------------- | ------------------- | --------------------------------------------- | -| `project.list()` | List all projects | <a href={typesUrl}><code>Project[]</code></a> | -| `project.current()` | Get current project | <a href={typesUrl}><code>Project</code></a> | +| Method | Description | Response | +| ------------------- | ---------------------------- | --------------------------------------------- | +| `project.list()` | Listet alle Projekte | <a href={typesUrl}><code>Project[]</code></a> | +| `project.current()` | Ruft das aktuelle Projekt ab | <a href={typesUrl}><code>Project</code></a> | --- @@ -192,9 +264,9 @@ const currentProject = await client.project.current() ### Path -| Method | Description | Response | -| ------------ | ---------------- | ---------------------------------------- | -| `path.get()` | Get current path | <a href={typesUrl}><code>Path</code></a> | +| Method | Description | Response | +| ------------ | -------------------------- | ---------------------------------------- | +| `path.get()` | Ruft den aktuellen Pfad ab | <a href={typesUrl}><code>Path</code></a> | --- @@ -209,10 +281,10 @@ const pathInfo = await client.path.get() ### Config -| Method | Description | Response | -| -------------------- | --------------------------------- | ----------------------------------------------------------------------------------------------------- | -| `config.get()` | Get config info | <a href={typesUrl}><code>Config</code></a> | -| `config.providers()` | List providers and default models | `{ providers: `<a href={typesUrl}><code>Provider[]</code></a>`, default: { [key: string]: string } }` | +| Method | Description | Response | +| -------------------- | ------------------------------------ | ----------------------------------------------------------------------------------------------------- | +| `config.get()` | Ruft Konfigurationsinfos ab | <a href={typesUrl}><code>Config</code></a> | +| `config.providers()` | Listet Provider und Standard-Modelle | `{ providers: `<a href={typesUrl}><code>Provider[]</code></a>`, default: { [key: string]: string } }` | --- @@ -228,27 +300,27 @@ const { providers, default: defaults } = await client.config.providers() ### Sessions -| Method | Description | Notes | -| ---------------------------------------------------------- | ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | -| `session.list()` | List sessions | Returns <a href={typesUrl}><code>Session[]</code></a> | -| `session.get({ path })` | Get session | Returns <a href={typesUrl}><code>Session</code></a> | -| `session.children({ path })` | List child sessions | Returns <a href={typesUrl}><code>Session[]</code></a> | -| `session.create({ body })` | Create session | Returns <a href={typesUrl}><code>Session</code></a> | -| `session.delete({ path })` | Delete session | Returns `boolean` | -| `session.update({ path, body })` | Update session properties | Returns <a href={typesUrl}><code>Session</code></a> | -| `session.init({ path, body })` | Analyze app and create `AGENTS.md` | Returns `boolean` | -| `session.abort({ path })` | Abort a running session | Returns `boolean` | -| `session.share({ path })` | Share session | Returns <a href={typesUrl}><code>Session</code></a> | -| `session.unshare({ path })` | Unshare session | Returns <a href={typesUrl}><code>Session</code></a> | -| `session.summarize({ path, body })` | Summarize session | Returns `boolean` | -| `session.messages({ path })` | List messages in a session | Returns `{ info: `<a href={typesUrl}><code>Message</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}[]` | -| `session.message({ path })` | Get message details | Returns `{ info: `<a href={typesUrl}><code>Message</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}` | -| `session.prompt({ path, body })` | Send prompt message | `body.noReply: true` returns UserMessage (context only). Default returns <a href={typesUrl}><code>AssistantMessage</code></a> with AI response | -| `session.command({ path, body })` | Send command to session | Returns `{ info: `<a href={typesUrl}><code>AssistantMessage</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}` | -| `session.shell({ path, body })` | Run a shell command | Returns <a href={typesUrl}><code>AssistantMessage</code></a> | -| `session.revert({ path, body })` | Revert a message | Returns <a href={typesUrl}><code>Session</code></a> | -| `session.unrevert({ path })` | Restore reverted messages | Returns <a href={typesUrl}><code>Session</code></a> | -| `postSessionByIdPermissionsByPermissionId({ path, body })` | Respond to a permission request | Returns `boolean` | +| Method | Description | Notes | +| ---------------------------------------------------------- | --------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `session.list()` | Listet Sessions | Gibt <a href={typesUrl}><code>Session[]</code></a> zurueck | +| `session.get({ path })` | Ruft Session ab | Gibt <a href={typesUrl}><code>Session</code></a> zurueck | +| `session.children({ path })` | Listet Kind-Sessions | Gibt <a href={typesUrl}><code>Session[]</code></a> zurueck | +| `session.create({ body })` | Erstellt Session | Gibt <a href={typesUrl}><code>Session</code></a> zurueck | +| `session.delete({ path })` | Loescht Session | Gibt `boolean` zurueck | +| `session.update({ path, body })` | Aktualisiert Session-Eigenschaften | Gibt <a href={typesUrl}><code>Session</code></a> zurueck | +| `session.init({ path, body })` | Analysiert App und erstellt `AGENTS.md` | Gibt `boolean` zurueck | +| `session.abort({ path })` | Bricht eine laufende Session ab | Gibt `boolean` zurueck | +| `session.share({ path })` | Teilt Session | Gibt <a href={typesUrl}><code>Session</code></a> zurueck | +| `session.unshare({ path })` | Hebt Teilen der Session auf | Gibt <a href={typesUrl}><code>Session</code></a> zurueck | +| `session.summarize({ path, body })` | Fasst Session zusammen | Gibt `boolean` zurueck | +| `session.messages({ path })` | Listet Nachrichten einer Session | Gibt `{ info: `<a href={typesUrl}><code>Message</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}[]` zurueck | +| `session.message({ path })` | Ruft Nachrichtendetails ab | Gibt `{ info: `<a href={typesUrl}><code>Message</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}` zurueck | +| `session.prompt({ path, body })` | Sendet Prompt-Nachricht | `body.noReply: true` gibt UserMessage (nur Kontext) zurueck. Standard gibt <a href={typesUrl}><code>AssistantMessage</code></a> mit AI-Antwort zurueck. Unterstuetzt `body.outputFormat` fuer [strukturierte Ausgabe](#structured-output) | +| `session.command({ path, body })` | Sendet Befehl an Session | Gibt `{ info: `<a href={typesUrl}><code>AssistantMessage</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}` zurueck | +| `session.shell({ path, body })` | Fuehrt Shell-Befehl aus | Gibt <a href={typesUrl}><code>AssistantMessage</code></a> zurueck | +| `session.revert({ path, body })` | Setzt Nachricht zurueck | Gibt <a href={typesUrl}><code>Session</code></a> zurueck | +| `session.unrevert({ path })` | Stellt zurueckgesetzte Nachrichten wieder her | Gibt <a href={typesUrl}><code>Session</code></a> zurueck | +| `postSessionByIdPermissionsByPermissionId({ path, body })` | Antwortet auf eine Berechtigungsanfrage | Gibt `boolean` zurueck | --- @@ -285,19 +357,19 @@ await client.session.prompt({ ### Files -| Method | Description | Response | -| ------------------------- | ---------------------------------- | ------------------------------------------------------------------------------------------- | -| `find.text({ query })` | Search for text in files | Array of match objects with `path`, `lines`, `line_number`, `absolute_offset`, `submatches` | -| `find.files({ query })` | Find files and directories by name | `string[]` (paths) | -| `find.symbols({ query })` | Find workspace symbols | <a href={typesUrl}><code>Symbol[]</code></a> | -| `file.read({ query })` | Read a file | `{ type: "raw" \| "patch", content: string }` | -| `file.status({ query? })` | Get status for tracked files | <a href={typesUrl}><code>File[]</code></a> | +| Method | Description | Response | +| ------------------------- | ------------------------------------------- | ------------------------------------------------------------------------------------------- | +| `find.text({ query })` | Sucht Text in Dateien | Array of match objects with `path`, `lines`, `line_number`, `absolute_offset`, `submatches` | +| `find.files({ query })` | Findet Dateien und Verzeichnisse nach Namen | `string[]` (paths) | +| `find.symbols({ query })` | Findet Workspace-Symbole | <a href={typesUrl}><code>Symbol[]</code></a> | +| `file.read({ query })` | Liest eine Datei | `{ type: "raw" \| "patch", content: string }` | +| `file.status({ query? })` | Ruft Status fuer getrackte Dateien ab | <a href={typesUrl}><code>File[]</code></a> | -`find.files` supports a few optional query fields: +`find.files` unterstuetzt einige optionale Query-Felder: -- `type`: `"file"` or `"directory"` -- `directory`: override the project root for the search -- `limit`: max results (1–200) +- `type`: `"file"` oder `"directory"` +- `directory`: Ueberschreibt das Projekt-Root fuer die Suche +- `limit`: Maximale Ergebnisse (1–200) --- @@ -326,17 +398,17 @@ const content = await client.file.read({ ### TUI -| Method | Description | Response | -| ------------------------------ | ------------------------- | --------- | -| `tui.appendPrompt({ body })` | Append text to the prompt | `boolean` | -| `tui.openHelp()` | Open the help dialog | `boolean` | -| `tui.openSessions()` | Open the session selector | `boolean` | -| `tui.openThemes()` | Open the theme selector | `boolean` | -| `tui.openModels()` | Open the model selector | `boolean` | -| `tui.submitPrompt()` | Submit the current prompt | `boolean` | -| `tui.clearPrompt()` | Clear the prompt | `boolean` | -| `tui.executeCommand({ body })` | Execute a command | `boolean` | -| `tui.showToast({ body })` | Show toast notification | `boolean` | +| Method | Description | Response | +| ------------------------------ | ------------------------------ | --------- | +| `tui.appendPrompt({ body })` | Haengt Text an den Prompt an | `boolean` | +| `tui.openHelp()` | Oeffnet den Hilfedialog | `boolean` | +| `tui.openSessions()` | Oeffnet die Session-Auswahl | `boolean` | +| `tui.openThemes()` | Oeffnet die Theme-Auswahl | `boolean` | +| `tui.openModels()` | Oeffnet die Modell-Auswahl | `boolean` | +| `tui.submitPrompt()` | Sendet den aktuellen Prompt ab | `boolean` | +| `tui.clearPrompt()` | Leert den Prompt | `boolean` | +| `tui.executeCommand({ body })` | Fuehrt einen Befehl aus | `boolean` | +| `tui.showToast({ body })` | Zeigt Toast-Benachrichtigung | `boolean` | --- @@ -357,9 +429,9 @@ await client.tui.showToast({ ### Auth -| Method | Description | Response | -| ------------------- | ------------------------------ | --------- | -| `auth.set({ ... })` | Set authentication credentials | `boolean` | +| Method | Description | Response | +| ------------------- | ----------------------------- | --------- | +| `auth.set({ ... })` | Setzt Authentifizierungsdaten | `boolean` | --- @@ -378,7 +450,7 @@ await client.auth.set({ | Method | Description | Response | | ------------------- | ------------------------- | ------------------------- | -| `event.subscribe()` | Server-sent events stream | Server-sent events stream | +| `event.subscribe()` | Server-Sent Events Stream | Server-sent events stream | --- diff --git a/packages/web/src/content/docs/de/server.mdx b/packages/web/src/content/docs/de/server.mdx index dd4a565faf..64322bda85 100644 --- a/packages/web/src/content/docs/de/server.mdx +++ b/packages/web/src/content/docs/de/server.mdx @@ -93,28 +93,28 @@ Der opencode-Server stellt folgende APIs bereit. ### Global -| Method | Path | Description | Response | -| ------ | ---------------- | ------------------------------ | ------------------------------------ | -| `GET` | `/global/health` | Get server health and version | `{ healthy: true, version: string }` | -| `GET` | `/global/event` | Get global events (SSE stream) | Event stream | +| Method | Path | Description | Response | +| ------ | ---------------- | ----------------------------------- | ------------------------------------ | +| `GET` | `/global/health` | Ruft Server-Status und Version ab | `{ healthy: true, version: string }` | +| `GET` | `/global/event` | Ruft globale Events ab (SSE-Stream) | Event stream | --- ### Project -| Method | Path | Description | Response | -| ------ | ------------------ | ----------------------- | --------------------------------------------- | -| `GET` | `/project` | List all projects | <a href={typesUrl}><code>Project[]</code></a> | -| `GET` | `/project/current` | Get the current project | <a href={typesUrl}><code>Project</code></a> | +| Method | Path | Description | Response | +| ------ | ------------------ | ---------------------------- | --------------------------------------------- | +| `GET` | `/project` | Listet alle Projekte | <a href={typesUrl}><code>Project[]</code></a> | +| `GET` | `/project/current` | Ruft das aktuelle Projekt ab | <a href={typesUrl}><code>Project</code></a> | --- ### Path & VCS -| Method | Path | Description | Response | -| ------ | ------- | ------------------------------------ | ------------------------------------------- | -| `GET` | `/path` | Get the current path | <a href={typesUrl}><code>Path</code></a> | -| `GET` | `/vcs` | Get VCS info for the current project | <a href={typesUrl}><code>VcsInfo</code></a> | +| Method | Path | Description | Response | +| ------ | ------- | ------------------------------------------- | ------------------------------------------- | +| `GET` | `/path` | Ruft den aktuellen Pfad ab | <a href={typesUrl}><code>Path</code></a> | +| `GET` | `/vcs` | Ruft VCS-Infos fuer das aktuelle Projekt ab | <a href={typesUrl}><code>VcsInfo</code></a> | --- @@ -122,87 +122,87 @@ Der opencode-Server stellt folgende APIs bereit. | Method | Path | Description | Response | | ------ | ------------------- | ---------------------------- | --------- | -| `POST` | `/instance/dispose` | Dispose the current instance | `boolean` | +| `POST` | `/instance/dispose` | Beendet die aktuelle Instanz | `boolean` | --- ### Konfiguration -| Method | Path | Description | Response | -| ------- | ------------------- | --------------------------------- | ---------------------------------------------------------------------------------------- | -| `GET` | `/config` | Get config info | <a href={typesUrl}><code>Config</code></a> | -| `PATCH` | `/config` | Update config | <a href={typesUrl}><code>Config</code></a> | -| `GET` | `/config/providers` | List providers and default models | `{ providers: `<a href={typesUrl}>Provider[]</a>`, default: { [key: string]: string } }` | +| Method | Path | Description | Response | +| ------- | ------------------- | ------------------------------------ | ---------------------------------------------------------------------------------------- | +| `GET` | `/config` | Ruft Konfigurationsinfos ab | <a href={typesUrl}><code>Config</code></a> | +| `PATCH` | `/config` | Aktualisiert Konfiguration | <a href={typesUrl}><code>Config</code></a> | +| `GET` | `/config/providers` | Listet Provider und Standard-Modelle | `{ providers: `<a href={typesUrl}>Provider[]</a>`, default: { [key: string]: string } }` | --- ### Anbieter -| Method | Path | Description | Response | -| ------ | -------------------------------- | ------------------------------------ | ----------------------------------------------------------------------------------- | -| `GET` | `/provider` | List all providers | `{ all: `<a href={typesUrl}>Provider[]</a>`, default: {...}, connected: string[] }` | -| `GET` | `/provider/auth` | Get provider authentication methods | `{ [providerID: string]: `<a href={typesUrl}>ProviderAuthMethod[]</a>` }` | -| `POST` | `/provider/{id}/oauth/authorize` | Authorize a provider using OAuth | <a href={typesUrl}><code>ProviderAuthAuthorization</code></a> | -| `POST` | `/provider/{id}/oauth/callback` | Handle OAuth callback for a provider | `boolean` | +| Method | Path | Description | Response | +| ------ | -------------------------------- | ----------------------------------------------- | ----------------------------------------------------------------------------------- | +| `GET` | `/provider` | Listet alle Provider | `{ all: `<a href={typesUrl}>Provider[]</a>`, default: {...}, connected: string[] }` | +| `GET` | `/provider/auth` | Ruft Authentifizierungsmethoden der Provider ab | `{ [providerID: string]: `<a href={typesUrl}>ProviderAuthMethod[]</a>` }` | +| `POST` | `/provider/{id}/oauth/authorize` | Autorisiert einen Provider per OAuth | <a href={typesUrl}><code>ProviderAuthAuthorization</code></a> | +| `POST` | `/provider/{id}/oauth/callback` | Behandelt OAuth-Callback fuer einen Provider | `boolean` | --- ### Sitzungen -| Method | Path | Description | Notes | -| -------- | ---------------------------------------- | ------------------------------------- | ---------------------------------------------------------------------------------- | -| `GET` | `/session` | List all sessions | Returns <a href={typesUrl}><code>Session[]</code></a> | -| `POST` | `/session` | Create a new session | body: `{ parentID?, title? }`, returns <a href={typesUrl}><code>Session</code></a> | -| `GET` | `/session/status` | Get session status for all sessions | Returns `{ [sessionID: string]: `<a href={typesUrl}>SessionStatus</a>` }` | -| `GET` | `/session/:id` | Get session details | Returns <a href={typesUrl}><code>Session</code></a> | -| `DELETE` | `/session/:id` | Delete a session and all its data | Returns `boolean` | -| `PATCH` | `/session/:id` | Update session properties | body: `{ title? }`, returns <a href={typesUrl}><code>Session</code></a> | -| `GET` | `/session/:id/children` | Get a session's child sessions | Returns <a href={typesUrl}><code>Session[]</code></a> | -| `GET` | `/session/:id/todo` | Get the todo list for a session | Returns <a href={typesUrl}><code>Todo[]</code></a> | -| `POST` | `/session/:id/init` | Analyze app and create `AGENTS.md` | body: `{ messageID, providerID, modelID }`, returns `boolean` | -| `POST` | `/session/:id/fork` | Fork an existing session at a message | body: `{ messageID? }`, returns <a href={typesUrl}><code>Session</code></a> | -| `POST` | `/session/:id/abort` | Abort a running session | Returns `boolean` | -| `POST` | `/session/:id/share` | Share a session | Returns <a href={typesUrl}><code>Session</code></a> | -| `DELETE` | `/session/:id/share` | Unshare a session | Returns <a href={typesUrl}><code>Session</code></a> | -| `GET` | `/session/:id/diff` | Get the diff for this session | query: `messageID?`, returns <a href={typesUrl}><code>FileDiff[]</code></a> | -| `POST` | `/session/:id/summarize` | Summarize the session | body: `{ providerID, modelID }`, returns `boolean` | -| `POST` | `/session/:id/revert` | Revert a message | body: `{ messageID, partID? }`, returns `boolean` | -| `POST` | `/session/:id/unrevert` | Restore all reverted messages | Returns `boolean` | -| `POST` | `/session/:id/permissions/:permissionID` | Respond to a permission request | body: `{ response, remember? }`, returns `boolean` | +| Method | Path | Description | Notes | +| -------- | ---------------------------------------- | --------------------------------------------------- | ---------------------------------------------------------------------------------- | +| `GET` | `/session` | Listet alle Sitzungen | Gibt <a href={typesUrl}><code>Session[]</code></a> zurueck | +| `POST` | `/session` | Erstellt eine neue Sitzung | body: `{ parentID?, title? }`, returns <a href={typesUrl}><code>Session</code></a> | +| `GET` | `/session/status` | Ruft Status aller Sitzungen ab | Gibt `{ [sessionID: string]: `<a href={typesUrl}>SessionStatus</a>` }` zurueck | +| `GET` | `/session/:id` | Ruft Sitzungsdetails ab | Gibt <a href={typesUrl}><code>Session</code></a> zurueck | +| `DELETE` | `/session/:id` | Loescht eine Sitzung und alle Daten | Gibt `boolean` zurueck | +| `PATCH` | `/session/:id` | Aktualisiert Sitzungseigenschaften | body: `{ title? }`, returns <a href={typesUrl}><code>Session</code></a> | +| `GET` | `/session/:id/children` | Ruft Kind-Sitzungen einer Sitzung ab | Gibt <a href={typesUrl}><code>Session[]</code></a> zurueck | +| `GET` | `/session/:id/todo` | Ruft die Todo-Liste einer Sitzung ab | Gibt <a href={typesUrl}><code>Todo[]</code></a> zurueck | +| `POST` | `/session/:id/init` | Analysiert App und erstellt `AGENTS.md` | body: `{ messageID, providerID, modelID }`, returns `boolean` | +| `POST` | `/session/:id/fork` | Forkt eine bestehende Sitzung an einer Nachricht | body: `{ messageID? }`, returns <a href={typesUrl}><code>Session</code></a> | +| `POST` | `/session/:id/abort` | Bricht eine laufende Sitzung ab | Gibt `boolean` zurueck | +| `POST` | `/session/:id/share` | Teilt eine Sitzung | Gibt <a href={typesUrl}><code>Session</code></a> zurueck | +| `DELETE` | `/session/:id/share` | Hebt Teilen einer Sitzung auf | Gibt <a href={typesUrl}><code>Session</code></a> zurueck | +| `GET` | `/session/:id/diff` | Ruft den Diff fuer diese Sitzung ab | query: `messageID?`, returns <a href={typesUrl}><code>FileDiff[]</code></a> | +| `POST` | `/session/:id/summarize` | Fasst die Sitzung zusammen | body: `{ providerID, modelID }`, returns `boolean` | +| `POST` | `/session/:id/revert` | Setzt eine Nachricht zurueck | body: `{ messageID, partID? }`, returns `boolean` | +| `POST` | `/session/:id/unrevert` | Stellt alle zurueckgesetzten Nachrichten wieder her | Gibt `boolean` zurueck | +| `POST` | `/session/:id/permissions/:permissionID` | Antwortet auf eine Berechtigungsanfrage | body: `{ response, remember? }`, returns `boolean` | --- ### Nachrichten -| Method | Path | Description | Notes | -| ------ | --------------------------------- | --------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `GET` | `/session/:id/message` | List messages in a session | query: `limit?`, returns `{ info: `<a href={typesUrl}>Message</a>`, parts: `<a href={typesUrl}>Part[]</a>`}[]` | -| `POST` | `/session/:id/message` | Send a message and wait for response | body: `{ messageID?, model?, agent?, noReply?, system?, tools?, parts }`, returns `{ info: `<a href={typesUrl}>Message</a>`, parts: `<a href={typesUrl}>Part[]</a>`}` | -| `GET` | `/session/:id/message/:messageID` | Get message details | Returns `{ info: `<a href={typesUrl}>Message</a>`, parts: `<a href={typesUrl}>Part[]</a>`}` | -| `POST` | `/session/:id/prompt_async` | Send a message asynchronously (no wait) | body: same as `/session/:id/message`, returns `204 No Content` | -| `POST` | `/session/:id/command` | Execute a slash command | body: `{ messageID?, agent?, model?, command, arguments }`, returns `{ info: `<a href={typesUrl}>Message</a>`, parts: `<a href={typesUrl}>Part[]</a>`}` | -| `POST` | `/session/:id/shell` | Run a shell command | body: `{ agent, model?, command }`, returns `{ info: `<a href={typesUrl}>Message</a>`, parts: `<a href={typesUrl}>Part[]</a>`}` | +| Method | Path | Description | Notes | +| ------ | --------------------------------- | --------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `GET` | `/session/:id/message` | Listet Nachrichten in einer Sitzung | query: `limit?`, returns `{ info: `<a href={typesUrl}>Message</a>`, parts: `<a href={typesUrl}>Part[]</a>`}[]` | +| `POST` | `/session/:id/message` | Sendet eine Nachricht und wartet auf Antwort | body: `{ messageID?, model?, agent?, noReply?, system?, tools?, parts }`, returns `{ info: `<a href={typesUrl}>Message</a>`, parts: `<a href={typesUrl}>Part[]</a>`}` | +| `GET` | `/session/:id/message/:messageID` | Ruft Nachrichtendetails ab | Returns `{ info: `<a href={typesUrl}>Message</a>`, parts: `<a href={typesUrl}>Part[]</a>`}` | +| `POST` | `/session/:id/prompt_async` | Sendet eine Nachricht asynchron (ohne Warten) | body: same as `/session/:id/message`, returns `204 No Content` | +| `POST` | `/session/:id/command` | Fuehrt einen Slash-Befehl aus | body: `{ messageID?, agent?, model?, command, arguments }`, returns `{ info: `<a href={typesUrl}>Message</a>`, parts: `<a href={typesUrl}>Part[]</a>`}` | +| `POST` | `/session/:id/shell` | Fuehrt einen Shell-Befehl aus | body: `{ agent, model?, command }`, returns `{ info: `<a href={typesUrl}>Message</a>`, parts: `<a href={typesUrl}>Part[]</a>`}` | --- ### Befehle -| Method | Path | Description | Response | -| ------ | ---------- | ----------------- | --------------------------------------------- | -| `GET` | `/command` | List all commands | <a href={typesUrl}><code>Command[]</code></a> | +| Method | Path | Description | Response | +| ------ | ---------- | ------------------- | --------------------------------------------- | +| `GET` | `/command` | Listet alle Befehle | <a href={typesUrl}><code>Command[]</code></a> | --- ### Dateien -| Method | Path | Description | Response | -| ------ | ------------------------ | ---------------------------------- | ------------------------------------------------------------------------------------------- | -| `GET` | `/find?pattern=<pat>` | Search for text in files | Array of match objects with `path`, `lines`, `line_number`, `absolute_offset`, `submatches` | -| `GET` | `/find/file?query=<q>` | Find files and directories by name | `string[]` (paths) | -| `GET` | `/find/symbol?query=<q>` | Find workspace symbols | <a href={typesUrl}><code>Symbol[]</code></a> | -| `GET` | `/file?path=<path>` | List files and directories | <a href={typesUrl}><code>FileNode[]</code></a> | -| `GET` | `/file/content?path=<p>` | Read a file | <a href={typesUrl}><code>FileContent</code></a> | -| `GET` | `/file/status` | Get status for tracked files | <a href={typesUrl}><code>File[]</code></a> | +| Method | Path | Description | Response | +| ------ | ------------------------ | ------------------------------------------- | ------------------------------------------------------------------------------------------- | +| `GET` | `/find?pattern=<pat>` | Sucht Text in Dateien | Array of match objects with `path`, `lines`, `line_number`, `absolute_offset`, `submatches` | +| `GET` | `/find/file?query=<q>` | Findet Dateien und Verzeichnisse nach Namen | `string[]` (paths) | +| `GET` | `/find/symbol?query=<q>` | Findet Workspace-Symbole | <a href={typesUrl}><code>Symbol[]</code></a> | +| `GET` | `/file?path=<path>` | Listet Dateien und Verzeichnisse | <a href={typesUrl}><code>FileNode[]</code></a> | +| `GET` | `/file/content?path=<p>` | Liest eine Datei | <a href={typesUrl}><code>FileContent</code></a> | +| `GET` | `/file/status` | Ruft Status fuer getrackte Dateien ab | <a href={typesUrl}><code>File[]</code></a> | #### `/find/file` Abfrageparameter @@ -216,71 +216,71 @@ Der opencode-Server stellt folgende APIs bereit. ### Werkzeuge (Experimentell) -| Method | Path | Description | Response | -| ------ | ------------------------------------------- | ---------------------------------------- | -------------------------------------------- | -| `GET` | `/experimental/tool/ids` | List all tool IDs | <a href={typesUrl}><code>ToolIDs</code></a> | -| `GET` | `/experimental/tool?provider=<p>&model=<m>` | List tools with JSON schemas for a model | <a href={typesUrl}><code>ToolList</code></a> | +| Method | Path | Description | Response | +| ------ | ------------------------------------------- | --------------------------------------------- | -------------------------------------------- | +| `GET` | `/experimental/tool/ids` | Listet alle Tool-IDs | <a href={typesUrl}><code>ToolIDs</code></a> | +| `GET` | `/experimental/tool?provider=<p>&model=<m>` | Listet Tools mit JSON-Schemas fuer ein Modell | <a href={typesUrl}><code>ToolList</code></a> | --- ### LSP, Formatierer & MCP -| Method | Path | Description | Response | -| ------ | ------------ | -------------------------- | -------------------------------------------------------- | -| `GET` | `/lsp` | Get LSP server status | <a href={typesUrl}><code>LSPStatus[]</code></a> | -| `GET` | `/formatter` | Get formatter status | <a href={typesUrl}><code>FormatterStatus[]</code></a> | -| `GET` | `/mcp` | Get MCP server status | `{ [name: string]: `<a href={typesUrl}>MCPStatus</a>` }` | -| `POST` | `/mcp` | Add MCP server dynamically | body: `{ name, config }`, returns MCP status object | +| Method | Path | Description | Response | +| ------ | ------------ | -------------------------------- | -------------------------------------------------------- | +| `GET` | `/lsp` | Ruft LSP-Server-Status ab | <a href={typesUrl}><code>LSPStatus[]</code></a> | +| `GET` | `/formatter` | Ruft Formatter-Status ab | <a href={typesUrl}><code>FormatterStatus[]</code></a> | +| `GET` | `/mcp` | Ruft MCP-Server-Status ab | `{ [name: string]: `<a href={typesUrl}>MCPStatus</a>` }` | +| `POST` | `/mcp` | Fuegt MCP-Server dynamisch hinzu | body: `{ name, config }`, returns MCP status object | --- ### Agenten -| Method | Path | Description | Response | -| ------ | -------- | ------------------------- | ------------------------------------------- | -| `GET` | `/agent` | List all available agents | <a href={typesUrl}><code>Agent[]</code></a> | +| Method | Path | Description | Response | +| ------ | -------- | -------------------------------- | ------------------------------------------- | +| `GET` | `/agent` | Listet alle verfuegbaren Agenten | <a href={typesUrl}><code>Agent[]</code></a> | --- ### Logging -| Method | Path | Description | Response | -| ------ | ------ | ------------------------------------------------------------ | --------- | -| `POST` | `/log` | Write log entry. Body: `{ service, level, message, extra? }` | `boolean` | +| Method | Path | Description | Response | +| ------ | ------ | ----------------------------------------------------------------- | --------- | +| `POST` | `/log` | Schreibt Log-Eintrag. Body: `{ service, level, message, extra? }` | `boolean` | --- ### TUI -| Method | Path | Description | Response | -| ------ | ----------------------- | ------------------------------------------- | ---------------------- | -| `POST` | `/tui/append-prompt` | Append text to the prompt | `boolean` | -| `POST` | `/tui/open-help` | Open the help dialog | `boolean` | -| `POST` | `/tui/open-sessions` | Open the session selector | `boolean` | -| `POST` | `/tui/open-themes` | Open the theme selector | `boolean` | -| `POST` | `/tui/open-models` | Open the model selector | `boolean` | -| `POST` | `/tui/submit-prompt` | Submit the current prompt | `boolean` | -| `POST` | `/tui/clear-prompt` | Clear the prompt | `boolean` | -| `POST` | `/tui/execute-command` | Execute a command (`{ command }`) | `boolean` | -| `POST` | `/tui/show-toast` | Show toast (`{ title?, message, variant }`) | `boolean` | -| `GET` | `/tui/control/next` | Wait for the next control request | Control request object | -| `POST` | `/tui/control/response` | Respond to a control request (`{ body }`) | `boolean` | +| Method | Path | Description | Response | +| ------ | ----------------------- | ----------------------------------------------- | ---------------------- | +| `POST` | `/tui/append-prompt` | Haengt Text an den Prompt an | `boolean` | +| `POST` | `/tui/open-help` | Oeffnet den Hilfedialog | `boolean` | +| `POST` | `/tui/open-sessions` | Oeffnet die Session-Auswahl | `boolean` | +| `POST` | `/tui/open-themes` | Oeffnet die Theme-Auswahl | `boolean` | +| `POST` | `/tui/open-models` | Oeffnet die Modell-Auswahl | `boolean` | +| `POST` | `/tui/submit-prompt` | Sendet den aktuellen Prompt ab | `boolean` | +| `POST` | `/tui/clear-prompt` | Leert den Prompt | `boolean` | +| `POST` | `/tui/execute-command` | Fuehrt einen Befehl aus (`{ command }`) | `boolean` | +| `POST` | `/tui/show-toast` | Zeigt Toast (`{ title?, message, variant }`) | `boolean` | +| `GET` | `/tui/control/next` | Wartet auf die naechste Kontrollanfrage | Control request object | +| `POST` | `/tui/control/response` | Antwortet auf eine Kontrollanfrage (`{ body }`) | `boolean` | --- ### Authentifizierung -| Method | Path | Description | Response | -| ------ | ----------- | --------------------------------------------------------------- | --------- | -| `PUT` | `/auth/:id` | Set authentication credentials. Body must match provider schema | `boolean` | +| Method | Path | Description | Response | +| ------ | ----------- | ------------------------------------------------------------------------ | --------- | +| `PUT` | `/auth/:id` | Setzt Authentifizierungsdaten. Body muss dem Provider-Schema entsprechen | `boolean` | --- ### Events -| Method | Path | Description | Response | -| ------ | -------- | ----------------------------------------------------------------------------- | ------------------------- | -| `GET` | `/event` | Server-sent events stream. First event is `server.connected`, then bus events | Server-sent events stream | +| Method | Path | Description | Response | +| ------ | -------- | ------------------------------------------------------------------------------- | ------------------------- | +| `GET` | `/event` | Server-Sent Events Stream. Erstes Event ist `server.connected`, dann Bus-Events | Server-sent events stream | --- @@ -288,4 +288,4 @@ Der opencode-Server stellt folgende APIs bereit. | Method | Path | Description | Response | | ------ | ------ | ------------------------- | --------------------------- | -| `GET` | `/doc` | OpenAPI 3.1 specification | HTML page with OpenAPI spec | +| `GET` | `/doc` | OpenAPI 3.1 Spezifikation | HTML page with OpenAPI spec | diff --git a/packages/web/src/content/docs/de/share.mdx b/packages/web/src/content/docs/de/share.mdx index 99fad21099..9b7e9284c7 100644 --- a/packages/web/src/content/docs/de/share.mdx +++ b/packages/web/src/content/docs/de/share.mdx @@ -43,7 +43,7 @@ Um den manuellen Modus explizit in der [Konfiguration](/docs/config) zu setzen: ```json title="opencode.json" { - "$schema": "https://opncd.ai/config.json", + "$schema": "https://opencode.ai/config.json", "share": "manual" } ``` @@ -56,7 +56,7 @@ Du kannst automatisches Teilen fuer neue Unterhaltungen aktivieren, indem du in ```json title="opencode.json" { - "$schema": "https://opncd.ai/config.json", + "$schema": "https://opencode.ai/config.json", "share": "auto" } ``` @@ -71,7 +71,7 @@ Du kannst Teilen komplett deaktivieren, indem du in der [Konfiguration](/docs/co ```json title="opencode.json" { - "$schema": "https://opncd.ai/config.json", + "$schema": "https://opencode.ai/config.json", "share": "disabled" } ``` diff --git a/packages/web/src/content/docs/de/skills.mdx b/packages/web/src/content/docs/de/skills.mdx index 63dbb126bb..72fba3eb09 100644 --- a/packages/web/src/content/docs/de/skills.mdx +++ b/packages/web/src/content/docs/de/skills.mdx @@ -36,11 +36,11 @@ Globale Definitionen kommen zusaetzlich aus `~/.config/opencode/skills/*/SKILL.m Jede `SKILL.md` muss mit YAML-Frontmatter beginnen. Nur diese Felder werden ausgewertet: -- `name` (required) -- `description` (required) +- `name` (erforderlich) +- `description` (erforderlich) - `license` (optional) - `compatibility` (optional) -- `metadata` (optional, string-to-string map) +- `metadata` (optional, String-zu-String-Map) Unbekannte Frontmatter-Felder werden ignoriert. diff --git a/packages/web/src/content/docs/de/themes.mdx b/packages/web/src/content/docs/de/themes.mdx index b97816801d..f3671220f9 100644 --- a/packages/web/src/content/docs/de/themes.mdx +++ b/packages/web/src/content/docs/de/themes.mdx @@ -83,29 +83,29 @@ Damit lassen sich Themes einfach erstellen und anpassen. ### Hierarchie -Themes are loaded from multiple directories in the following order where later directories override earlier ones: +Themes werden aus mehreren Verzeichnissen in folgender Reihenfolge geladen, wobei spaetere Verzeichnisse fruehere ueberschreiben: -1. **Built-in themes** - These are embedded in the binary -2. **User config directory** - Defined in `~/.config/opencode/themes/*.json` or `$XDG_CONFIG_HOME/opencode/themes/*.json` -3. **Project root directory** - Defined in the `<project-root>/.opencode/themes/*.json` -4. **Current working directory** - Defined in `./.opencode/themes/*.json` +1. **Eingebaute Themes** - Diese sind im Binary eingebettet +2. **Benutzer-Config-Verzeichnis** - Definiert in `~/.config/opencode/themes/*.json` oder `$XDG_CONFIG_HOME/opencode/themes/*.json` +3. **Projekt-Root-Verzeichnis** - Definiert in `<project-root>/.opencode/themes/*.json` +4. **Aktuelles Arbeitsverzeichnis** - Definiert in `./.opencode/themes/*.json` -If multiple directories contain a theme with the same name, the theme from the directory with higher priority will be used. +Wenn mehrere Verzeichnisse ein Theme mit demselben Namen enthalten, wird das Theme aus dem Verzeichnis mit der hoeheren Prioritaet verwendet. --- ### Theme erstellen -To create a custom theme, create a JSON file in one of the theme directories. +Um ein eigenes Theme zu erstellen, lege eine JSON-Datei in einem der Theme-Verzeichnisse an. -For user-wide themes: +Fuer benutzerweite Themes: ```bash no-frame mkdir -p ~/.config/opencode/themes vim ~/.config/opencode/themes/my-theme.json ``` -And for project-specific themes. +Und fuer projektspezifische Themes: ```bash no-frame mkdir -p .opencode/themes @@ -116,34 +116,34 @@ vim .opencode/themes/my-theme.json ### JSON-Format -Themes use a flexible JSON format with support for: +Themes nutzen ein flexibles JSON-Format mit Unterstuetzung fuer: -- **Hex colors**: `"#ffffff"` -- **ANSI colors**: `3` (0-255) -- **Color references**: `"primary"` or custom definitions -- **Dark/light variants**: `{"dark": "#000", "light": "#fff"}` -- **No color**: `"none"` - Uses the terminal's default color or transparent +- **Hex-Farben**: `"#ffffff"` +- **ANSI-Farben**: `3` (0-255) +- **Farbreferenzen**: `"primary"` oder eigene Definitionen +- **Dunkel/Hell-Varianten**: `{"dark": "#000", "light": "#fff"}` +- **Keine Farbe**: `"none"` - Nutzt die Standardfarbe des Terminals oder transparent --- ### Farbdefinitionen -The `defs` section is optional and it allows you to define reusable colors that can be referenced in the theme. +Der `defs`-Abschnitt ist optional und erlaubt es dir, wiederverwendbare Farben zu definieren, die im Theme referenziert werden koennen. --- ### Terminal-Standardwerte -The special value `"none"` can be used for any color to inherit the terminal's default color. This is particularly useful for creating themes that blend seamlessly with your terminal's color scheme: +Der spezielle Wert `"none"` kann fuer jede Farbe verwendet werden, um die Standardfarbe des Terminals zu erben. Das ist besonders nuetzlich, um Themes zu erstellen, die nahtlos mit deinem Terminal-Farbschema verschmelzen: -- `"text": "none"` - Uses terminal's default foreground color -- `"background": "none"` - Uses terminal's default background color +- `"text": "none"` - Nutzt die Standard-Vordergrundfarbe des Terminals +- `"background": "none"` - Nutzt die Standard-Hintergrundfarbe des Terminals --- ### Beispiel -Here's an example of a custom theme: +Hier ist ein Beispiel fuer ein eigenes Theme: ```json title="my-theme.json" { diff --git a/packages/web/src/content/docs/de/tools.mdx b/packages/web/src/content/docs/de/tools.mdx index b7a41d87bb..0038f25184 100644 --- a/packages/web/src/content/docs/de/tools.mdx +++ b/packages/web/src/content/docs/de/tools.mdx @@ -109,7 +109,7 @@ Das Tool `write` wird ueber die Berechtigung `edit` gesteuert. ### read -Read file contents from your codebase. +Liest Dateiinhalte aus deiner Codebasis. ```json title="opencode.json" {4} { @@ -120,13 +120,13 @@ Read file contents from your codebase. } ``` -This tool reads files and returns their contents. It supports reading specific line ranges for large files. +Dieses Tool liest Dateien und gibt deren Inhalt zurueck. Es unterstuetzt das Lesen spezifischer Zeilenbereiche bei grossen Dateien. --- ### grep -Search file contents using regular expressions. +Durchsucht Dateiinhalte mit regulaeren Ausdruecken. ```json title="opencode.json" {4} { @@ -137,13 +137,13 @@ Search file contents using regular expressions. } ``` -Fast content search across your codebase. Supports full regex syntax and file pattern filtering. +Schnelle Inhaltssuche in deiner Codebasis. Unterstuetzt volle Regex-Syntax und Filterung nach Dateimustern. --- ### glob -Find files by pattern matching. +Findet Dateien per Musterabgleich. ```json title="opencode.json" {4} { @@ -154,13 +154,13 @@ Find files by pattern matching. } ``` -Search for files using glob patterns like `**/*.js` or `src/**/*.ts`. Returns matching file paths sorted by modification time. +Sucht nach Dateien mit Glob-Mustern wie `**/*.js` oder `src/**/*.ts`. Gibt passende Dateipfade sortiert nach Aenderungsdatum zurueck. --- ### list -List files and directories in a given path. +Listet Dateien und Verzeichnisse in einem Pfad auf. ```json title="opencode.json" {4} { @@ -171,16 +171,16 @@ List files and directories in a given path. } ``` -This tool lists directory contents. It accepts glob patterns to filter results. +Dieses Tool listet Verzeichnisinhalte auf. Es akzeptiert Glob-Muster zum Filtern der Ergebnisse. --- -### lsp (experimental) +### lsp (experimentell) -Interact with your configured LSP servers to get code intelligence features like definitions, references, hover info, and call hierarchy. +Interagiere mit deinen konfigurierten LSP-Servern fuer Code-Intelligence-Features wie Definitionen, Referenzen, Hover-Infos und Call-Hierarchien. :::note -This tool is only available when `OPENCODE_EXPERIMENTAL_LSP_TOOL=true` (or `OPENCODE_EXPERIMENTAL=true`). +Dieses Tool ist nur verfuegbar, wenn `OPENCODE_EXPERIMENTAL_LSP_TOOL=true` (oder `OPENCODE_EXPERIMENTAL=true`) gesetzt ist. ::: ```json title="opencode.json" {4} @@ -192,15 +192,15 @@ This tool is only available when `OPENCODE_EXPERIMENTAL_LSP_TOOL=true` (or `OPEN } ``` -Supported operations include `goToDefinition`, `findReferences`, `hover`, `documentSymbol`, `workspaceSymbol`, `goToImplementation`, `prepareCallHierarchy`, `incomingCalls`, and `outgoingCalls`. +Unterstuetzte Operationen sind `goToDefinition`, `findReferences`, `hover`, `documentSymbol`, `workspaceSymbol`, `goToImplementation`, `prepareCallHierarchy`, `incomingCalls` und `outgoingCalls`. -To configure which LSP servers are available for your project, see [LSP Servers](/docs/lsp). +Um verfuegbare LSP-Server fuer dein Projekt zu konfigurieren, siehe [LSP-Server](/docs/lsp). --- ### patch -Apply patches to files. +Wendet Patches auf Dateien an. ```json title="opencode.json" {4} { @@ -211,17 +211,17 @@ Apply patches to files. } ``` -This tool applies patch files to your codebase. Useful for applying diffs and patches from various sources. +Dieses Tool wendet Patch-Dateien auf deine Codebasis an. Nuetzlich fuer Diffs und Patches aus verschiedenen Quellen. :::note -The `patch` tool is controlled by the `edit` permission, which covers all file modifications (`edit`, `write`, `patch`, `multiedit`). +Das Tool `patch` wird ueber die Berechtigung `edit` gesteuert, welche alle Datei-Aenderungen abdeckt (`edit`, `write`, `patch`, `multiedit`). ::: --- ### skill -Load a [skill](/docs/skills) (a `SKILL.md` file) and return its content in the conversation. +Laedt einen [Skill](/docs/skills) (eine `SKILL.md`-Datei) und gibt dessen Inhalt in der Unterhaltung zurueck. ```json title="opencode.json" {4} { @@ -236,7 +236,7 @@ Load a [skill](/docs/skills) (a `SKILL.md` file) and return its content in the c ### todowrite -Manage todo lists during coding sessions. +Verwaltet Todo-Listen waehrend Coding-Sessions. ```json title="opencode.json" {4} { @@ -247,17 +247,17 @@ Manage todo lists during coding sessions. } ``` -Creates and updates task lists to track progress during complex operations. The LLM uses this to organize multi-step tasks. +Erstellt und aktualisiert Aufgabenlisten, um den Fortschritt bei komplexen Operationen zu verfolgen. Das LLM nutzt dies, um mehrstufige Aufgaben zu organisieren. :::note -This tool is disabled for subagents by default, but you can enable it manually. [Learn more](/docs/agents/#permissions) +Dieses Tool ist fuer Sub-Agenten standardmaessig deaktiviert, kann aber manuell aktiviert werden. [Mehr dazu](/docs/agents/#permissions) ::: --- ### todoread -Read existing todo lists. +Liest existierende Todo-Listen. ```json title="opencode.json" {4} { @@ -268,17 +268,17 @@ Read existing todo lists. } ``` -Reads the current todo list state. Used by the LLM to track what tasks are pending or completed. +Liest den aktuellen Status der Todo-Liste. Wird vom LLM genutzt, um offene oder erledigte Aufgaben zu verfolgen. :::note -This tool is disabled for subagents by default, but you can enable it manually. [Learn more](/docs/agents/#permissions) +Dieses Tool ist fuer Sub-Agenten standardmaessig deaktiviert, kann aber manuell aktiviert werden. [Mehr dazu](/docs/agents/#permissions) ::: --- ### webfetch -Fetch web content. +Ruft Webinhalte ab. ```json title="opencode.json" {4} { @@ -289,18 +289,18 @@ Fetch web content. } ``` -Allows the LLM to fetch and read web pages. Useful for looking up documentation or researching online resources. +Erlaubt dem LLM, Webseiten abzurufen und zu lesen. Nuetzlich zum Nachschlagen von Dokumentation oder fuer Online-Recherche. --- ### websearch -Search the web for information. +Durchsucht das Web nach Informationen. :::note -This tool is only available when using the OpenCode provider or when the `OPENCODE_ENABLE_EXA` environment variable is set to any truthy value (e.g., `true` or `1`). +Dieses Tool ist nur verfuegbar, wenn der OpenCode-Provider genutzt wird oder die Umgebungsvariable `OPENCODE_ENABLE_EXA` auf einen 'truthy' Wert (z. B. `true` oder `1`) gesetzt ist. -To enable when launching OpenCode: +Zum Aktivieren beim Start von OpenCode: ```bash OPENCODE_ENABLE_EXA=1 opencode @@ -317,19 +317,19 @@ OPENCODE_ENABLE_EXA=1 opencode } ``` -Performs web searches using Exa AI to find relevant information online. Useful for researching topics, finding current events, or gathering information beyond the training data cutoff. +Fuehrt Websuchen mit Exa AI durch, um relevante Informationen online zu finden. Nuetzlich fuer Recherche, aktuelle Ereignisse oder Informationen jenseits des Trainingsdatums. -No API key is required — the tool connects directly to Exa AI's hosted MCP service without authentication. +Kein API-Key erforderlich — das Tool verbindet sich direkt mit dem gehosteten MCP-Service von Exa AI ohne Authentifizierung. :::tip -Use `websearch` when you need to find information (discovery), and `webfetch` when you need to retrieve content from a specific URL (retrieval). +Nutze `websearch` zum Finden von Informationen (Discovery) und `webfetch` zum Abrufen von Inhalten einer spezifischen URL (Retrieval). ::: --- ### question -Ask the user questions during execution. +Stellt dem Benutzer waehrend der Ausfuehrung Fragen. ```json title="opencode.json" {4} { @@ -340,14 +340,14 @@ Ask the user questions during execution. } ``` -This tool allows the LLM to ask the user questions during a task. It's useful for: +Dieses Tool erlaubt dem LLM, dem Benutzer waehrend einer Aufgabe Fragen zu stellen. Nuetzlich fuer: -- Gathering user preferences or requirements -- Clarifying ambiguous instructions -- Getting decisions on implementation choices -- Offering choices about what direction to take +- Sammeln von Benutzerpraeferenzen oder Anforderungen +- Klaerung mehrdeutiger Anweisungen +- Entscheidungen bei Implementierungsoptionen einholen +- Auswahlmoeglichkeiten fuer das weitere Vorgehen anbieten -Each question includes a header, the question text, and a list of options. Users can select from the provided options or type a custom answer. When there are multiple questions, users can navigate between them before submitting all answers. +Jede Frage enthaelt eine Ueberschrift, den Fragetext und eine Liste von Optionen. Benutzer koennen aus den Optionen waehlen oder eine eigene Antwort eingeben. Bei mehreren Fragen koennen Benutzer zwischen ihnen navigieren, bevor sie alle Antworten absenden. --- diff --git a/packages/web/src/content/docs/de/troubleshooting.mdx b/packages/web/src/content/docs/de/troubleshooting.mdx index 076200cbd9..e8286faca0 100644 --- a/packages/web/src/content/docs/de/troubleshooting.mdx +++ b/packages/web/src/content/docs/de/troubleshooting.mdx @@ -12,7 +12,7 @@ Wenn OpenCode Probleme macht, starte mit Logs und lokal gespeicherten Daten auf Logdateien werden hier gespeichert: - **macOS/Linux**: `~/.local/share/opencode/log/` -- **Windows**: Press `WIN+R` and paste `%USERPROFILE%\.local\share\opencode\log` +- **Windows**: Druecke `WIN+R` und fuege ein: `%USERPROFILE%\.local\share\opencode\log` Dateinamen enthalten Zeitstempel (z. B. `2025-01-09T123456.log`) und es bleiben die letzten 10 Logs erhalten. @@ -25,7 +25,7 @@ Mit `--log-level` bekommst du detailliertere Diagnoseinfos, z. B. `opencode --lo opencode speichert Sitzungs- und App-Daten auf der Festplatte unter: - **macOS/Linux**: `~/.local/share/opencode/` -- **Windows**: Press `WIN+R` and paste `%USERPROFILE%\.local\share\opencode` +- **Windows**: Druecke `WIN+R` und fuege ein: `%USERPROFILE%\.local\share\opencode` Dieses Verzeichnis enthaelt: @@ -52,17 +52,17 @@ Viele Probleme kommen von fehlerhaften Plugins, kaputtem Cache oder falschen Ser ### Plugins deaktivieren -If the desktop app is crashing on launch, hanging, or behaving strangely, start by disabling plugins. +Wenn die Desktop-App beim Start abstuerzt, haengt oder sich seltsam verhaelt, deaktiviere zunaechst Plugins. #### Globale Konfiguration prüfen -Open your global config file and look for a `plugin` key. +Oeffne deine globale Konfigurationsdatei und suche nach dem `plugin`-Schluessel. -- **macOS/Linux**: `~/.config/opencode/opencode.jsonc` (or `~/.config/opencode/opencode.json`) -- **macOS/Linux** (older installs): `~/.local/share/opencode/opencode.jsonc` -- **Windows**: Press `WIN+R` and paste `%USERPROFILE%\.config\opencode\opencode.jsonc` +- **macOS/Linux**: `~/.config/opencode/opencode.jsonc` (oder `~/.config/opencode/opencode.json`) +- **macOS/Linux** (aeltere Installationen): `~/.local/share/opencode/opencode.jsonc` +- **Windows**: Druecke `WIN+R` und fuege ein: `%USERPROFILE%\.config\opencode\opencode.jsonc` -If you have plugins configured, temporarily disable them by removing the key or setting it to an empty array: +Wenn du Plugins konfiguriert hast, deaktiviere sie voruebergehend, indem du den Schluessel entfernst oder auf ein leeres Array setzt: ```jsonc { @@ -73,100 +73,100 @@ If you have plugins configured, temporarily disable them by removing the key or #### Plugin-Verzeichnisse prüfen -OpenCode can also load local plugins from disk. Temporarily move these out of the way (or rename the folder) and restart the desktop app: +OpenCode kann auch lokale Plugins von der Festplatte laden. Verschiebe diese voruebergehend (oder benenne den Ordner um) und starte die Desktop-App neu: -- **Global plugins** +- **Globale Plugins** - **macOS/Linux**: `~/.config/opencode/plugins/` - - **Windows**: Press `WIN+R` and paste `%USERPROFILE%\.config\opencode\plugins` -- **Project plugins** (only if you use per-project config) + - **Windows**: Druecke `WIN+R` und fuege ein: `%USERPROFILE%\.config\opencode\plugins` +- **Projekt-Plugins** (nur bei projektspezifischer Konfig) - `<your-project>/.opencode/plugins/` -If the app starts working again, re-enable plugins one at a time to find which one is causing the issue. +Wenn die App wieder funktioniert, aktiviere Plugins nacheinander, um den Verursacher zu finden. --- ### Cache leeren -If disabling plugins doesn't help (or a plugin install is stuck), clear the cache so OpenCode can rebuild it. +Wenn das Deaktivieren von Plugins nicht hilft (oder eine Plugin-Installation haengt), leere den Cache, damit OpenCode ihn neu aufbauen kann. -1. Quit OpenCode Desktop completely. -2. Delete the cache directory: +1. Beende OpenCode Desktop komplett. +2. Loesche das Cache-Verzeichnis: -- **macOS**: Finder -> `Cmd+Shift+G` -> paste `~/.cache/opencode` -- **Linux**: delete `~/.cache/opencode` (or run `rm -rf ~/.cache/opencode`) -- **Windows**: Press `WIN+R` and paste `%USERPROFILE%\.cache\opencode` +- **macOS**: Finder -> `Cmd+Shift+G` -> einfuegen: `~/.cache/opencode` +- **Linux**: loesche `~/.cache/opencode` (oder fuehre aus: `rm -rf ~/.cache/opencode`) +- **Windows**: Druecke `WIN+R` und fuege ein: `%USERPROFILE%\.cache\opencode` -3. Restart OpenCode Desktop. +3. Starte OpenCode Desktop neu. --- ### Server-Verbindungsprobleme beheben -OpenCode Desktop can either start its own local server (default) or connect to a server URL you configured. +OpenCode Desktop kann entweder einen eigenen lokalen Server starten (Standard) oder sich mit einer konfigurierten Server-URL verbinden. -If you see a **"Connection Failed"** dialog (or the app never gets past the splash screen), check for a custom server URL. +Wenn du einen **"Connection Failed"**-Dialog siehst (oder die App beim Splash-Screen haengen bleibt), pruefe auf eine benutzerdefinierte Server-URL. #### Desktop-Standard-Server-URL löschen -From the Home screen, click the server name (with the status dot) to open the Server picker. In the **Default server** section, click **Clear**. +Klicke im Startbildschirm auf den Servernamen (mit dem Statuspunkt), um die Serverauswahl zu oeffnen. Klicke im Bereich **Default server** auf **Clear**. #### `server.port` / `server.hostname` aus Konfiguration entfernen -If your `opencode.json(c)` contains a `server` section, temporarily remove it and restart the desktop app. +Wenn deine `opencode.json(c)` einen `server`-Abschnitt enthaelt, entferne ihn voruebergehend und starte die Desktop-App neu. #### Umgebungsvariablen prüfen -If you have `OPENCODE_PORT` set in your environment, the desktop app will try to use that port for the local server. +Wenn du `OPENCODE_PORT` in deiner Umgebung gesetzt hast, versucht die Desktop-App diesen Port fuer den lokalen Server zu nutzen. -- Unset `OPENCODE_PORT` (or pick a free port) and restart. +- Setze `OPENCODE_PORT` zurueck (oder waehle einen freien Port) und starte neu. --- ### Linux: Wayland / X11-Probleme -On Linux, some Wayland setups can cause blank windows or compositor errors. +Unter Linux koennen manche Wayland-Setups leere Fenster oder Compositor-Fehler verursachen. -- If you're on Wayland and the app is blank/crashing, try launching with `OC_ALLOW_WAYLAND=1`. -- If that makes things worse, remove it and try launching under an X11 session instead. +- Wenn du Wayland nutzt und die App leer ist/abstuerzt, versuche den Start mit `OC_ALLOW_WAYLAND=1`. +- Wenn das es verschlimmert, entferne es und versuche den Start in einer X11-Session. --- ### Windows: WebView2-Laufzeit -On Windows, OpenCode Desktop requires the Microsoft Edge **WebView2 Runtime**. If the app opens to a blank window or won't start, install/update WebView2 and try again. +Unter Windows benoetigt OpenCode Desktop die Microsoft Edge **WebView2 Runtime**. Wenn die App ein leeres Fenster zeigt oder nicht startet, installiere/aktualisiere WebView2 und versuche es erneut. --- ### Windows: Allgemeine Performance-Probleme -If you're experiencing slow performance, file access issues, or terminal problems on Windows, try using [WSL (Windows Subsystem for Linux)](/docs/windows-wsl). WSL provides a Linux environment that works more seamlessly with OpenCode's features. +Wenn du langsame Performance, Dateizugriffsprobleme oder Terminal-Probleme unter Windows hast, versuche [WSL (Windows Subsystem for Linux)](/docs/windows-wsl). WSL bietet eine Linux-Umgebung, die nahtloser mit OpenCode-Features funktioniert. --- ### Benachrichtigungen werden nicht angezeigt -OpenCode Desktop only shows system notifications when: +OpenCode Desktop zeigt Systembenachrichtigungen nur wenn: -- notifications are enabled for OpenCode in your OS settings, and -- the app window is not focused. +- Benachrichtigungen fuer OpenCode in den OS-Einstellungen aktiviert sind, und +- das App-Fenster nicht fokussiert ist. --- ### Desktop-App-Speicher zurücksetzen (letzter Ausweg) -If the app won't start and you can't clear settings from inside the UI, reset the desktop app's saved state. +Wenn die App nicht startet und du Einstellungen nicht in der UI loeschen kannst, setze den gespeicherten Zustand der Desktop-App zurueck. -1. Quit OpenCode Desktop. -2. Find and delete these files (they live in the OpenCode Desktop app data directory): +1. Beende OpenCode Desktop. +2. Finde und loesche diese Dateien (im App-Data-Verzeichnis von OpenCode Desktop): - `opencode.settings.dat` (desktop default server URL) -- `opencode.global.dat` and `opencode.workspace.*.dat` (UI state like recent servers/projects) +- `opencode.global.dat` und `opencode.workspace.*.dat` (UI state like recent servers/projects) -To find the directory quickly: +So findest du das Verzeichnis schnell: -- **macOS**: Finder -> `Cmd+Shift+G` -> `~/Library/Application Support` (then search for the filenames above) -- **Linux**: search under `~/.local/share` for the filenames above -- **Windows**: Press `WIN+R` -> `%APPDATA%` (then search for the filenames above) +- **macOS**: Finder -> `Cmd+Shift+G` -> `~/Library/Application Support` (dann suche nach den Dateinamen oben) +- **Linux**: suche unter `~/.local/share` nach den Dateinamen oben +- **Windows**: Druecke `WIN+R` -> `%APPDATA%` (dann suche nach den Dateinamen oben) --- @@ -198,84 +198,83 @@ Hier sind typische Fehlerbilder und wie du sie loest. ### OpenCode startet nicht -1. Check the logs for error messages -2. Try running with `--print-logs` to see output in the terminal -3. Ensure you have the latest version with `opencode upgrade` +1. Pruefe die Logs auf Fehlermeldungen +2. Versuche den Start mit `--print-logs`, um Ausgaben im Terminal zu sehen +3. Stelle sicher, dass du die neueste Version hast: `opencode upgrade` --- ### Authentifizierungsprobleme -1. Try re-authenticating with the `/connect` command in the TUI -2. Check that your API keys are valid -3. Ensure your network allows connections to the provider's API +1. Versuche erneute Authentifizierung mit `/connect` in der TUI +2. Pruefe, ob deine API-Keys gueltig sind +3. Stelle sicher, dass dein Netzwerk Verbindungen zur Provider-API erlaubt --- ### Modell nicht verfügbar -1. Check that you've authenticated with the provider -2. Verify the model name in your config is correct -3. Some models may require specific access or subscriptions +1. Pruefe, ob du dich beim Provider authentifiziert hast +2. Verifiziere, dass der Modellname in deiner Config korrekt ist +3. Manche Modelle erfordern speziellen Zugriff oder Abonnements -If you encounter `ProviderModelNotFoundError` you are most likely incorrectly -referencing a model somewhere. -Models should be referenced like so: `<providerId>/<modelId>` +Wenn du `ProviderModelNotFoundError` erhaeltst, referenzierst du ein Modell wahrscheinlich falsch. +Modelle sollten so referenziert werden: `<providerId>/<modelId>` -Examples: +Beispiele: - `openai/gpt-4.1` - `openrouter/google/gemini-2.5-flash` - `opencode/kimi-k2` -To figure out what models you have access to, run `opencode models` +Um zu sehen, auf welche Modelle du Zugriff hast, fuehre `opencode models` aus. --- ### ProviderInitError -If you encounter a ProviderInitError, you likely have an invalid or corrupted configuration. +Wenn du einen ProviderInitError erhaeltst, hast du wahrscheinlich eine ungueltige oder korrupte Konfiguration. -To resolve this: +Zur Loesung: -1. First, verify your provider is set up correctly by following the [providers guide](/docs/providers) -2. If the issue persists, try clearing your stored configuration: +1. Pruefe zuerst, ob dein Provider korrekt eingerichtet ist, gemaess dem [Provider-Guide](/docs/providers) +2. Wenn das Problem besteht, versuche deine gespeicherte Konfiguration zu loeschen: ```bash rm -rf ~/.local/share/opencode ``` - On Windows, press `WIN+R` and delete: `%USERPROFILE%\.local\share\opencode` + Unter Windows druecke `WIN+R` und loesche: `%USERPROFILE%\.local\share\opencode` -3. Re-authenticate with your provider using the `/connect` command in the TUI. +3. Authentifiziere dich erneut beim Provider mit dem `/connect`-Befehl in der TUI. --- ### AI_APICallError und Provider-Paket-Probleme -If you encounter API call errors, this may be due to outdated provider packages. opencode dynamically installs provider packages (OpenAI, Anthropic, Google, etc.) as needed and caches them locally. +Wenn du API-Call-Fehler erhaeltst, kann das an veralteten Provider-Paketen liegen. opencode installiert Provider-Pakete (OpenAI, Anthropic, Google, etc.) dynamisch bei Bedarf und cached sie lokal. -To resolve provider package issues: +Um Provider-Paket-Probleme zu loesen: -1. Clear the provider package cache: +1. Leere den Provider-Paket-Cache: ```bash rm -rf ~/.cache/opencode ``` - On Windows, press `WIN+R` and delete: `%USERPROFILE%\.cache\opencode` + Unter Windows druecke `WIN+R` und loesche: `%USERPROFILE%\.cache\opencode` -2. Restart opencode to reinstall the latest provider packages +2. Starte opencode neu, um die neuesten Provider-Pakete zu installieren -This will force opencode to download the most recent versions of provider packages, which often resolves compatibility issues with model parameters and API changes. +Dies zwingt opencode, die neuesten Versionen der Provider-Pakete herunterzuladen, was oft Kompatibilitaetsprobleme mit Modellparametern und API-Aenderungen loest. --- ### Copy/Paste funktioniert nicht unter Linux -Linux users need to have one of the following clipboard utilities installed for copy/paste functionality to work: +Linux-Nutzer muessen eines der folgenden Clipboard-Utilities installiert haben, damit Copy/Paste funktioniert: -**For X11 systems:** +**Fuer X11-Systeme:** ```bash apt install -y xclip @@ -283,13 +282,13 @@ apt install -y xclip apt install -y xsel ``` -**For Wayland systems:** +**Fuer Wayland-Systeme:** ```bash apt install -y wl-clipboard ``` -**For headless environments:** +**Fuer Headless-Umgebungen:** ```bash apt install -y xvfb @@ -298,4 +297,4 @@ Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 & export DISPLAY=:99.0 ``` -opencode will detect if you're using Wayland and prefer `wl-clipboard`, otherwise it will try to find clipboard tools in order of: `xclip` and `xsel`. +opencode erkennt, ob du Wayland nutzt und bevorzugt `wl-clipboard`, sonst versucht es `xclip` und `xsel` (in dieser Reihenfolge). diff --git a/packages/web/src/content/docs/de/tui.mdx b/packages/web/src/content/docs/de/tui.mdx index ebd16fa76a..144662c119 100644 --- a/packages/web/src/content/docs/de/tui.mdx +++ b/packages/web/src/content/docs/de/tui.mdx @@ -74,7 +74,7 @@ Hier sind alle verfuegbaren Slash-Commands: ### connect -Add a provider to OpenCode. Allows you to select from available providers and add their API keys. +Fuegt einen Provider zu OpenCode hinzu. Erlaubt die Auswahl aus verfuegbaren Providern und das Hinzufuegen ihrer API-Keys. ```bash frame="none" /connect @@ -84,7 +84,7 @@ Add a provider to OpenCode. Allows you to select from available providers and ad ### compact -Compact the current session. _Alias_: `/summarize` +Kompaktiert die aktuelle Session. _Alias_: `/summarize` ```bash frame="none" /compact @@ -96,7 +96,7 @@ Compact the current session. _Alias_: `/summarize` ### details -Toggle tool execution details. +Schaltet Tool-Ausfuehrungsdetails um. ```bash frame="none" /details @@ -108,7 +108,7 @@ Toggle tool execution details. ### editor -Open external editor for composing messages. Uses the editor set in your `EDITOR` environment variable. [Learn more](#editor-setup). +Oeffnet externen Editor zum Verfassen von Nachrichten. Nutzt den in der `EDITOR`-Umgebungsvariable gesetzten Editor. [Mehr dazu](#editor-setup). ```bash frame="none" /editor @@ -120,7 +120,7 @@ Open external editor for composing messages. Uses the editor set in your `EDITOR ### exit -Exit OpenCode. _Aliases_: `/quit`, `/q` +Beendet OpenCode. _Aliase_: `/quit`, `/q` ```bash frame="none" /exit @@ -132,7 +132,7 @@ Exit OpenCode. _Aliases_: `/quit`, `/q` ### export -Export current conversation to Markdown and open in your default editor. Uses the editor set in your `EDITOR` environment variable. [Learn more](#editor-setup). +Exportiert die aktuelle Unterhaltung als Markdown und oeffnet sie in deinem Standard-Editor. Nutzt den in der `EDITOR`-Umgebungsvariable gesetzten Editor. [Mehr dazu](#editor-setup). ```bash frame="none" /export @@ -144,7 +144,7 @@ Export current conversation to Markdown and open in your default editor. Uses th ### help -Show the help dialog. +Zeigt den Hilfedialog. ```bash frame="none" /help @@ -156,7 +156,7 @@ Show the help dialog. ### init -Create or update `AGENTS.md` file. [Learn more](/docs/rules). +Erstellt oder aktualisiert die `AGENTS.md`-Datei. [Mehr dazu](/docs/rules). ```bash frame="none" /init @@ -168,7 +168,7 @@ Create or update `AGENTS.md` file. [Learn more](/docs/rules). ### models -List available models. +Listet verfuegbare Modelle. ```bash frame="none" /models @@ -180,7 +180,7 @@ List available models. ### new -Start a new session. _Alias_: `/clear` +Startet eine neue Session. _Alias_: `/clear` ```bash frame="none" /new @@ -192,14 +192,13 @@ Start a new session. _Alias_: `/clear` ### redo -Redo a previously undone message. Only available after using `/undo`. +Wiederholt eine zuvor rueckgaengig gemachte Nachricht. Nur verfuegbar nach Verwendung von `/undo`. :::tip -Any file changes will also be restored. +Auch Dateiaenderungen werden wiederhergestellt. ::: -Internally, this uses Git to manage the file changes. So your project **needs to -be a Git repository**. +Intern nutzt dies Git, um die Dateiaenderungen zu verwalten. Dein Projekt muss also **ein Git-Repository sein**. ```bash frame="none" /redo @@ -211,7 +210,7 @@ be a Git repository**. ### sessions -List and switch between sessions. _Aliases_: `/resume`, `/continue` +Listet Sessions und wechselt zwischen ihnen. _Aliase_: `/resume`, `/continue` ```bash frame="none" /sessions @@ -223,7 +222,7 @@ List and switch between sessions. _Aliases_: `/resume`, `/continue` ### share -Share current session. [Learn more](/docs/share). +Teilt die aktuelle Session. [Mehr dazu](/docs/share). ```bash frame="none" /share @@ -235,7 +234,7 @@ Share current session. [Learn more](/docs/share). ### themes -List available themes. +Listet verfuegbare Themes. ```bash frame="none" /theme @@ -247,10 +246,10 @@ List available themes. ### thinking -Toggle the visibility of thinking/reasoning blocks in the conversation. When enabled, you can see the model's reasoning process for models that support extended thinking. +Schaltet die Sichtbarkeit von Thinking/Reasoning-Bloecken in der Unterhaltung um. Wenn aktiviert, kannst du den Denkprozess des Modells sehen (bei Modellen, die das unterstuetzen). :::note -This command only controls whether thinking blocks are **displayed** - it does not enable or disable the model's reasoning capabilities. To toggle actual reasoning capabilities, use `ctrl+t` to cycle through model variants. +Dieser Befehl steuert nur, ob Thinking-Bloecke **angezeigt** werden - er aktiviert oder deaktiviert nicht die Reasoning-Faehigkeiten des Modells. Um die Reasoning-Faehigkeiten umzuschalten, nutze `ctrl+t`, um durch die Modell-Varianten zu wechseln. ::: ```bash frame="none" @@ -261,14 +260,13 @@ This command only controls whether thinking blocks are **displayed** - it does n ### undo -Undo last message in the conversation. Removes the most recent user message, all subsequent responses, and any file changes. +Macht die letzte Nachricht in der Unterhaltung rueckgaengig. Entfernt die letzte Benutzernachricht, alle folgenden Antworten und alle Dateiaenderungen. :::tip -Any file changes made will also be reverted. +Auch durchgefuehrte Dateiaenderungen werden rueckgaengig gemacht. ::: -Internally, this uses Git to manage the file changes. So your project **needs to -be a Git repository**. +Intern nutzt dies Git, um die Dateiaenderungen zu verwalten. Dein Projekt muss also **ein Git-Repository sein**. ```bash frame="none" /undo @@ -280,7 +278,7 @@ be a Git repository**. ### unshare -Unshare current session. [Learn more](/docs/share#un-sharing). +Hebt das Teilen der aktuellen Session auf. [Mehr dazu](/docs/share#un-sharing). ```bash frame="none" /unshare @@ -290,7 +288,7 @@ Unshare current session. [Learn more](/docs/share#un-sharing). ## Editor-Einrichtung -Both the `/editor` and `/export` commands use the editor specified in your `EDITOR` environment variable. +Sowohl `/editor` als auch `/export` nutzen den in deiner `EDITOR`-Umgebungsvariable spezifizierten Editor. <Tabs> <TabItem label="Linux/macOS"> @@ -304,7 +302,7 @@ Both the `/editor` and `/export` commands use the editor specified in your `EDIT export EDITOR="code --wait" ``` - To make it permanent, add this to your shell profile; + Um es dauerhaft zu machen, fuege dies zu deinem Shell-Profil hinzu; `~/.bashrc`, `~/.zshrc`, etc. </TabItem> @@ -318,8 +316,7 @@ Both the `/editor` and `/export` commands use the editor specified in your `EDIT set EDITOR=code --wait ``` - To make it permanent, use **System Properties** > **Environment - Variables**. + Um es dauerhaft zu machen, nutze **Systemeigenschaften** > **Umgebungsvariablen**. </TabItem> @@ -332,62 +329,72 @@ Both the `/editor` and `/export` commands use the editor specified in your `EDIT $env:EDITOR = "code --wait" ``` - To make it permanent, add this to your PowerShell profile. + Um es dauerhaft zu machen, fuege dies zu deinem PowerShell-Profil hinzu. </TabItem> </Tabs> -Popular editor options include: +Beliebte Editoren sind: - `code` - Visual Studio Code - `cursor` - Cursor - `windsurf` - Windsurf -- `nvim` - Neovim editor -- `vim` - Vim editor -- `nano` - Nano editor +- `nvim` - Neovim +- `vim` - Vim +- `nano` - Nano - `notepad` - Windows Notepad - `subl` - Sublime Text :::note -Some editors like VS Code need to be started with the `--wait` flag. +Einige Editoren wie VS Code muessen mit dem `--wait`-Flag gestartet werden. ::: -Some editors need command-line arguments to run in blocking mode. The `--wait` flag makes the editor process block until closed. +Einige Editoren benoetigen Befehlszeilenargumente, um im blockierenden Modus zu laufen. Das `--wait`-Flag sorgt dafuer, dass der Editor-Prozess blockiert, bis er geschlossen wird. --- ## Konfiguration -You can customize TUI behavior through your OpenCode config file. +Du kannst das Verhalten der TUI ueber die Datei `tui.json` (oder `tui.jsonc`) anpassen. -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", - "tui": { - "scroll_speed": 3, - "scroll_acceleration": { - "enabled": true - } - } + "$schema": "https://opencode.ai/tui.json", + "theme": "opencode", + "keybinds": { + "leader": "ctrl+x" + }, + "scroll_speed": 3, + "scroll_acceleration": { + "enabled": true + }, + "diff_style": "auto" } ``` +Dies ist getrennt von `opencode.json`, welche das Server-/Runtime-Verhalten konfiguriert. + ### Optionen -- `scroll_acceleration` - Enable macOS-style scroll acceleration for smooth, natural scrolling. When enabled, scroll speed increases with rapid scrolling gestures and stays precise for slower movements. **This setting takes precedence over `scroll_speed` and overrides it when enabled.** -- `scroll_speed` - Controls how fast the TUI scrolls when using scroll commands (minimum: `1`). Defaults to `3`. **Note: This is ignored if `scroll_acceleration.enabled` is set to `true`.** +- `theme` - Setzt dein UI-Theme. [Mehr dazu](/docs/themes). +- `keybinds` - Passt Tastenkombinationen an. [Mehr dazu](/docs/keybinds). +- `scroll_acceleration.enabled` - Aktiviert Scroll-Beschleunigung im macOS-Stil fuer weiches, natuerliches Scrollen. Wenn aktiviert, erhoeht sich die Scroll-Geschwindigkeit bei schnellen Gesten und bleibt praezise bei langsamen Bewegungen. **Diese Einstellung hat Vorrang vor `scroll_speed` und ueberschreibt es, wenn aktiviert.** +- `scroll_speed` - Steuert, wie schnell die TUI scrollt (Minimum: `0.001`, unterstuetzt Dezimalwerte). Standard ist `3`. **Hinweis: Wird ignoriert, wenn `scroll_acceleration.enabled` auf `true` gesetzt ist.** +- `diff_style` - Steuert die Diff-Darstellung. `"auto"` passt sich der Terminalbreite an, `"stacked"` zeigt immer ein einspaltiges Layout. + +Verwende `OPENCODE_TUI_CONFIG`, um einen benutzerdefinierten TUI-Konfigurationspfad zu laden. --- ## Anpassung -You can customize various aspects of the TUI view using the command palette (`ctrl+x h` or `/help`). These settings persist across restarts. +Du kannst verschiedene Aspekte der TUI-Ansicht ueber die Befehlspalette (`ctrl+x h` oder `/help`) anpassen. Diese Einstellungen bleiben ueber Neustarts hinweg erhalten. --- #### Benutzername-Anzeige -Toggle whether your username appears in chat messages. Access this through: +Schaltet um, ob dein Benutzername in Chat-Nachrichten erscheint. Zugriff hierueber: -- Command palette: Search for "username" or "hide username" -- The setting persists automatically and will be remembered across TUI sessions +- Befehlspalette: Suche nach "username" oder "hide username" +- Die Einstellung wird automatisch gespeichert und bleibt ueber TUI-Sessions hinweg erhalten. diff --git a/packages/web/src/content/docs/de/zen.mdx b/packages/web/src/content/docs/de/zen.mdx index f52ed5f363..e5661ad569 100644 --- a/packages/web/src/content/docs/de/zen.mdx +++ b/packages/web/src/content/docs/de/zen.mdx @@ -57,6 +57,8 @@ Du kannst unsere Modelle auch ueber die folgenden API-Endpunkte aufrufen. | Model | Model ID | Endpoint | AI SDK Package | | ------------------ | ------------------ | -------------------------------------------------- | --------------------------- | +| GPT 5.4 | gpt-5.4 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| GPT 5.3 Codex | gpt-5.3-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.2 | gpt-5.2 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.2 Codex | gpt-5.2-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.1 | gpt-5.1 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | @@ -66,22 +68,24 @@ Du kannst unsere Modelle auch ueber die folgenden API-Endpunkte aufrufen. | GPT 5 | gpt-5 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5 Codex | gpt-5-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5 Nano | gpt-5-nano | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| Claude Opus 4.6 | claude-opus-4-6 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Opus 4.5 | claude-opus-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Opus 4.1 | claude-opus-4-1 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Sonnet 4.6 | claude-sonnet-4-6 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Sonnet 4.5 | claude-sonnet-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Sonnet 4 | claude-sonnet-4 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Haiku 4.5 | claude-haiku-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Haiku 3.5 | claude-3-5-haiku | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| Claude Opus 4.6 | claude-opus-4-6 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| Claude Opus 4.5 | claude-opus-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| Claude Opus 4.1 | claude-opus-4-1 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Gemini 3.1 Pro | gemini-3.1-pro | `https://opencode.ai/zen/v1/models/gemini-3.1-pro` | `@ai-sdk/google` | | Gemini 3 Pro | gemini-3-pro | `https://opencode.ai/zen/v1/models/gemini-3-pro` | `@ai-sdk/google` | | Gemini 3 Flash | gemini-3-flash | `https://opencode.ai/zen/v1/models/gemini-3-flash` | `@ai-sdk/google` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.5 Free | minimax-m2.5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.1 | minimax-m2.1 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.1 Free | minimax-m2.1-free | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| GLM 5 | glm-5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | GLM 4.7 | glm-4.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM 4.7 Free | glm-4.7-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | GLM 4.6 | glm-4.6 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 Free | kimi-k2.5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2 Thinking | kimi-k2-thinking | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2 | kimi-k2 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Qwen3 Coder 480B | qwen3-coder | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -110,29 +114,35 @@ Unten siehst du die Preise **pro 1 Mio. Tokens**. | Model | Input | Output | Cached Read | Cached Write | | --------------------------------- | ------ | ------ | ----------- | ------------ | | Big Pickle | Free | Free | Free | - | -| MiniMax M2.1 Free | Free | Free | Free | - | +| MiniMax M2.5 Free | Free | Free | Free | - | +| MiniMax M2.5 | $0.30 | $1.20 | $0.06 | $0.375 | | MiniMax M2.1 | $0.30 | $1.20 | $0.10 | - | -| GLM 4.7 Free | Free | Free | Free | - | +| GLM 5 | $1.00 | $3.20 | $0.20 | - | | GLM 4.7 | $0.60 | $2.20 | $0.10 | - | | GLM 4.6 | $0.60 | $2.20 | $0.10 | - | -| Kimi K2.5 Free | Free | Free | Free | - | -| Kimi K2.5 | $0.60 | $3.00 | $0.08 | - | +| Kimi K2.5 | $0.60 | $3.00 | $0.10 | - | | Kimi K2 Thinking | $0.40 | $2.50 | - | - | | Kimi K2 | $0.40 | $2.50 | - | - | | Qwen3 Coder 480B | $0.45 | $1.50 | - | - | +| Claude Opus 4.6 (≤ 200K tokens) | $5.00 | $25.00 | $0.50 | $6.25 | +| Claude Opus 4.6 (> 200K tokens) | $10.00 | $37.50 | $1.00 | $12.50 | +| Claude Opus 4.5 | $5.00 | $25.00 | $0.50 | $6.25 | +| Claude Opus 4.1 | $15.00 | $75.00 | $1.50 | $18.75 | +| Claude Sonnet 4.6 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 | +| Claude Sonnet 4.6 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 | | Claude Sonnet 4.5 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 | | Claude Sonnet 4.5 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 | | Claude Sonnet 4 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 | | Claude Sonnet 4 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 | | Claude Haiku 4.5 | $1.00 | $5.00 | $0.10 | $1.25 | | Claude Haiku 3.5 | $0.80 | $4.00 | $0.08 | $1.00 | -| Claude Opus 4.6 (≤ 200K tokens) | $5.00 | $25.00 | $0.50 | $6.25 | -| Claude Opus 4.6 (> 200K tokens) | $10.00 | $37.50 | $1.00 | $12.50 | -| Claude Opus 4.5 | $5.00 | $25.00 | $0.50 | $6.25 | -| Claude Opus 4.1 | $15.00 | $75.00 | $1.50 | $18.75 | +| Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | +| Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | | Gemini 3 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | +| GPT 5.4 | $2.50 | $15.00 | $0.25 | - | +| GPT 5.3 Codex | $1.75 | $14.00 | $0.175 | - | | GPT 5.2 | $1.75 | $14.00 | $0.175 | - | | GPT 5.2 Codex | $1.75 | $14.00 | $0.175 | - | | GPT 5.1 | $1.07 | $8.50 | $0.107 | - | @@ -152,10 +162,8 @@ Kreditkartengebuehren geben wir zum Selbstkostenpreis weiter (4,4 % + $0.30 pro Die kostenlosen Modelle: -- GLM 4.7 Free ist fuer begrenzte Zeit verfuegbar, um Feedback zu sammeln und das Modell zu verbessern. -- Kimi K2.5 Free ist fuer begrenzte Zeit verfuegbar, um Feedback zu sammeln und das Modell zu verbessern. -- MiniMax M2.1 Free ist fuer begrenzte Zeit verfuegbar, um Feedback zu sammeln und das Modell zu verbessern. -- Big Pickle ist ein Stealth-Modell und ebenfalls zeitlich begrenzt kostenlos verfuegbar. +- MiniMax M2.5 Free ist fuer begrenzte Zeit auf OpenCode verfuegbar. Das Team nutzt diese Zeit, um Feedback zu sammeln und das Modell zu verbessern. +- Big Pickle ist ein Stealth-Modell, das fuer begrenzte Zeit kostenlos auf OpenCode verfuegbar ist. Das Team nutzt diese Zeit, um Feedback zu sammeln und das Modell zu verbessern. Wenn du Fragen hast, <a href={email}>kontaktiere uns</a>. @@ -178,17 +186,28 @@ Mit aktiviertem Auto-Reload kann die Abrechnung dennoch darueber liegen, falls d --- +### Veraltete Modelle + +| Model | Datum der Abschaltung | +| ---------------- | --------------------- | +| Qwen3 Coder 480B | 6. Feb. 2026 | +| Kimi K2 Thinking | 6. Maerz 2026 | +| Kimi K2 | 6. Maerz 2026 | +| MiniMax M2.1 | 15. Maerz 2026 | +| GLM 4.7 | 15. Maerz 2026 | +| GLM 4.6 | 15. Maerz 2026 | + +--- + ## Datenschutz Alle Modelle werden in den USA gehostet. Unsere Provider arbeiten grundsaetzlich mit Zero-Retention und nutzen deine Daten nicht zum Training, mit folgenden Ausnahmen: -- Big Pickle: During its free period, collected data may be used to improve the model. -- GLM 4.7 Free: During its free period, collected data may be used to improve the model. -- Kimi K2.5 Free: During its free period, collected data may be used to improve the model. -- MiniMax M2.1 Free: During its free period, collected data may be used to improve the model. -- OpenAI APIs: Requests are retained for 30 days in accordance with [OpenAI's Data Policies](https://platform.openai.com/docs/guides/your-data). -- Anthropic APIs: Requests are retained for 30 days in accordance with [Anthropic's Data Policies](https://docs.anthropic.com/en/docs/claude-code/data-usage). +- Big Pickle: Waehrend der kostenlosen Phase koennen gesammelte Daten zur Verbesserung des Modells genutzt werden. +- MiniMax M2.5 Free: Waehrend der kostenlosen Phase koennen gesammelte Daten zur Verbesserung des Modells genutzt werden. +- OpenAI APIs: Anfragen werden fuer 30 Tage gemaess [OpenAI's Data Policies](https://platform.openai.com/docs/guides/your-data) aufbewahrt. +- Anthropic APIs: Anfragen werden fuer 30 Tage gemaess [Anthropic's Data Policies](https://docs.anthropic.com/en/docs/claude-code/data-usage) aufbewahrt. --- @@ -232,8 +251,7 @@ Du kannst eigene OpenAI- oder Anthropic-API-Keys verwenden und trotzdem andere Z Bei eigenen Keys erfolgt die Token-Abrechnung direkt ueber den Provider, nicht ueber Zen. -For example, your organization might already have a key for OpenAI or Anthropic -and you want to use that instead of the one that Zen provides. +Zum Beispiel hat deine Organisation vielleicht bereits einen Key fuer OpenAI oder Anthropic und du moechtest diesen anstelle des von Zen bereitgestellten nutzen. --- diff --git a/packages/web/src/content/docs/ecosystem.mdx b/packages/web/src/content/docs/ecosystem.mdx index 85839a2d82..d5a1e853df 100644 --- a/packages/web/src/content/docs/ecosystem.mdx +++ b/packages/web/src/content/docs/ecosystem.mdx @@ -15,38 +15,40 @@ You can also check out [awesome-opencode](https://github.com/awesome-opencode/aw ## Plugins -| Name | Description | -| --------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | -| [opencode-daytona](https://github.com/jamesmurdza/daytona/blob/main/guides/typescript/opencode/README.md) | Automatically run OpenCode sessions in isolated Daytona sandboxes with git sync and live previews | -| [opencode-helicone-session](https://github.com/H2Shami/opencode-helicone-session) | Automatically inject Helicone session headers for request grouping | -| [opencode-type-inject](https://github.com/nick-vi/opencode-type-inject) | Auto-inject TypeScript/Svelte types into file reads with lookup tools | -| [opencode-openai-codex-auth](https://github.com/numman-ali/opencode-openai-codex-auth) | Use your ChatGPT Plus/Pro subscription instead of API credits | -| [opencode-gemini-auth](https://github.com/jenslys/opencode-gemini-auth) | Use your existing Gemini plan instead of API billing | -| [opencode-antigravity-auth](https://github.com/NoeFabris/opencode-antigravity-auth) | Use Antigravity's free models instead of API billing | -| [opencode-devcontainers](https://github.com/athal7/opencode-devcontainers) | Multi-branch devcontainer isolation with shallow clones and auto-assigned ports | -| [opencode-google-antigravity-auth](https://github.com/shekohex/opencode-google-antigravity-auth) | Google Antigravity OAuth Plugin, with support for Google Search, and more robust API handling | -| [opencode-dynamic-context-pruning](https://github.com/Tarquinen/opencode-dynamic-context-pruning) | Optimize token usage by pruning obsolete tool outputs | -| [opencode-websearch-cited](https://github.com/ghoulr/opencode-websearch-cited.git) | Add native websearch support for supported providers with Google grounded style | -| [opencode-pty](https://github.com/shekohex/opencode-pty.git) | Enables AI agents to run background processes in a PTY, send interactive input to them. | -| [opencode-shell-strategy](https://github.com/JRedeker/opencode-shell-strategy) | Instructions for non-interactive shell commands - prevents hangs from TTY-dependent operations | -| [opencode-wakatime](https://github.com/angristan/opencode-wakatime) | Track OpenCode usage with Wakatime | -| [opencode-md-table-formatter](https://github.com/franlol/opencode-md-table-formatter/tree/main) | Clean up markdown tables produced by LLMs | -| [opencode-morph-fast-apply](https://github.com/JRedeker/opencode-morph-fast-apply) | 10x faster code editing with Morph Fast Apply API and lazy edit markers | -| [oh-my-opencode](https://github.com/code-yeongyu/oh-my-opencode) | Background agents, pre-built LSP/AST/MCP tools, curated agents, Claude Code compatible | -| [opencode-notificator](https://github.com/panta82/opencode-notificator) | Desktop notifications and sound alerts for OpenCode sessions | -| [opencode-notifier](https://github.com/mohak34/opencode-notifier) | Desktop notifications and sound alerts for permission, completion, and error events | -| [opencode-zellij-namer](https://github.com/24601/opencode-zellij-namer) | AI-powered automatic Zellij session naming based on OpenCode context | -| [opencode-skillful](https://github.com/zenobi-us/opencode-skillful) | Allow OpenCode agents to lazy load prompts on demand with skill discovery and injection | -| [opencode-supermemory](https://github.com/supermemoryai/opencode-supermemory) | Persistent memory across sessions using Supermemory | -| [@plannotator/opencode](https://github.com/backnotprop/plannotator/tree/main/apps/opencode-plugin) | Interactive plan review with visual annotation and private/offline sharing | -| [@openspoon/subtask2](https://github.com/spoons-and-mirrors/subtask2) | Extend opencode /commands into a powerful orchestration system with granular flow control | -| [opencode-scheduler](https://github.com/different-ai/opencode-scheduler) | Schedule recurring jobs using launchd (Mac) or systemd (Linux) with cron syntax | -| [micode](https://github.com/vtemian/micode) | Structured Brainstorm → Plan → Implement workflow with session continuity | -| [octto](https://github.com/vtemian/octto) | Interactive browser UI for AI brainstorming with multi-question forms | -| [opencode-background-agents](https://github.com/kdcokenny/opencode-background-agents) | Claude Code-style background agents with async delegation and context persistence | -| [opencode-notify](https://github.com/kdcokenny/opencode-notify) | Native OS notifications for OpenCode – know when tasks complete | -| [opencode-workspace](https://github.com/kdcokenny/opencode-workspace) | Bundled multi-agent orchestration harness – 16 components, one install | -| [opencode-worktree](https://github.com/kdcokenny/opencode-worktree) | Zero-friction git worktrees for OpenCode | +| Name | Description | +| -------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | +| [opencode-daytona](https://github.com/daytonaio/daytona/tree/main/libs/opencode-plugin) | Automatically run OpenCode sessions in isolated Daytona sandboxes with git sync and live previews | +| [opencode-helicone-session](https://github.com/H2Shami/opencode-helicone-session) | Automatically inject Helicone session headers for request grouping | +| [opencode-type-inject](https://github.com/nick-vi/opencode-type-inject) | Auto-inject TypeScript/Svelte types into file reads with lookup tools | +| [opencode-openai-codex-auth](https://github.com/numman-ali/opencode-openai-codex-auth) | Use your ChatGPT Plus/Pro subscription instead of API credits | +| [opencode-gemini-auth](https://github.com/jenslys/opencode-gemini-auth) | Use your existing Gemini plan instead of API billing | +| [opencode-antigravity-auth](https://github.com/NoeFabris/opencode-antigravity-auth) | Use Antigravity's free models instead of API billing | +| [opencode-devcontainers](https://github.com/athal7/opencode-devcontainers) | Multi-branch devcontainer isolation with shallow clones and auto-assigned ports | +| [opencode-google-antigravity-auth](https://github.com/shekohex/opencode-google-antigravity-auth) | Google Antigravity OAuth Plugin, with support for Google Search, and more robust API handling | +| [opencode-dynamic-context-pruning](https://github.com/Tarquinen/opencode-dynamic-context-pruning) | Optimize token usage by pruning obsolete tool outputs | +| [opencode-vibeguard](https://github.com/inkdust2021/opencode-vibeguard) | Redact secrets/PII into VibeGuard-style placeholders before LLM calls; restore locally | +| [opencode-websearch-cited](https://github.com/ghoulr/opencode-websearch-cited.git) | Add native websearch support for supported providers with Google grounded style | +| [opencode-pty](https://github.com/shekohex/opencode-pty.git) | Enables AI agents to run background processes in a PTY, send interactive input to them. | +| [opencode-shell-strategy](https://github.com/JRedeker/opencode-shell-strategy) | Instructions for non-interactive shell commands - prevents hangs from TTY-dependent operations | +| [opencode-wakatime](https://github.com/angristan/opencode-wakatime) | Track OpenCode usage with Wakatime | +| [opencode-md-table-formatter](https://github.com/franlol/opencode-md-table-formatter/tree/main) | Clean up markdown tables produced by LLMs | +| [opencode-morph-plugin](https://github.com/morphllm/opencode-morph-plugin) | Fast Apply editing, WarpGrep codebase search, and context compaction via Morph | +| [oh-my-opencode](https://github.com/code-yeongyu/oh-my-opencode) | Background agents, pre-built LSP/AST/MCP tools, curated agents, Claude Code compatible | +| [opencode-notificator](https://github.com/panta82/opencode-notificator) | Desktop notifications and sound alerts for OpenCode sessions | +| [opencode-notifier](https://github.com/mohak34/opencode-notifier) | Desktop notifications and sound alerts for permission, completion, and error events | +| [opencode-zellij-namer](https://github.com/24601/opencode-zellij-namer) | AI-powered automatic Zellij session naming based on OpenCode context | +| [opencode-skillful](https://github.com/zenobi-us/opencode-skillful) | Allow OpenCode agents to lazy load prompts on demand with skill discovery and injection | +| [opencode-supermemory](https://github.com/supermemoryai/opencode-supermemory) | Persistent memory across sessions using Supermemory | +| [@plannotator/opencode](https://github.com/backnotprop/plannotator/tree/main/apps/opencode-plugin) | Interactive plan review with visual annotation and private/offline sharing | +| [@openspoon/subtask2](https://github.com/spoons-and-mirrors/subtask2) | Extend opencode /commands into a powerful orchestration system with granular flow control | +| [opencode-scheduler](https://github.com/different-ai/opencode-scheduler) | Schedule recurring jobs using launchd (Mac) or systemd (Linux) with cron syntax | +| [micode](https://github.com/vtemian/micode) | Structured Brainstorm → Plan → Implement workflow with session continuity | +| [octto](https://github.com/vtemian/octto) | Interactive browser UI for AI brainstorming with multi-question forms | +| [opencode-background-agents](https://github.com/kdcokenny/opencode-background-agents) | Claude Code-style background agents with async delegation and context persistence | +| [opencode-notify](https://github.com/kdcokenny/opencode-notify) | Native OS notifications for OpenCode – know when tasks complete | +| [opencode-workspace](https://github.com/kdcokenny/opencode-workspace) | Bundled multi-agent orchestration harness – 16 components, one install | +| [opencode-worktree](https://github.com/kdcokenny/opencode-worktree) | Zero-friction git worktrees for OpenCode | +| [opencode-sentry-monitor](https://github.com/stolinski/opencode-sentry-monitor) | Trace and debug your AI agents with Sentry AI Monitoring | --- diff --git a/packages/web/src/content/docs/es/custom-tools.mdx b/packages/web/src/content/docs/es/custom-tools.mdx index 76188e184e..133abf4ab2 100644 --- a/packages/web/src/content/docs/es/custom-tools.mdx +++ b/packages/web/src/content/docs/es/custom-tools.mdx @@ -79,6 +79,32 @@ Esto crea dos herramientas: `math_add` y `math_multiply`. --- +#### Colisiones de nombres con herramientas integradas + +Las herramientas personalizadas están codificadas por el nombre de la herramienta. Si una herramienta personalizada utiliza el mismo nombre que una herramienta integrada, la herramienta personalizada tiene prioridad. + +Por ejemplo, este archivo reemplaza la herramienta `bash` integrada: + +```ts title=".opencode/tools/bash.ts" +import { tool } from "@opencode-ai/plugin" + +export default tool({ + description: "Restricted bash wrapper", + args: { + command: tool.schema.string(), + }, + async execute(args) { + return `blocked: ${args.command}` + }, +}) +``` + +:::note +Prefiera nombres únicos a menos que intencionalmente desee reemplazar una herramienta integrada. Si desea deshabilitar una herramienta integrada pero no anularla, use [permisos](/docs/permissions). +::: + +--- + ### Argumentos Puedes usar `tool.schema`, que es simplemente [Zod](https://zod.dev), para definir tipos de argumentos. diff --git a/packages/web/src/content/docs/es/ecosystem.mdx b/packages/web/src/content/docs/es/ecosystem.mdx index b1f4bdc9a4..8bb32e7065 100644 --- a/packages/web/src/content/docs/es/ecosystem.mdx +++ b/packages/web/src/content/docs/es/ecosystem.mdx @@ -15,38 +15,40 @@ También puedes consultar [awesome-opencode](https://github.com/awesome-opencode ## Complementos -| Nombre | Descripción | -| --------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | -| [opencode-daytona](https://github.com/jamesmurdza/daytona/blob/main/guides/typescript/opencode/README.md) | Ejecute automáticamente sesiones OpenCode en entornos sandbox aislados de Daytona con git sync y vistas previas en vivo | -| [opencode-helicone-session](https://github.com/H2Shami/opencode-helicone-session) | Inyecte automáticamente encabezados de sesión de Helicone para agrupación de solicitudes | -| [opencode-type-inject](https://github.com/nick-vi/opencode-type-inject) | Inyecte automáticamente tipos TypeScript/Svelte en lecturas de archivos con herramientas de búsqueda | -| [opencode-openai-codex-auth](https://github.com/numman-ali/opencode-openai-codex-auth) | Utilice su suscripción ChatGPT Plus/Pro en lugar de créditos API | -| [opencode-gemini-auth](https://github.com/jenslys/opencode-gemini-auth) | Utilice su plan Gemini existente en lugar de la facturación API | -| [opencode-antigravity-auth](https://github.com/NoeFabris/opencode-antigravity-auth) | Utilice los modelos gratuitos de Antigravity en lugar de la facturación API | -| [opencode-devcontainers](https://github.com/athal7/opencode-devcontainers) | Aislamiento de contenedores de desarrollo de múltiples ramas con clones superficiales y puertos asignados automáticamente | -| [opencode-google-antigravity-auth](https://github.com/shekohex/opencode-google-antigravity-auth) | Complemento Google Antigravity OAuth, compatible con la Búsqueda de Google y manejo más sólido de API | -| [opencode-dynamic-context-pruning](https://github.com/Tarquinen/opencode-dynamic-context-pruning) | Optimice el uso de tokens eliminando los resultados de herramientas obsoletas | -| [opencode-websearch-cited](https://github.com/ghoulr/opencode-websearch-cited.git) | Agregue soporte de búsqueda web nativa para proveedores compatibles con el estilo basado en Google | -| [opencode-pty](https://github.com/shekohex/opencode-pty.git) | Permite a los agentes de IA ejecutar procesos en segundo plano en un PTY y enviarles información interactiva. | -| [opencode-shell-strategy](https://github.com/JRedeker/opencode-shell-strategy) | Instrucciones para comandos de shell no interactivos: evita bloqueos de operaciones dependientes de TTY | -| [opencode-wakatime](https://github.com/angristan/opencode-wakatime) | Seguimiento del uso de OpenCode con Wakatime | -| [opencode-md-table-formatter](https://github.com/franlol/opencode-md-table-formatter/tree/main) | Limpiar tablas de Markdown producidas por LLMs | -| [opencode-morph-fast-apply](https://github.com/JRedeker/opencode-morph-fast-apply) | Edición de código 10 veces más rápida con Morph Fast Apply API y marcadores de edición diferidos | -| [oh-my-opencode](https://github.com/code-yeongyu/oh-my-opencode) | Agentes en segundo plano, herramientas LSP/AST/MCP prediseñadas, agentes seleccionados, compatible con Claude Code | -| [opencode-notificator](https://github.com/panta82/opencode-notificator) | Notificaciones de escritorio y alertas sonoras para sesiones OpenCode | -| [opencode-notifier](https://github.com/mohak34/opencode-notifier) | Notificaciones de escritorio y alertas sonoras para eventos de permiso, finalización y error | -| [opencode-zellij-namer](https://github.com/24601/opencode-zellij-namer) | Nomenclatura automática de sesiones Zellij impulsada por IA basada en el contexto OpenCode | -| [opencode-skillful](https://github.com/zenobi-us/opencode-skillful) | Permitir que los agentes OpenCode carguen mensajes de forma diferida a pedido con descubrimiento e inyección de habilidades | -| [opencode-supermemory](https://github.com/supermemoryai/opencode-supermemory) | Memoria persistente entre sesiones utilizando Supermemoria | -| [@plannotator/opencode](https://github.com/backnotprop/plannotator/tree/main/apps/opencode-plugin) | Revisión interactiva del plan con anotaciones visuales y uso compartido privado/sin conexión | -| [@openspoon/subtask2](https://github.com/spoons-and-mirrors/subtask2) | Amplíe opencode /commands a un potente sistema de orquestación con control de flujo granular | -| [opencode-scheduler](https://github.com/different-ai/opencode-scheduler) | Programe trabajos recurrentes usando launchd (Mac) o systemd (Linux) con sintaxis cron | -| [micode](https://github.com/vtemian/micode) | Lluvia de ideas estructurada → Planificar → Implementar flujo de trabajo con continuidad de sesión | -| [octto](https://github.com/vtemian/octto) | Interfaz de usuario interactiva del navegador para lluvia de ideas de IA con formularios de preguntas múltiples | -| [opencode-background-agents](https://github.com/kdcokenny/opencode-background-agents) | Agentes en segundo plano estilo Claude Code con delegación asíncrona y persistencia de contexto | -| [opencode-notify](https://github.com/kdcokenny/opencode-notify) | Notificaciones nativas del sistema operativo para OpenCode: sepa cuándo se completan las tareas | -| [opencode-workspace](https://github.com/kdcokenny/opencode-workspace) | Arnés de orquestación multiagente incluido: 16 componentes, una instalación | -| [opencode-worktree](https://github.com/kdcokenny/opencode-worktree) | Árboles de trabajo de Git de fricción cero para OpenCode | +| Nombre | Descripción | +| -------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | +| [opencode-daytona](https://github.com/daytonaio/daytona/tree/main/libs/opencode-plugin) | Ejecute automáticamente sesiones OpenCode en entornos sandbox aislados de Daytona con git sync y vistas previas en vivo | +| [opencode-helicone-session](https://github.com/H2Shami/opencode-helicone-session) | Inyecte automáticamente encabezados de sesión de Helicone para agrupación de solicitudes | +| [opencode-type-inject](https://github.com/nick-vi/opencode-type-inject) | Inyecte automáticamente tipos TypeScript/Svelte en lecturas de archivos con herramientas de búsqueda | +| [opencode-openai-codex-auth](https://github.com/numman-ali/opencode-openai-codex-auth) | Utilice su suscripción ChatGPT Plus/Pro en lugar de créditos API | +| [opencode-gemini-auth](https://github.com/jenslys/opencode-gemini-auth) | Utilice su plan Gemini existente en lugar de la facturación API | +| [opencode-antigravity-auth](https://github.com/NoeFabris/opencode-antigravity-auth) | Utilice los modelos gratuitos de Antigravity en lugar de la facturación API | +| [opencode-devcontainers](https://github.com/athal7/opencode-devcontainers) | Aislamiento de contenedores de desarrollo de múltiples ramas con clones superficiales y puertos asignados automáticamente | +| [opencode-google-antigravity-auth](https://github.com/shekohex/opencode-google-antigravity-auth) | Complemento Google Antigravity OAuth, compatible con la Búsqueda de Google y manejo más sólido de API | +| [opencode-dynamic-context-pruning](https://github.com/Tarquinen/opencode-dynamic-context-pruning) | Optimice el uso de tokens eliminando los resultados de herramientas obsoletas | +| [opencode-vibeguard](https://github.com/inkdust2021/opencode-vibeguard) | Redacta secretos/PII en marcadores de posición estilo VibeGuard antes de las llamadas a LLM; restaura localmente | +| [opencode-websearch-cited](https://github.com/ghoulr/opencode-websearch-cited.git) | Agregue soporte de búsqueda web nativa para proveedores compatibles con el estilo basado en Google | +| [opencode-pty](https://github.com/shekohex/opencode-pty.git) | Permite a los agentes de IA ejecutar procesos en segundo plano en un PTY y enviarles información interactiva. | +| [opencode-shell-strategy](https://github.com/JRedeker/opencode-shell-strategy) | Instrucciones para comandos de shell no interactivos: evita bloqueos de operaciones dependientes de TTY | +| [opencode-wakatime](https://github.com/angristan/opencode-wakatime) | Seguimiento del uso de OpenCode con Wakatime | +| [opencode-md-table-formatter](https://github.com/franlol/opencode-md-table-formatter/tree/main) | Limpiar tablas de Markdown producidas por LLMs | +| [opencode-morph-fast-apply](https://github.com/JRedeker/opencode-morph-fast-apply) | Edición de código 10 veces más rápida con Morph Fast Apply API y marcadores de edición diferidos | +| [oh-my-opencode](https://github.com/code-yeongyu/oh-my-opencode) | Agentes en segundo plano, herramientas LSP/AST/MCP prediseñadas, agentes seleccionados, compatible con Claude Code | +| [opencode-notificator](https://github.com/panta82/opencode-notificator) | Notificaciones de escritorio y alertas sonoras para sesiones OpenCode | +| [opencode-notifier](https://github.com/mohak34/opencode-notifier) | Notificaciones de escritorio y alertas sonoras para eventos de permiso, finalización y error | +| [opencode-zellij-namer](https://github.com/24601/opencode-zellij-namer) | Nomenclatura automática de sesiones Zellij impulsada por IA basada en el contexto OpenCode | +| [opencode-skillful](https://github.com/zenobi-us/opencode-skillful) | Permitir que los agentes OpenCode carguen mensajes de forma diferida a pedido con descubrimiento e inyección de habilidades | +| [opencode-supermemory](https://github.com/supermemoryai/opencode-supermemory) | Memoria persistente entre sesiones utilizando Supermemory | +| [@plannotator/opencode](https://github.com/backnotprop/plannotator/tree/main/apps/opencode-plugin) | Revisión interactiva del plan con anotaciones visuales y uso compartido privado/sin conexión | +| [@openspoon/subtask2](https://github.com/spoons-and-mirrors/subtask2) | Amplíe opencode /commands a un potente sistema de orquestación con control de flujo granular | +| [opencode-scheduler](https://github.com/different-ai/opencode-scheduler) | Programe trabajos recurrentes usando launchd (Mac) o systemd (Linux) con sintaxis cron | +| [micode](https://github.com/vtemian/micode) | Lluvia de ideas estructurada → Planificar → Implementar flujo de trabajo con continuidad de sesión | +| [octto](https://github.com/vtemian/octto) | Interfaz de usuario interactiva del navegador para lluvia de ideas de IA con formularios de preguntas múltiples | +| [opencode-background-agents](https://github.com/kdcokenny/opencode-background-agents) | Agentes en segundo plano estilo Claude Code con delegación asíncrona y persistencia de contexto | +| [opencode-notify](https://github.com/kdcokenny/opencode-notify) | Notificaciones nativas del sistema operativo para OpenCode: sepa cuándo se completan las tareas | +| [opencode-workspace](https://github.com/kdcokenny/opencode-workspace) | Arnés de orquestación multiagente incluido: 16 componentes, una instalación | +| [opencode-worktree](https://github.com/kdcokenny/opencode-worktree) | Árboles de trabajo de Git de fricción cero para OpenCode | +| [opencode-sentry-monitor](https://github.com/stolinski/opencode-sentry-monitor) | Rastree y depure sus agentes de IA con Sentry AI Monitoring | --- diff --git a/packages/web/src/content/docs/es/go.mdx b/packages/web/src/content/docs/es/go.mdx new file mode 100644 index 0000000000..49e6d585fd --- /dev/null +++ b/packages/web/src/content/docs/es/go.mdx @@ -0,0 +1,145 @@ +--- +title: Go +description: Suscripción de bajo coste para modelos de código abiertos. +--- + +import config from "../../../../config.mjs" +export const console = config.console +export const email = `mailto:${config.email}` + +OpenCode Go es una suscripción de bajo coste de **10 $/mes** que te ofrece acceso fiable a modelos populares de código abierto. + +:::note +OpenCode Go está actualmente en beta. +::: + +Go funciona como cualquier otro proveedor en OpenCode. Te suscribes a OpenCode Go y obtienes tu clave API. Es **completamente opcional** y no necesitas usarlo para utilizar OpenCode. + +Está diseñado principalmente para usuarios internacionales, con modelos alojados en EE. UU., la UE y Singapur para un acceso global estable. + +--- + +## Contexto + +Los modelos abiertos han mejorado mucho. Ahora alcanzan un rendimiento cercano al de los modelos propietarios para tareas de programación. Y como muchos proveedores pueden servirlos de forma competitiva, suelen ser mucho más baratos. + +Sin embargo, conseguir un acceso fiable y de baja latencia a ellos puede ser difícil. Los proveedores varían en calidad y disponibilidad. + +:::tip +Hemos probado un grupo selecto de modelos y proveedores que funcionan bien con OpenCode. +::: + +Para solucionar esto, hicimos un par de cosas: + +1. Probamos un grupo selecto de modelos abiertos y hablamos con sus equipos sobre la mejor manera de ejecutarlos. +2. Luego trabajamos con algunos proveedores para asegurarnos de que se sirvieran correctamente. +3. Finalmente, evaluamos la combinación de modelo/proveedor y elaboramos una lista que nos sentimos cómodos recomendando. + +OpenCode Go te da acceso a estos modelos por **10 $/mes**. + +--- + +## Cómo funciona + +OpenCode Go funciona como cualquier otro proveedor en OpenCode. + +1. Inicias sesión en **<a href={console}>OpenCode Zen</a>**, te suscribes a Go y copias tu clave API. +2. Ejecutas el comando `/connect` en la TUI, seleccionas `OpenCode Go` y pegas tu clave API. +3. Ejecuta `/models` en la TUI para ver la lista de modelos disponibles a través de Go. + +:::note +Solo un miembro por espacio de trabajo puede suscribirse a OpenCode Go. +::: + +La lista actual de modelos incluye: + +- **GLM-5** +- **Kimi K2.5** +- **MiniMax M2.5** + +La lista de modelos puede cambiar a medida que probamos y añadimos nuevos. + +--- + +## Límites de uso + +OpenCode Go incluye los siguientes límites: + +- **Límite de 5 horas** — 12 $ de uso +- **Límite semanal** — 30 $ de uso +- **Límite mensual** — 60 $ de uso + +Los límites se definen en valor monetario. Esto significa que tu recuento real de solicitudes depende del modelo que uses. Los modelos más baratos como MiniMax M2.5 permiten más solicitudes, mientras que los modelos de mayor coste como GLM-5 permiten menos. + +La siguiente tabla proporciona una estimación del recuento de solicitudes basada en patrones de uso típicos de Go: + +| | GLM-5 | Kimi K2.5 | MiniMax M2.5 | +| ----------------------- | ----- | --------- | ------------ | +| solicitudes por 5 horas | 1.150 | 1.850 | 30.000 | +| solicitudes por semana | 2.880 | 4.630 | 75.000 | +| solicitudes por mes | 5.750 | 9.250 | 150.000 | + +Las estimaciones se basan en patrones de solicitud promedio observados: + +- GLM-5 — 700 de entrada, 52.000 en caché, 150 tokens de salida por solicitud +- Kimi K2.5 — 870 de entrada, 55.000 en caché, 200 tokens de salida por solicitud +- MiniMax M2.5 — 300 de entrada, 55.000 en caché, 125 tokens de salida por solicitud + +Puedes realizar un seguimiento de tu uso actual en la **<a href={console}>consola</a>**. + +:::tip +Si alcanzas el límite de uso, puedes seguir usando los modelos gratuitos. +::: + +Los límites de uso pueden cambiar a medida que aprendamos del uso temprano y los comentarios. + +--- + +### Precios + +OpenCode Go es un plan de suscripción de **10 $/mes**. A continuación se muestran los precios **por 1M de tokens**. + +| Modelo | Entrada | Salida | Lectura en caché | +| ------------ | ------- | ------ | ---------------- | +| GLM-5 | 1,00 $ | 3,20 $ | 0,20 $ | +| Kimi K2.5 | 0,60 $ | 3,00 $ | 0,10 $ | +| MiniMax M2.5 | 0,30 $ | 1,20 $ | 0,03 $ | + +--- + +### Uso más allá de los límites + +Si también tienes créditos en tu saldo de Zen, puedes habilitar la opción **Usar saldo** en la consola. Cuando está habilitada, Go recurrirá a tu saldo de Zen después de que hayas alcanzado tus límites de uso en lugar de bloquear las solicitudes. + +--- + +## Endpoints + +También puedes acceder a los modelos de Go a través de los siguientes endpoints de API. + +| Modelo | ID del modelo | Endpoint | Paquete AI SDK | +| ------------ | ------------- | ------------------------------------------------ | --------------------------- | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | + +El [model id](/docs/config/#models) en tu configuración de OpenCode usa el formato `opencode-go/<model-id>`. Por ejemplo, para Kimi K2.5, usarías `opencode-go/kimi-k2.5` en tu configuración. + +--- + +## Privacidad + +El plan está diseñado principalmente para usuarios internacionales, con modelos alojados en EE. UU., la UE y Singapur para un acceso global estable. + +<a href={email}>Contáctanos</a> si tienes alguna pregunta. + +--- + +## Objetivos + +Creamos OpenCode Go para: + +1. Hacer que la programación con IA sea **accesible** a más personas con una suscripción de bajo coste. +2. Proporcionar acceso **fiable** a los mejores modelos de código abierto. +3. Seleccionar modelos que han sido **probados y evaluados** para su uso con agentes de programación. +4. **Sin ataduras**, permitiéndote usar cualquier otro proveedor con OpenCode también. diff --git a/packages/web/src/content/docs/es/keybinds.mdx b/packages/web/src/content/docs/es/keybinds.mdx index 7ce014f0a2..4c1f7e1a80 100644 --- a/packages/web/src/content/docs/es/keybinds.mdx +++ b/packages/web/src/content/docs/es/keybinds.mdx @@ -3,11 +3,11 @@ title: Combinaciones de teclas description: Personaliza tus combinaciones de teclas. --- -OpenCode tiene una lista de combinaciones de teclas que puede personalizar a través de la configuración OpenCode. +OpenCode tiene una lista de combinaciones de teclas que puede personalizar a través de `tui.json`. -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "keybinds": { "leader": "ctrl+x", "app_exit": "ctrl+c,ctrl+d,<leader>q", @@ -28,6 +28,7 @@ OpenCode tiene una lista de combinaciones de teclas que puede personalizar a tra "session_unshare": "none", "session_interrupt": "escape", "session_compact": "<leader>c", + "session_child_first": "<leader>down", "session_child_cycle": "<leader>right", "session_child_cycle_reverse": "<leader>left", "session_parent": "<leader>up", @@ -117,11 +118,11 @@ No es necesario utilizar una tecla líder para las combinaciones de teclas, pero ## Desactivar combinación de teclas -Puede deshabilitar una combinación de teclas agregando la clave a su configuración con un valor de "ninguno". +Puede deshabilitar una combinación de teclas agregando la clave a `tui.json` con un valor de "none". -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "keybinds": { "session_compact": "none" } diff --git a/packages/web/src/content/docs/es/lsp.mdx b/packages/web/src/content/docs/es/lsp.mdx index fc741ca898..27eab4cadf 100644 --- a/packages/web/src/content/docs/es/lsp.mdx +++ b/packages/web/src/content/docs/es/lsp.mdx @@ -27,6 +27,7 @@ OpenCode viene con varios servidores LSP integrados para idiomas populares: | gopls | .go | Comando `go` disponible | | hls | .hs, .lhs | Comando `haskell-language-server-wrapper` disponible | | jdtls | .java | `Java SDK (version 21+)` instalado | +| julials | .jl | `julia` y `LanguageServer.jl` instalados | | kotlin-ls | .kt, .kts | Autoinstalaciones para proyectos Kotlin | | lua-ls | .lua | Autoinstalaciones para proyectos Lua | | nixd | .nix | Comando `nixd` disponible | diff --git a/packages/web/src/content/docs/es/plugins.mdx b/packages/web/src/content/docs/es/plugins.mdx index 904821bdb8..dc44180725 100644 --- a/packages/web/src/content/docs/es/plugins.mdx +++ b/packages/web/src/content/docs/es/plugins.mdx @@ -308,6 +308,10 @@ El ayudante `tool` crea una herramienta personalizada a la que opencode puede ll Sus herramientas personalizadas estarán disponibles para opencode junto con las herramientas integradas. +:::note +Si una herramienta de complemento utiliza el mismo nombre que una herramienta integrada, la herramienta de complemento tiene prioridad. +::: + --- ### Registro diff --git a/packages/web/src/content/docs/es/providers.mdx b/packages/web/src/content/docs/es/providers.mdx index 8d86612538..2ee033f00d 100644 --- a/packages/web/src/content/docs/es/providers.mdx +++ b/packages/web/src/content/docs/es/providers.mdx @@ -84,6 +84,38 @@ Funciona como cualquier otro proveedor en OpenCode y su uso es completamente opc --- +## OpenCode Go + +OpenCode Go es un plan de suscripción de bajo costo que brinda acceso confiable a modelos de codificación abiertos populares proporcionados por el equipo de OpenCode que han sido +probado y verificado para funcionar bien con OpenCode. + +1. Ejecute el comando `/connect` en TUI, seleccione `OpenCode Go` y diríjase a [opencode.ai/auth](https://opencode.ai/zen). + + ```txt + /connect + ``` + +2. Inicie sesión, agregue sus datos de facturación y copie su clave API. + +3. Pegue su clave API. + + ```txt + ┌ API key + │ + │ + └ enter + ``` + +4. Ejecute `/models` en TUI para ver la lista de modelos que recomendamos. + + ```txt + /models + ``` + +Funciona como cualquier otro proveedor en OpenCode y su uso es completamente opcional. + +--- + ## Directorio Veamos algunos de los proveedores en detalle. Si desea agregar un proveedor a la @@ -792,8 +824,6 @@ Para utilizar su suscripción GitHub Copilot con opencode: :::note Algunos modelos pueden necesitar un [Pro+ suscripción](https://github.com/features/copilot/plans) para usar. - -Algunos modelos deben habilitarse manualmente en su [GitHub configuración del copiloto](https://docs.github.com/en/copilot/how-tos/use-ai-models/configure-access-to-ai-models#setup-for-individual-use). ::: 1. Ejecute el comando `/connect` y busque GitHub Copilot. @@ -1483,6 +1513,39 @@ SAP AI Core brinda acceso a más de 40 modelos de OpenAI, Anthropic, Google, Ama --- +### STACKIT + +STACKIT AI Model Serving proporciona un entorno de alojamiento soberano totalmente gestionado para modelos de IA, centrándose en LLM como Llama, Mistral y Qwen, con máxima soberanía de datos en infraestructura europea. + +1. Diríjase al [Portal STACKIT](https://portal.stackit.cloud), navegue hasta **AI Model Serving** y cree un token de autenticación para su proyecto. + + :::tip + Necesita una cuenta de cliente STACKIT, una cuenta de usuario y un proyecto antes de crear tokens de autenticación. + ::: + +2. Ejecute el comando `/connect` y busque **STACKIT**. + + ```txt + /connect + ``` + +3. Ingrese su token de autenticación de STACKIT AI Model Serving. + + ```txt + ┌ API key + │ + │ + └ enter + ``` + +4. Ejecute el comando `/models` para seleccionar entre los modelos disponibles como _Qwen3-VL 235B_ o _Llama 3.3 70B_. + + ```txt + /models + ``` + +--- + ### OVHcloud AI Endpoints 1. Dirígete al [panel de OVHcloud](https://ovh.com/manager). Navegue a la sección `Public Cloud`, `AI & Machine Learning` > `AI Endpoints` y en la pestaña `API Keys`, haga clic en **Crear una nueva clave API**. diff --git a/packages/web/src/content/docs/es/sdk.mdx b/packages/web/src/content/docs/es/sdk.mdx index d1282b95e9..d75149cde8 100644 --- a/packages/web/src/content/docs/es/sdk.mdx +++ b/packages/web/src/content/docs/es/sdk.mdx @@ -117,6 +117,78 @@ try { --- +## Salida Estructurada + +Puede solicitar una salida JSON estructurada del modelo especificando un `format` con un esquema JSON. El modelo utilizará una herramienta `StructuredOutput` para devolver un JSON validado que coincida con su esquema. + +### Uso Básico + +```typescript +const result = await client.session.prompt({ + path: { id: sessionId }, + body: { + parts: [{ type: "text", text: "Research Anthropic and provide company info" }], + format: { + type: "json_schema", + schema: { + type: "object", + properties: { + company: { type: "string", description: "Company name" }, + founded: { type: "number", description: "Year founded" }, + products: { + type: "array", + items: { type: "string" }, + description: "Main products", + }, + }, + required: ["company", "founded"], + }, + }, + }, +}) + +// Access the structured output +console.log(result.data.info.structured_output) +// { company: "Anthropic", founded: 2021, products: ["Claude", "Claude API"] } +``` + +### Tipos de Formato de Salida + +| Tipo | Descripción | +| ------------- | --------------------------------------------------------------------- | +| `text` | Predeterminado. Respuesta de texto estándar (sin salida estructurada) | +| `json_schema` | Devuelve JSON validado que coincide con el esquema proporcionado | + +### Formato de Esquema JSON + +Cuando use `type: 'json_schema'`, proporcione: + +| Campo | Tipo | Descripción | +| ------------ | --------------- | ---------------------------------------------------------------- | +| `type` | `'json_schema'` | Requerido. Especifica el modo de esquema JSON | +| `schema` | `object` | Requerido. Objeto JSON Schema que define la estructura de salida | +| `retryCount` | `number` | Opcional. Número de reintentos de validación (predeterminado: 2) | + +### Manejo de Errores + +Si el modelo no logra producir una salida estructurada válida después de todos los reintentos, la respuesta incluirá un `StructuredOutputError`: + +```typescript +if (result.data.info.error?.name === "StructuredOutputError") { + console.error("Failed to produce structured output:", result.data.info.error.message) + console.error("Attempts:", result.data.info.error.retries) +} +``` + +### Mejores Prácticas + +1. **Proporcione descripciones claras** en las propiedades de su esquema para ayudar al modelo a entender qué datos extraer +2. **Use `required`** para especificar qué campos deben estar presentes +3. **Mantenga los esquemas enfocados** - los esquemas anidados complejos pueden ser más difíciles de completar correctamente para el modelo +4. **Establezca un `retryCount` apropiado** - aumente para esquemas complejos, disminuya para simples + +--- + ## API El SDK expone todas las API del servidor a través de un cliente con seguridad de tipos. @@ -226,27 +298,27 @@ const { providers, default: defaults } = await client.config.providers() ### Sesiones -| Método | Descripción | Notas | -| ---------------------------------------------------------- | --------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `session.list()` | Listar sesiones | Devuelve <a href={typesUrl}><code>Session[]</code></a> | -| `session.get({ path })` | Obtener sesión | Devuelve <a href={typesUrl}><code>Session</code></a> | -| `session.children({ path })` | Listar sesiones secundarias | Devuelve <a href={typesUrl}><code>Session[]</code></a> | -| `session.create({ body })` | Crear sesión | Devuelve <a href={typesUrl}><code>Session</code></a> | -| `session.delete({ path })` | Eliminar sesión | Devuelve `boolean` | -| `session.update({ path, body })` | Actualizar propiedades de sesión | Devuelve <a href={typesUrl}><code>Session</code></a> | -| `session.init({ path, body })` | Analizar aplicación y crear `AGENTS.md` | Devuelve `boolean` | -| `session.abort({ path })` | Cancelar una sesión en ejecución | Devuelve `boolean` | -| `session.share({ path })` | Compartir sesión | Devuelve <a href={typesUrl}><code>Session</code></a> | -| `session.unshare({ path })` | Dejar de compartir sesión | Devuelve <a href={typesUrl}><code>Session</code></a> | -| `session.summarize({ path, body })` | Resumir sesión | Devuelve `boolean` | -| `session.messages({ path })` | Listar mensajes en una sesión | Devuelve `{ info: `<a href={typesUrl}><code>Message</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}[]` | -| `session.message({ path })` | Obtener detalles del mensaje | Devuelve `{ info: `<a href={typesUrl}><code>Message</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}` | -| `session.prompt({ path, body })` | Enviar mensaje rápido | `body.noReply: true` devuelve UserMessage (solo contexto). El valor predeterminado devuelve <a href={typesUrl}><code>AssistantMessage</code></a> con respuesta de IA | -| `session.command({ path, body })` | Enviar comando a la sesión | Devuelve `{ info: `<a href={typesUrl}><code>AssistantMessage</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}` | -| `session.shell({ path, body })` | Ejecute un comando de shell | Devuelve <a href={typesUrl}><code>AssistantMessage</code></a> | -| `session.revert({ path, body })` | Revertir un mensaje | Devuelve <a href={typesUrl}><code>Session</code></a> | -| `session.unrevert({ path })` | Restaurar mensajes revertidos | Devuelve <a href={typesUrl}><code>Session</code></a> | -| `postSessionByIdPermissionsByPermissionId({ path, body })` | Responder a una solicitud de permiso | Devuelve `boolean` | +| Método | Descripción | Notas | +| ---------------------------------------------------------- | --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `session.list()` | Listar sesiones | Devuelve <a href={typesUrl}><code>Session[]</code></a> | +| `session.get({ path })` | Obtener sesión | Devuelve <a href={typesUrl}><code>Session</code></a> | +| `session.children({ path })` | Listar sesiones secundarias | Devuelve <a href={typesUrl}><code>Session[]</code></a> | +| `session.create({ body })` | Crear sesión | Devuelve <a href={typesUrl}><code>Session</code></a> | +| `session.delete({ path })` | Eliminar sesión | Devuelve `boolean` | +| `session.update({ path, body })` | Actualizar propiedades de sesión | Devuelve <a href={typesUrl}><code>Session</code></a> | +| `session.init({ path, body })` | Analizar aplicación y crear `AGENTS.md` | Devuelve `boolean` | +| `session.abort({ path })` | Cancelar una sesión en ejecución | Devuelve `boolean` | +| `session.share({ path })` | Compartir sesión | Devuelve <a href={typesUrl}><code>Session</code></a> | +| `session.unshare({ path })` | Dejar de compartir sesión | Devuelve <a href={typesUrl}><code>Session</code></a> | +| `session.summarize({ path, body })` | Resumir sesión | Devuelve `boolean` | +| `session.messages({ path })` | Listar mensajes en una sesión | Devuelve `{ info: `<a href={typesUrl}><code>Message</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}[]` | +| `session.message({ path })` | Obtener detalles del mensaje | Devuelve `{ info: `<a href={typesUrl}><code>Message</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}` | +| `session.prompt({ path, body })` | Enviar mensaje rápido | `body.noReply: true` devuelve UserMessage (solo contexto). El valor predeterminado devuelve <a href={typesUrl}><code>AssistantMessage</code></a> con respuesta de IA. Admite `body.outputFormat` para [salida estructurada](#salida-estructurada) | +| `session.command({ path, body })` | Enviar comando a la sesión | Devuelve `{ info: `<a href={typesUrl}><code>AssistantMessage</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}` | +| `session.shell({ path, body })` | Ejecute un comando de shell | Devuelve <a href={typesUrl}><code>AssistantMessage</code></a> | +| `session.revert({ path, body })` | Revertir un mensaje | Devuelve <a href={typesUrl}><code>Session</code></a> | +| `session.unrevert({ path })` | Restaurar mensajes revertidos | Devuelve <a href={typesUrl}><code>Session</code></a> | +| `postSessionByIdPermissionsByPermissionId({ path, body })` | Responder a una solicitud de permiso | Devuelve `boolean` | --- diff --git a/packages/web/src/content/docs/es/share.mdx b/packages/web/src/content/docs/es/share.mdx index e1c62a031c..3bb376f386 100644 --- a/packages/web/src/content/docs/es/share.mdx +++ b/packages/web/src/content/docs/es/share.mdx @@ -41,7 +41,7 @@ Para configurar explícitamente el modo manual en su [archivo de configuración] ```json title="opencode.json" { - "$schema": "https://opncd.ai/config.json", + "$schema": "https://opencode.ai/config.json", "share": "manual" } ``` @@ -54,7 +54,7 @@ Puede habilitar el uso compartido automático para todas las conversaciones nuev ```json title="opencode.json" { - "$schema": "https://opncd.ai/config.json", + "$schema": "https://opencode.ai/config.json", "share": "auto" } ``` @@ -69,7 +69,7 @@ Puede desactivar el uso compartido por completo configurando la opción `share` ```json title="opencode.json" { - "$schema": "https://opncd.ai/config.json", + "$schema": "https://opencode.ai/config.json", "share": "disabled" } ``` diff --git a/packages/web/src/content/docs/es/themes.mdx b/packages/web/src/content/docs/es/themes.mdx index d7c7426267..8c8028eb6e 100644 --- a/packages/web/src/content/docs/es/themes.mdx +++ b/packages/web/src/content/docs/es/themes.mdx @@ -61,11 +61,11 @@ El tema del sistema es para usuarios que: ## Usar un tema -Puede seleccionar un tema abriendo la selección de tema con el comando `/theme`. O puede especificarlo en su [config](/docs/config). +Puede seleccionar un tema abriendo la selección de tema con el comando `/theme`. O puede especificarlo en `tui.json`. -```json title="opencode.json" {3} +```json title="tui.json" {3} { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "theme": "tokyonight" } ``` diff --git a/packages/web/src/content/docs/es/tui.mdx b/packages/web/src/content/docs/es/tui.mdx index ba7430f502..02f14d55ad 100644 --- a/packages/web/src/content/docs/es/tui.mdx +++ b/packages/web/src/content/docs/es/tui.mdx @@ -355,24 +355,34 @@ Algunos editores necesitan argumentos de línea de comandos para ejecutarse en m ## Configurar -Puede personalizar el comportamiento de TUI a través de su archivo de configuración OpenCode. +Puede personalizar el comportamiento de TUI a través de `tui.json` (o `tui.jsonc`). -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", - "tui": { - "scroll_speed": 3, - "scroll_acceleration": { - "enabled": true - } - } + "$schema": "https://opencode.ai/tui.json", + "theme": "opencode", + "keybinds": { + "leader": "ctrl+x" + }, + "scroll_speed": 3, + "scroll_acceleration": { + "enabled": true + }, + "diff_style": "auto" } ``` +Esto es independiente de `opencode.json`, que configura el comportamiento del servidor/tiempo de ejecución. + ### Opciones -- `scroll_acceleration`: habilite la aceleración de desplazamiento estilo macOS para un desplazamiento suave y natural. Cuando está habilitado, la velocidad de desplazamiento aumenta con gestos de desplazamiento rápido y se mantiene precisa para movimientos más lentos. **Esta configuración tiene prioridad sobre `scroll_speed` y la anula cuando está habilitada.** -- `scroll_speed`: controla la rapidez con la que se desplaza el TUI cuando se utilizan comandos de desplazamiento (mínimo: `1`). El valor predeterminado es `3`. **Nota: Esto se ignora si `scroll_acceleration.enabled` está configurado en `true`.** +- `theme`: establece su tema de interfaz de usuario. [Más información](/docs/themes). +- `keybinds`: personaliza los atajos de teclado. [Más información](/docs/keybinds). +- `scroll_acceleration.enabled`: habilite la aceleración de desplazamiento estilo macOS para un desplazamiento suave y natural. Cuando está habilitado, la velocidad de desplazamiento aumenta con gestos de desplazamiento rápido y se mantiene precisa para movimientos más lentos. **Esta configuración tiene prioridad sobre `scroll_speed` y la anula cuando está habilitada.** +- `scroll_speed`: controla la rapidez con la que se desplaza el TUI cuando se utilizan comandos de desplazamiento (mínimo: `0.001`, admite valores decimales). El valor predeterminado es `3`. **Nota: Esto se ignora si `scroll_acceleration.enabled` está configurado en `true`.** +- `diff_style`: controla la representación de diferencias. `"auto"` se adapta al ancho del terminal, `"stacked"` siempre muestra un diseño de una sola columna. + +Utilice `OPENCODE_TUI_CONFIG` para cargar una ruta de configuración de TUI personalizada. --- diff --git a/packages/web/src/content/docs/es/zen.mdx b/packages/web/src/content/docs/es/zen.mdx index 10847b452e..9848eb100a 100644 --- a/packages/web/src/content/docs/es/zen.mdx +++ b/packages/web/src/content/docs/es/zen.mdx @@ -62,6 +62,8 @@ También puede acceder a nuestros modelos a través de los siguientes puntos fin | Modelo | Model ID | Endpoint | AI SDK package | | ------------------ | ------------------ | -------------------------------------------------- | --------------------------- | +| GPT 5.4 | gpt-5.4 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| GPT 5.3 Codex | gpt-5.3-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.2 | gpt-5.2 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.2 Codex | gpt-5.2-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.1 | gpt-5.1 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | @@ -71,22 +73,24 @@ También puede acceder a nuestros modelos a través de los siguientes puntos fin | GPT 5 | gpt-5 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5 Codex | gpt-5-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5 Nano | gpt-5-nano | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| Claude Opus 4.6 | claude-opus-4-6 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Opus 4.5 | claude-opus-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Opus 4.1 | claude-opus-4-1 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Sonnet 4.6 | claude-sonnet-4-6 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Sonnet 4.5 | claude-sonnet-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Sonnet 4 | claude-sonnet-4 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Haiku 4.5 | claude-haiku-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Haiku 3.5 | claude-3-5-haiku | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| Claude Opus 4.6 | claude-opus-4-6 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| Claude Opus 4.5 | claude-opus-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| Claude Opus 4.1 | claude-opus-4-1 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Gemini 3.1 Pro | gemini-3.1-pro | `https://opencode.ai/zen/v1/models/gemini-3.1-pro` | `@ai-sdk/google` | | Gemini 3 Pro | gemini-3-pro | `https://opencode.ai/zen/v1/models/gemini-3-pro` | `@ai-sdk/google` | | Gemini 3 Flash | gemini-3-flash | `https://opencode.ai/zen/v1/models/gemini-3-flash` | `@ai-sdk/google` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.5 Free | minimax-m2.5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.1 | minimax-m2.1 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.1 Free | minimax-m2.1-free | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| GLM 5 | glm-5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | GLM 4.7 | glm-4.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM 4.7 Free | glm-4.7-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | GLM 4.6 | glm-4.6 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 Free | kimi-k2.5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2 Thinking | kimi-k2-thinking | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2 | kimi-k2 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Qwen3 Coder 480B | qwen3-coder | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -115,29 +119,35 @@ Apoyamos un modelo de pago por uso. A continuación se muestran los precios **po | Modelo | Entrada | Salida | Lectura en caché | Escritura en caché | | ------------------------------------ | ------- | ------ | ---------------- | ------------------ | | Big Pickle | Gratis | Gratis | Gratis | - | -| MiniMax M2.1 Free | Gratis | Gratis | Gratis | - | +| MiniMax M2.5 Free | Gratis | Gratis | Gratis | - | +| MiniMax M2.5 | $0,30 | $1,20 | $0,06 | - | | MiniMax M2.1 | $0,30 | $1,20 | $0,10 | - | -| GLM 4.7 Free | Gratis | Gratis | Gratis | - | +| GLM 5 | $1,00 | $3,20 | $0,20 | - | | GLM 4.7 | $0,60 | $2.20 | $0,10 | - | | GLM 4.6 | $0,60 | $2.20 | $0,10 | - | -| Kimi K2.5 Free | Gratis | Gratis | Gratis | - | | Kimi K2.5 | $0,60 | $3.00 | $0,08 | - | | Kimi K2 Thinking | $0,40 | $2.50 | - | - | | Kimi K2 | $0,40 | $2.50 | - | - | | Qwen3 Coder 480B | $0,45 | $1,50 | - | - | +| Claude Opus 4.6 (≤ 200.000 tokens) | $5.00 | $25.00 | $0,50 | $6.25 | +| Claude Opus 4.6 (> 200K tokens) | $10.00 | $37,50 | $1.00 | $12,50 | +| Claude Opus 4.5 | $5.00 | $25.00 | $0,50 | $6.25 | +| Claude Opus 4.1 | $15.00 | $75.00 | $1,50 | $18,75 | +| Claude Sonnet 4.6 (≤ 200.000 tokens) | $3.00 | $15.00 | $0,30 | $3,75 | +| Claude Sonnet 4.6 (> 200.000 tokens) | $6.00 | $22,50 | $0,60 | $7.50 | | Claude Sonnet 4.5 (≤ 200.000 tokens) | $3.00 | $15.00 | $0,30 | $3,75 | | Claude Sonnet 4.5 (> 200.000 tokens) | $6.00 | $22,50 | $0,60 | $7.50 | | Claude Sonnet 4 (≤ 200K tokens) | $3.00 | $15.00 | $0,30 | $3,75 | | Claude Sonnet 4 (> 200K tokens) | $6.00 | $22,50 | $0,60 | $7.50 | | Claude Haiku 4.5 | $1.00 | $5.00 | $0,10 | $1,25 | | Claude Haiku 3.5 | $0,80 | $4.00 | $0,08 | $1.00 | -| Claude Opus 4.6 (≤ 200.000 tokens) | $5.00 | $25.00 | $0,50 | $6.25 | -| Claude Opus 4.6 (> 200K tokens) | $10.00 | $37,50 | $1.00 | $12,50 | -| Claude Opus 4.5 | $5.00 | $25.00 | $0,50 | $6.25 | -| Claude Opus 4.1 | $15.00 | $75.00 | $1,50 | $18,75 | +| Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0,20 | - | +| Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0,40 | - | | Gemini 3 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0,20 | - | | Gemini 3 Pro (> 200K tokens) | $4.00 | $18.00 | $0,40 | - | | Gemini 3 Flash | $0,50 | $3.00 | $0,05 | - | +| GPT 5.4 | $2,50 | $15,00 | $0,25 | - | +| GPT 5.3 Codex | $1,75 | $14.00 | $0,175 | - | | GPT 5.2 | $1,75 | $14.00 | $0,175 | - | | GPT 5.2 Codex | $1,75 | $14.00 | $0,175 | - | | GPT 5.1 | $1.07 | $8,50 | $0,107 | - | @@ -156,9 +166,7 @@ Las tarifas de las tarjetas de crédito se trasladan al costo (4,4% + 0,30 dóla Los modelos gratuitos: -- GLM 4.7 Free está disponible en OpenCode por tiempo limitado. El equipo está aprovechando este tiempo para recopilar comentarios y mejorar el modelo. -- Kimi K2.5 Free está disponible en OpenCode por tiempo limitado. El equipo está aprovechando este tiempo para recopilar comentarios y mejorar el modelo. -- MiniMax M2.1 Free está disponible en OpenCode por tiempo limitado. El equipo está aprovechando este tiempo para recopilar comentarios y mejorar el modelo. +- MiniMax M2.5 Free está disponible en OpenCode por tiempo limitado. El equipo está aprovechando este tiempo para recopilar comentarios y mejorar el modelo. - Big Pickle es un modelo sigiloso gratuito en OpenCode por tiempo limitado. El equipo está aprovechando este tiempo para recopilar comentarios y mejorar el modelo. <a href={email}>Contáctenos</a> si tiene alguna pregunta. @@ -184,14 +192,25 @@ cobrarle más de $20 si su saldo es inferior a $5. --- +### Modelos obsoletos + +| Modelo | Fecha de retiro | +| ---------------- | ------------------- | +| Qwen3 Coder 480B | 6 de feb. de 2026 | +| Kimi K2 Thinking | 6 de marzo de 2026 | +| Kimi K2 | 6 de marzo de 2026 | +| MiniMax M2.1 | 15 de marzo de 2026 | +| GLM 4.7 | 15 de marzo de 2026 | +| GLM 4.6 | 15 de marzo de 2026 | + +--- + ## Privacidad Todos nuestros modelos están alojados en los EE. UU. Nuestros proveedores siguen una política de retención cero y no utilizan sus datos para la capacitación de modelos, con las siguientes excepciones: - Big Pickle: Durante su periodo gratuito, los datos recopilados podrán utilizarse para mejorar el modelo. -- GLM 4.7 Gratis: Durante su periodo gratuito, los datos recopilados podrán utilizarse para mejorar el modelo. -- Kimi K2.5 Free: Durante su periodo gratuito, los datos recopilados podrán utilizarse para mejorar el modelo. -- MiniMax M2.1 Free: Durante su período gratuito, los datos recopilados podrán utilizarse para mejorar el modelo. +- MiniMax M2.5 Free: Durante su período gratuito, los datos recopilados podrán utilizarse para mejorar el modelo. - API de OpenAI: las solicitudes se conservan durante 30 días de acuerdo con las [Políticas de datos de OpenAI](https://platform.openai.com/docs/guides/your-data). - API de Anthropic: las solicitudes se conservan durante 30 días de acuerdo con las [Políticas de datos de Anthropic](https://docs.anthropic.com/en/docs/claude-code/data-usage). diff --git a/packages/web/src/content/docs/fr/cli.mdx b/packages/web/src/content/docs/fr/cli.mdx index 8773d941f3..92a473d34b 100644 --- a/packages/web/src/content/docs/fr/cli.mdx +++ b/packages/web/src/content/docs/fr/cli.mdx @@ -558,6 +558,7 @@ OpenCode peut être configuré à l'aide de variables d'environnement. | `OPENCODE_AUTO_SHARE` | booléen | Partager automatiquement des sessions | | `OPENCODE_GIT_BASH_PATH` | chaîne | Chemin vers l'exécutable Git Bash sur Windows | | `OPENCODE_CONFIG` | chaîne | Chemin d'accès au fichier de configuration | +| `OPENCODE_TUI_CONFIG` | chaîne | Chemin d'accès au fichier de configuration TUI | | `OPENCODE_CONFIG_DIR` | chaîne | Chemin d'accès au répertoire de configuration | | `OPENCODE_CONFIG_CONTENT` | chaîne | Contenu de configuration JSON en ligne | | `OPENCODE_DISABLE_AUTOUPDATE` | booléen | Désactiver les vérifications automatiques des mises à jour | diff --git a/packages/web/src/content/docs/fr/config.mdx b/packages/web/src/content/docs/fr/config.mdx index 8c0d15e183..c576fe2da1 100644 --- a/packages/web/src/content/docs/fr/config.mdx +++ b/packages/web/src/content/docs/fr/config.mdx @@ -14,10 +14,11 @@ OpenCode prend en charge les formats **JSON** et **JSONC** (JSON avec commentair ```jsonc title="opencode.jsonc" { "$schema": "https://opencode.ai/config.json", - // Theme configuration - "theme": "opencode", "model": "anthropic/claude-sonnet-4-5", "autoupdate": true, + "server": { + "port": 4096, + }, } ``` @@ -34,7 +35,7 @@ Les fichiers de configuration sont **fusionnés**, pas remplacés. Les fichiers de configuration sont fusionnés et non remplacés. Les paramètres des emplacements de configuration suivants sont combinés. Les configurations ultérieures remplacent les précédentes uniquement en cas de clés en conflit. Les paramètres non conflictuels de toutes les configurations sont conservés. -Par exemple, si votre configuration globale définit `theme: "opencode"` et `autoupdate: true` et que la configuration de votre projet définit `model: "anthropic/claude-sonnet-4-5"`, la configuration finale inclura les trois paramètres. +Par exemple, si votre configuration globale définit `autoupdate: true` et que la configuration de votre projet définit `model: "anthropic/claude-sonnet-4-5"`, la configuration finale inclura les deux paramètres. --- @@ -95,7 +96,9 @@ Vous pouvez activer des serveurs spécifiques dans votre configuration locale : ### Globale -Placez votre configuration globale OpenCode dans `~/.config/opencode/opencode.json`. Utilisez la configuration globale pour les préférences de l'utilisateur telles que les thèmes, les fournisseurs ou les raccourcis clavier. +Placez votre configuration globale OpenCode dans `~/.config/opencode/opencode.json`. Utilisez la configuration globale pour les préférences de l'utilisateur telles que les fournisseurs, les modèles et les autorisations. + +Pour les paramètres spécifiques à TUI, utilisez `~/.config/opencode/tui.json`. La configuration globale remplace les paramètres par défaut de l'organisation distante. @@ -105,6 +108,8 @@ La configuration globale remplace les paramètres par défaut de l'organisation Ajoutez `opencode.json` à la racine de votre projet. La configuration du projet a la priorité la plus élevée parmi les fichiers de configuration standard : elle remplace les configurations globales et distantes. +Pour les paramètres TUI spécifiques au projet, ajoutez `tui.json` à côté. + :::tip Placez la configuration spécifique au projet à la racine de votre projet. ::: @@ -145,34 +150,32 @@ Le répertoire personnalisé est chargé après les répertoires de configuratio Le fichier de configuration a un schéma défini dans [**`opencode.ai/config.json`**](https://opencode.ai/config.json). +La configuration TUI utilise [**`opencode.ai/tui.json`**](https://opencode.ai/tui.json). + Votre éditeur doit être capable de valider et de compléter automatiquement en fonction du schéma. --- ### TUI -Vous pouvez configurer les paramètres spécifiques à TUI via l'option `tui`. +Utilisez un fichier dédié `tui.json` (ou `tui.jsonc`) pour les paramètres spécifiques à TUI. -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", - "tui": { - "scroll_speed": 3, - "scroll_acceleration": { - "enabled": true - }, - "diff_style": "auto" - } + "$schema": "https://opencode.ai/tui.json", + "scroll_speed": 3, + "scroll_acceleration": { + "enabled": true + }, + "diff_style": "auto" } ``` -Options disponibles : +Utilisez `OPENCODE_TUI_CONFIG` pour pointer vers un fichier de configuration TUI personnalisé. -- `scroll_acceleration.enabled` - Active l'accélération de défilement de style macOS. **A priorité sur `scroll_speed`.** -- `scroll_speed` - Multiplicateur de vitesse de défilement personnalisé (par défaut : `3`, minimum : `1`). Ignoré si `scroll_acceleration.enabled` est `true`. -- `diff_style` - Contrôle le rendu différentiel. `"auto"` s'adapte à la largeur du terminal, `"stacked"` affiche toujours une seule colonne. +Les anciennes clés `theme`, `keybinds` et `tui` dans `opencode.json` sont obsolètes et migrées automatiquement lorsque cela est possible. -[En savoir plus sur l'utilisation du TUI ici](/docs/tui). +[En savoir plus sur l'utilisation du TUI ici](/docs/tui#configure). --- @@ -298,12 +301,12 @@ Les jetons du porteur (`AWS_BEARER_TOKEN_BEDROCK` ou `/connect`) ont priorité s ### Thèmes -Vous pouvez configurer le thème que vous souhaitez utiliser dans votre configuration OpenCode via l'option `theme`. +Définissez votre thème d'interface utilisateur dans `tui.json`. -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", - "theme": "" + "$schema": "https://opencode.ai/tui.json", + "theme": "tokyonight" } ``` @@ -403,11 +406,11 @@ Vous pouvez également définir des commandes à l'aide de fichiers markdown dan ### Raccourcis clavier -Vous pouvez personnaliser vos raccourcis clavier via l'option `keybinds`. +Personnalisez les raccourcis clavier dans `tui.json`. -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "keybinds": {} } ``` @@ -487,13 +490,15 @@ Vous pouvez contrôler le comportement de compactage du contexte via l'option `c "$schema": "https://opencode.ai/config.json", "compaction": { "auto": true, - "prune": true + "prune": true, + "reserved": 10000 } } ``` - `auto` - Compacte automatiquement la session lorsque le contexte est plein (par défaut : `true`). - `prune` - Supprimez les anciennes sorties de l'outil pour économiser des tokens (par défaut : `true`). +- `reserved` - Tampon de jetons pour le compactage. Laisse suffisamment de marge pour éviter le débordement lors du compactage. --- diff --git a/packages/web/src/content/docs/fr/ecosystem.mdx b/packages/web/src/content/docs/fr/ecosystem.mdx index dd74e1f7bf..2ce2c52438 100644 --- a/packages/web/src/content/docs/fr/ecosystem.mdx +++ b/packages/web/src/content/docs/fr/ecosystem.mdx @@ -6,71 +6,73 @@ description: Projets et intégrations construits avec OpenCode. Une collection de projets communautaires construits sur OpenCode. :::note -Vous souhaitez ajouter votre projet lié à OpenCode à cette liste ? Soumettez un PR. +Vous souhaitez ajouter votre projet lié à OpenCode à cette liste ? Soumettez une PR. ::: -Vous pouvez également consulter [awesome-opencode](https://github.com/awesome-opencode/awesome-opencode) et [opencode.cafe](https://opencode.cafe), une communauté qui regroupe l'écosystème OpenCode. +Vous pouvez également consulter [awesome-opencode](https://github.com/awesome-opencode/awesome-opencode) et [opencode.cafe](https://opencode.cafe), une communauté qui regroupe l'écosystème et la communauté. --- ## Extensions -| Nom | Description | -| --------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | -| [opencode-daytona](https://github.com/jamesmurdza/daytona/blob/main/guides/typescript/opencode/README.md) | Exécute automatiquement des sessions OpenCode dans des environnements sandbox Daytona isolés avec synchronisation git et prévisualisations en direct | -| [opencode-helicone-session](https://github.com/H2Shami/opencode-helicone-session) | Injecte automatiquement les en-têtes de session Helicone pour le regroupement des requêtes | -| [opencode-type-inject](https://github.com/nick-vi/opencode-type-inject) | Injecte automatiquement les types TypeScript/Svelte dans les lectures de fichiers avec des outils de recherche | -| [opencode-openai-codex-auth](https://github.com/numman-ali/opencode-openai-codex-auth) | Utilise votre abonnement ChatGPT Plus/Pro au lieu de crédits API | -| [opencode-gemini-auth](https://github.com/jenslys/opencode-gemini-auth) | Utilise votre forfait Gemini existant au lieu de la facturation API | -| [opencode-antigravity-auth](https://github.com/NoeFabris/opencode-antigravity-auth) | Utilise les modèles gratuits d'Antigravity au lieu de la facturation API | -| [opencode-devcontainers](https://github.com/athal7/opencode-devcontainers) | Isolation de conteneur de développement multibranche avec clones superficiels et ports attribués automatiquement | -| [opencode-google-antigravity-auth](https://github.com/shekohex/opencode-google-antigravity-auth) | Plugin Google Antigravity OAuth, avec support de la recherche Google et gestion API plus robuste | -| [opencode-dynamic-context-pruning](https://github.com/Tarquinen/opencode-dynamic-context-pruning) | Optimise l'utilisation des jetons en éliminant les sorties d'outils obsolètes | -| [opencode-websearch-cited](https://github.com/ghoulr/opencode-websearch-cited.git) | Ajoute le support natif de la recherche Web pour les fournisseurs pris en charge avec le style ancré par Google | -| [opencode-pty](https://github.com/shekohex/opencode-pty.git) | Permet aux agents IA d'exécuter des processus en arrière-plan dans un PTY et de leur envoyer des entrées interactives. | -| [opencode-shell-strategy](https://github.com/JRedeker/opencode-shell-strategy) | Instructions pour les commandes shell non interactives - empêche les blocages des opérations dépendantes du TTY | -| [opencode-wakatime](https://github.com/angristan/opencode-wakatime) | Suit l'utilisation de OpenCode avec Wakatime | -| [opencode-md-table-formatter](https://github.com/franlol/opencode-md-table-formatter/tree/main) | Nettoie les tableaux Markdown produits par les LLM | -| [opencode-morph-fast-apply](https://github.com/JRedeker/opencode-morph-fast-apply) | Édition de code 10 fois plus rapide avec Morph Fast Apply API et les marqueurs d'édition différée | -| [oh-my-opencode](https://github.com/code-yeongyu/oh-my-opencode) | Agents d'arrière-plan, outils LSP/AST/MCP prédéfinis, agents sélectionnés, compatibles Claude Code | -| [opencode-notificator](https://github.com/panta82/opencode-notificator) | Notifications de bureau et alertes sonores pour les sessions OpenCode | -| [opencode-notifier](https://github.com/mohak34/opencode-notifier) | Notifications sur le bureau et alertes sonores pour les événements d'autorisation, d'achèvement et d'erreur | -| [opencode-zellij-namer](https://github.com/24601/opencode-zellij-namer) | Dénomination automatique de session Zellij basée sur l'IA et le contexte OpenCode | -| [opencode-skillful](https://github.com/zenobi-us/opencode-skillful) | Autorise les agents OpenCode à charger paresseusement les prompts à la demande grâce à la découverte et à l'injection de compétences | -| [opencode-supermemory](https://github.com/supermemoryai/opencode-supermemory) | Mémoire persistante entre les sessions utilisant Supermemory | -| [@plannotator/opencode](https://github.com/backnotprop/plannotator/tree/main/apps/opencode-plugin) | Révision interactive du plan avec annotation visuelle et partage privé/hors ligne | -| [@openspoon/subtask2](https://github.com/spoons-and-mirrors/subtask2) | Étend les commandes /commands d'opencode dans un système d'orchestration puissant avec contrôle de flux granulaire | -| [opencode-scheduler](https://github.com/different-ai/opencode-scheduler) | Planifie des tâches récurrentes à l'aide de launchd (Mac) ou systemd (Linux) avec la syntaxe cron | -| [micode](https://github.com/vtemian/micode) | Workflow structuré Brainstorming → Planifier → Mettre en œuvre avec continuité de session | -| [octto](https://github.com/vtemian/octto) | Interface utilisateur de navigateur interactive pour le brainstorming IA avec des formulaires multi-questions | -| [opencode-background-agents](https://github.com/kdcokenny/opencode-background-agents) | Agents d'arrière-plan de style Claude Code avec délégation asynchrone et persistance du contexte | -| [opencode-notify](https://github.com/kdcokenny/opencode-notify) | Notifications natives du système d'exploitation pour OpenCode – savoir quand les tâches sont terminées | -| [opencode-workspace](https://github.com/kdcokenny/opencode-workspace) | Harness d'orchestration multi-agent prêt à l'emploi - 16 composants, une installation | -| [opencode-worktree](https://github.com/kdcokenny/opencode-worktree) | Arbres de travail Git sans friction pour OpenCode | +| Nom | Description | +| -------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | +| [opencode-daytona](https://github.com/daytonaio/daytona/tree/main/libs/opencode-plugin) | Exécute automatiquement des sessions OpenCode dans des sandbox Daytona isolées avec synchronisation git et prévisualisations en direct | +| [opencode-helicone-session](https://github.com/H2Shami/opencode-helicone-session) | Injecte automatiquement les en-têtes de session Helicone pour le regroupement des requêtes | +| [opencode-type-inject](https://github.com/nick-vi/opencode-type-inject) | Injecte automatiquement les types TypeScript/Svelte dans les lectures de fichiers avec des outils de recherche | +| [opencode-openai-codex-auth](https://github.com/numman-ali/opencode-openai-codex-auth) | Utilise votre abonnement ChatGPT Plus/Pro au lieu de crédits API | +| [opencode-gemini-auth](https://github.com/jenslys/opencode-gemini-auth) | Utilise votre forfait Gemini existant au lieu de la facturation API | +| [opencode-antigravity-auth](https://github.com/NoeFabris/opencode-antigravity-auth) | Utilise les modèles gratuits d'Antigravity au lieu de la facturation API | +| [opencode-devcontainers](https://github.com/athal7/opencode-devcontainers) | Isolation de conteneur de développement multi-branches avec clones superficiels et ports attribués automatiquement | +| [opencode-google-antigravity-auth](https://github.com/shekohex/opencode-google-antigravity-auth) | Plugin OAuth Google Antigravity, avec prise en charge de la recherche Google et une gestion d'API plus robuste | +| [opencode-dynamic-context-pruning](https://github.com/Tarquinen/opencode-dynamic-context-pruning) | Optimise l'utilisation des jetons en élaguant les sorties d'outils obsolètes | +| [opencode-vibeguard](https://github.com/inkdust2021/opencode-vibeguard) | Masque les secrets/PII par des espaces réservés de style VibeGuard avant les appels LLM ; restaure localement | +| [opencode-websearch-cited](https://github.com/ghoulr/opencode-websearch-cited.git) | Ajoute le support natif de la recherche web pour les fournisseurs pris en charge avec le style Google Grounding | +| [opencode-pty](https://github.com/shekohex/opencode-pty.git) | Permet aux agents IA d'exécuter des processus en arrière-plan dans un PTY et de leur envoyer des entrées interactives. | +| [opencode-shell-strategy](https://github.com/JRedeker/opencode-shell-strategy) | Instructions pour les commandes shell non interactives - empêche les blocages dus aux opérations dépendantes du TTY | +| [opencode-wakatime](https://github.com/angristan/opencode-wakatime) | Suit l'utilisation d'OpenCode avec Wakatime | +| [opencode-md-table-formatter](https://github.com/franlol/opencode-md-table-formatter/tree/main) | Nettoie les tableaux Markdown produits par les LLM | +| [opencode-morph-fast-apply](https://github.com/JRedeker/opencode-morph-fast-apply) | Édition de code 10x plus rapide avec l'API Morph Fast Apply et des marqueurs d'édition différée | +| [oh-my-opencode](https://github.com/code-yeongyu/oh-my-opencode) | Agents d'arrière-plan, outils LSP/AST/MCP pré-construits, agents sélectionnés, compatible Claude Code | +| [opencode-notificator](https://github.com/panta82/opencode-notificator) | Notifications de bureau et alertes sonores pour les sessions OpenCode | +| [opencode-notifier](https://github.com/mohak34/opencode-notifier) | Notifications de bureau et alertes sonores pour les événements de permission, d'achèvement et d'erreur | +| [opencode-zellij-namer](https://github.com/24601/opencode-zellij-namer) | Nommage automatique de session Zellij alimenté par l'IA basé sur le contexte OpenCode | +| [opencode-skillful](https://github.com/zenobi-us/opencode-skillful) | Permet aux agents OpenCode le chargement différé de prompts à la demande avec découverte et injection de compétences | +| [opencode-supermemory](https://github.com/supermemoryai/opencode-supermemory) | Mémoire persistante entre les sessions utilisant Supermemory | +| [@plannotator/opencode](https://github.com/backnotprop/plannotator/tree/main/apps/opencode-plugin) | Révision de plan interactive avec annotation visuelle et partage privé/hors ligne | +| [@openspoon/subtask2](https://github.com/spoons-and-mirrors/subtask2) | Étend opencode /commands en un système d'orchestration puissant avec contrôle de flux granulaire | +| [opencode-scheduler](https://github.com/different-ai/opencode-scheduler) | Planifie des tâches récurrentes en utilisant launchd (Mac) ou systemd (Linux) avec la syntaxe cron | +| [micode](https://github.com/vtemian/micode) | Flux de travail structuré Brainstorming → Planification → Implémentation avec continuité de session | +| [octto](https://github.com/vtemian/octto) | Interface utilisateur de navigateur interactive pour le brainstorming IA avec des formulaires multi-questions | +| [opencode-background-agents](https://github.com/kdcokenny/opencode-background-agents) | Agents d'arrière-plan de style Claude Code avec délégation asynchrone et persistance du contexte | +| [opencode-notify](https://github.com/kdcokenny/opencode-notify) | Notifications natives de l'OS pour OpenCode – sachez quand les tâches sont terminées | +| [opencode-workspace](https://github.com/kdcokenny/opencode-workspace) | Harnais d'orchestration multi-agents groupé – 16 composants, une installation | +| [opencode-worktree](https://github.com/kdcokenny/opencode-worktree) | Worktrees git sans friction pour OpenCode | +| [opencode-sentry-monitor](https://github.com/stolinski/opencode-sentry-monitor) | Tracez et déboguez vos agents IA avec Sentry AI Monitoring | --- ## Projets -| Nom | Description | -| ------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------ | -| [kimaki](https://github.com/remorses/kimaki) | Bot Discord pour contrôler les sessions OpenCode, construit sur le SDK | -| [opencode.nvim](https://github.com/NickvanDyke/opencode.nvim) | Plugin Neovim pour les prompts compatibles avec l'éditeur, construit sur l'API | -| [portal](https://github.com/hosenur/portal) | Interface utilisateur Web axée sur le mobile pour OpenCode sur Tailscale/VPN | -| [opencode plugin template](https://github.com/zenobi-us/opencode-plugin-template/) | Modèle pour créer des plugins OpenCode | -| [opencode.nvim](https://github.com/sudo-tee/opencode.nvim) | Frontend Neovim pour opencode - un agent de codage d'IA basé sur un terminal | -| [ai-sdk-provider-opencode-sdk](https://github.com/ben-vargas/ai-sdk-provider-opencode-sdk) | Fournisseur Vercel AI SDK pour l'utilisation de OpenCode via @opencode-ai/sdk | -| [OpenChamber](https://github.com/btriapitsyn/openchamber) | Application Web/De bureau et extension VS Code pour OpenCode | -| [OpenCode-Obsidian](https://github.com/mtymek/opencode-obsidian) | Plugin Obsidian qui intègre OpenCode dans l'interface utilisateur d'Obsidian | -| [OpenWork](https://github.com/different-ai/openwork) | Une alternative open source à Claude Cowork, propulsée par OpenCode | -| [ocx](https://github.com/kdcokenny/ocx) | Gestionnaire d'extensions OpenCode avec profils portables et isolés. | -| [CodeNomad](https://github.com/NeuralNomadsAI/CodeNomad) | Application client de bureau, Web, mobile et distante pour OpenCode | +| Nom | Description | +| ------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------- | +| [kimaki](https://github.com/remorses/kimaki) | Bot Discord pour contrôler les sessions OpenCode, construit sur le SDK | +| [opencode.nvim](https://github.com/NickvanDyke/opencode.nvim) | Plugin Neovim pour des prompts conscients de l'éditeur, construit sur l'API | +| [portal](https://github.com/hosenur/portal) | Interface Web mobile-first pour OpenCode via Tailscale/VPN | +| [opencode plugin template](https://github.com/zenobi-us/opencode-plugin-template/) | Modèle pour créer des plugins OpenCode | +| [opencode.nvim](https://github.com/sudo-tee/opencode.nvim) | Frontend Neovim pour opencode - un agent de codage IA basé sur terminal | +| [ai-sdk-provider-opencode-sdk](https://github.com/ben-vargas/ai-sdk-provider-opencode-sdk) | Fournisseur Vercel AI SDK pour utiliser OpenCode via @opencode-ai/sdk | +| [OpenChamber](https://github.com/btriapitsyn/openchamber) | Application Web / Bureau et extension VS Code pour OpenCode | +| [OpenCode-Obsidian](https://github.com/mtymek/opencode-obsidian) | Plugin Obsidian qui intègre OpenCode dans l'interface d'Obsidian | +| [OpenWork](https://github.com/different-ai/openwork) | Une alternative open-source à Claude Cowork, propulsée par OpenCode | +| [ocx](https://github.com/kdcokenny/ocx) | Gestionnaire d'extensions OpenCode avec profils portables et isolés. | +| [CodeNomad](https://github.com/NeuralNomadsAI/CodeNomad) | Application client Bureau, Web, Mobile et Distante pour OpenCode | --- ## Agents -| Nom | Description | -| ----------------------------------------------------------------- | ----------------------------------------------------------------------------- | -| [Agentic](https://github.com/Cluster444/agentic) | Agents et commandes d'IA modulaires pour un développement structuré | -| [opencode-agents](https://github.com/darrenhinde/opencode-agents) | Configurations, prompts, agents et plugins pour des flux de travail améliorés | +| Nom | Description | +| ----------------------------------------------------------------- | ---------------------------------------------------------------------- | +| [Agentic](https://github.com/Cluster444/agentic) | Agents IA modulaires et commandes pour un développement structuré | +| [opencode-agents](https://github.com/darrenhinde/opencode-agents) | Configs, prompts, agents et plugins pour des flux de travail améliorés | diff --git a/packages/web/src/content/docs/fr/go.mdx b/packages/web/src/content/docs/fr/go.mdx new file mode 100644 index 0000000000..fc2b6aa6c6 --- /dev/null +++ b/packages/web/src/content/docs/fr/go.mdx @@ -0,0 +1,145 @@ +--- +title: Go +description: Abonnement à bas coût pour les modèles de code ouverts. +--- + +import config from "../../../../config.mjs" +export const console = config.console +export const email = `mailto:${config.email}` + +OpenCode Go est un abonnement à bas coût de **10 $/mois** qui vous donne un accès fiable aux modèles de code ouverts populaires. + +:::note +OpenCode Go est actuellement en bêta. +::: + +Go fonctionne comme tout autre fournisseur dans OpenCode. Vous vous abonnez à OpenCode Go et obtenez votre clé API. C'est **complètement optionnel** et vous n'avez pas besoin de l'utiliser pour utiliser OpenCode. + +Il est conçu principalement pour les utilisateurs internationaux, avec des modèles hébergés aux États-Unis, en UE et à Singapour pour un accès mondial stable. + +--- + +## Contexte + +Les modèles ouverts sont devenus vraiment bons. Ils atteignent maintenant des performances proches des modèles propriétaires pour les tâches de codage. Et parce que de nombreux fournisseurs peuvent les servir de manière compétitive, ils sont généralement beaucoup moins chers. + +Cependant, obtenir un accès fiable et à faible latence à ces modèles peut être difficile. Les fournisseurs varient en qualité et en disponibilité. + +:::tip +Nous avons testé un groupe sélectionné de modèles et de fournisseurs qui fonctionnent bien avec OpenCode. +::: + +Pour remédier à cela, nous avons fait plusieurs choses : + +1. Nous avons testé un groupe sélectionné de modèles ouverts et discuté avec leurs équipes de la meilleure façon de les exécuter. +2. Nous avons ensuite travaillé avec quelques fournisseurs pour nous assurer qu'ils étaient servis correctement. +3. Enfin, nous avons évalué la combinaison modèle/fournisseur et établi une liste que nous nous sentons à l'aise de recommander. + +OpenCode Go vous donne accès à ces modèles pour **10 $/mois**. + +--- + +## Comment ça marche + +OpenCode Go fonctionne comme tout autre fournisseur dans OpenCode. + +1. Vous vous connectez à **<a href={console}>OpenCode Zen</a>**, vous vous abonnez à Go et copiez votre clé API. +2. Vous exécutez la commande `/connect` dans la TUI, sélectionnez `OpenCode Go`, et collez votre clé API. +3. Exécutez `/models` dans la TUI pour voir la liste des modèles disponibles via Go. + +:::note +Un seul membre par espace de travail peut s'abonner à OpenCode Go. +::: + +La liste actuelle des modèles inclut : + +- **GLM-5** +- **Kimi K2.5** +- **MiniMax M2.5** + +La liste des modèles peut changer à mesure que nous testons et ajoutons de nouveaux modèles. + +--- + +## Limites d'utilisation + +OpenCode Go inclut les limites suivantes : + +- **Limite de 5 heures** — 12 $ d'utilisation +- **Limite hebdomadaire** — 30 $ d'utilisation +- **Limite mensuelle** — 60 $ d'utilisation + +Les limites sont définies en valeur monétaire. Cela signifie que votre nombre réel de requêtes dépend du modèle que vous utilisez. Les modèles moins chers comme MiniMax M2.5 permettent plus de requêtes, tandis que les modèles plus coûteux comme GLM-5 en permettent moins. + +Le tableau ci-dessous fournit une estimation du nombre de requêtes basée sur des modèles d'utilisation typiques de Go : + +| | GLM-5 | Kimi K2.5 | MiniMax M2.5 | +| --------------------- | ----- | --------- | ------------ | +| requêtes par 5 heures | 1 150 | 1 850 | 30 000 | +| requêtes par semaine | 2 880 | 4 630 | 75 000 | +| requêtes par mois | 5 750 | 9 250 | 150 000 | + +Les estimations sont basées sur des modèles de requêtes moyens observés : + +- GLM-5 — 700 tokens d'entrée, 52 000 en cache, 150 de sortie par requête +- Kimi K2.5 — 870 tokens d'entrée, 55 000 en cache, 200 de sortie par requête +- MiniMax M2.5 — 300 tokens d'entrée, 55 000 en cache, 125 de sortie par requête + +Vous pouvez suivre votre utilisation actuelle dans la **<a href={console}>console</a>**. + +:::tip +Si vous atteignez la limite d'utilisation, vous pouvez continuer à utiliser les modèles gratuits. +::: + +Les limites d'utilisation peuvent changer à mesure que nous apprenons des premiers usages et retours. + +--- + +### Tarification + +OpenCode Go est un plan d'abonnement à **10 $/mois**. Ci-dessous se trouvent les prix **par 1M de tokens**. + +| Modèle | Entrée | Sortie | Lecture en cache | +| ------------ | ------ | ------ | ---------------- | +| GLM-5 | 1,00 $ | 3,20 $ | 0,20 $ | +| Kimi K2.5 | 0,60 $ | 3,00 $ | 0,10 $ | +| MiniMax M2.5 | 0,30 $ | 1,20 $ | 0,03 $ | + +--- + +### Utilisation au-delà des limites + +Si vous avez aussi des crédits sur votre solde Zen, vous pouvez activer l'option **Use balance** dans la console. Lorsqu'elle est activée, Go basculera sur votre solde Zen après que vous ayez atteint vos limites d'utilisation au lieu de bloquer les requêtes. + +--- + +## Endpoints + +Vous pouvez également accéder aux modèles Go via les endpoints API suivants. + +| Modèle | ID du modèle | Endpoint | Package AI SDK | +| ------------ | ------------ | ------------------------------------------------ | --------------------------- | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | + +L'[ID du modèle](/docs/config/#models) dans votre configuration OpenCode utilise le format `opencode-go/<model-id>`. Par exemple, pour Kimi K2.5, vous utiliseriez `opencode-go/kimi-k2.5` dans votre configuration. + +--- + +## Confidentialité + +Le plan est conçu principalement pour les utilisateurs internationaux, avec des modèles hébergés aux États-Unis, en UE et à Singapour pour un accès mondial stable. + +<a href={email}>Contactez-nous</a> si vous avez des questions. + +--- + +## Objectifs + +Nous avons créé OpenCode Go pour : + +1. Rendre le codage par IA **accessible** à plus de personnes avec un abonnement à bas coût. +2. Fournir un accès **fiable** aux meilleurs modèles de code ouverts. +3. Sélectionner des modèles qui sont **testés et évalués** pour l'utilisation d'agents de codage. +4. N'avoir **aucun verrouillage** en vous permettant d'utiliser tout autre fournisseur avec OpenCode également. diff --git a/packages/web/src/content/docs/fr/keybinds.mdx b/packages/web/src/content/docs/fr/keybinds.mdx index 4ec98adfa2..281e5df743 100644 --- a/packages/web/src/content/docs/fr/keybinds.mdx +++ b/packages/web/src/content/docs/fr/keybinds.mdx @@ -28,6 +28,7 @@ OpenCode a une liste de raccourcis clavier que vous pouvez personnaliser via la "session_unshare": "none", "session_interrupt": "escape", "session_compact": "<leader>c", + "session_child_first": "<leader>down", "session_child_cycle": "<leader>right", "session_child_cycle_reverse": "<leader>left", "session_parent": "<leader>up", diff --git a/packages/web/src/content/docs/fr/lsp.mdx b/packages/web/src/content/docs/fr/lsp.mdx index cf2dfb6180..8a83370da0 100644 --- a/packages/web/src/content/docs/fr/lsp.mdx +++ b/packages/web/src/content/docs/fr/lsp.mdx @@ -27,6 +27,7 @@ OpenCode est livré avec plusieurs serveurs LSP intégrés pour les langages pop | gopls | .go | Commande `go` disponible | | hls | .hs, .lhs | Commande `haskell-language-server-wrapper` disponible | | jdtls | .java | `Java SDK (version 21+)` installé | +| julials | .jl | `julia` et `LanguageServer.jl` installés | | kotlin-ls | .kt, .kts | Installation automatique pour les projets Kotlin | | lua-ls | .lua | Installation automatique pour les projets Lua | | nixd | .nix | Commande `nixd` disponible | diff --git a/packages/web/src/content/docs/fr/mcp-servers.mdx b/packages/web/src/content/docs/fr/mcp-servers.mdx index e1d1f24e7c..5d01286879 100644 --- a/packages/web/src/content/docs/fr/mcp-servers.mdx +++ b/packages/web/src/content/docs/fr/mcp-servers.mdx @@ -375,9 +375,9 @@ Si vous disposez d'un grand nombre de serveurs MCP, vous souhaiterez peut-être --- -#### Patterns glob +#### Modèles globaux -Le pattern glob utilise des modèles de globbing regex simples : +Le modèle glob utilise des modèles de globbing regex simples : - `*` correspond à zéro ou plusieurs caractères (par exemple, `"my-mcp*"` correspond à `my-mcp_search`, `my-mcp_list`, etc.) - `?` correspond exactement à un caractère @@ -509,473 +509,3 @@ Alternativement, vous pouvez ajouter quelque chose comme ceci à votre [AGENTS.m ```md title="AGENTS.md" If you are unsure how to do something, use `gh_grep` to search code examples from GitHub. ``` - -Vous pouvez également désactiver un serveur en définissant `enabled` sur `false`. Ceci est utile si vous souhaitez désactiver temporairement un serveur sans le supprimer de votre configuration. - ---- - -### Remplacement des valeurs par défaut distantes - -Les organisations peuvent fournir des serveurs MCP par défaut via leur point de terminaison `.well-known/opencode`. Ces serveurs peuvent être désactivés par défaut, permettant aux utilisateurs de choisir ceux dont ils ont besoin. - -Pour activer un serveur spécifique à partir de la configuration distante de votre organisation, ajoutez-le à votre configuration locale avec `enabled: true` : - -```json title="opencode.json" -{ - "$schema": "https://opencode.ai/config.json", - "mcp": { - "jira": { - "type": "remote", - "url": "https://jira.example.com/mcp", - "enabled": true - } - } -} -``` - -Vos valeurs de configuration locales remplacent les valeurs par défaut distantes. Voir [config precedence](/docs/config#precedence-order) pour plus de détails. - ---- - -## Local - -Ajoutez des serveurs MCP locaux en utilisant `type` à `"local"` dans l'objet MCP. - -```jsonc title="opencode.jsonc" {15} -{ - "$schema": "https://opencode.ai/config.json", - "mcp": { - "my-local-mcp-server": { - "type": "local", - // Or ["bun", "x", "my-mcp-command"] - "command": ["npx", "-y", "my-mcp-command"], - "enabled": true, - "environment": { - "MY_ENV_VAR": "my_env_var_value", - }, - }, - }, -} -``` - -La commande indique comment le serveur MCP local est démarré. Vous pouvez également transmettre une liste de variables d’environnement. - -Par exemple, voici comment ajouter le serveur de test [`@modelcontextprotocol/server-everything`](https://www.npmjs.com/package/@modelcontextprotocol/server-everything) MCP. - -```jsonc title="opencode.jsonc" -{ - "$schema": "https://opencode.ai/config.json", - "mcp": { - "mcp_everything": { - "type": "local", - "command": ["npx", "-y", "@modelcontextprotocol/server-everything"], - }, - }, -} -``` - -Et pour l'utiliser, je peux ajouter `use the mcp_everything tool` à mes invites. - -```txt "mcp_everything" -use the mcp_everything tool to add the number 3 and 4 -``` - ---- - -#### Options - -Voici toutes les options pour configurer un serveur MCP local. - -| Options | Tapez | Obligatoire | Descriptif | -| ------------- | ------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------- | -| `type` | Chaîne | Oui | Le type de connexion au serveur MCP doit être `"local"`. | -| `command` | Tableau | Oui | Commande et arguments pour exécuter le serveur MCP. | -| `environment` | Objet | | Variables d'environnement à définir lors de l'exécution du serveur. | -| `enabled` | Booléen | | Activez ou désactivez le serveur MCP au démarrage. | -| `timeout` | Numéro | | Délai d'expiration en ms pour la récupération des outils depuis le serveur MCP. La valeur par défaut est 5 000 (5 secondes). | - ---- - -## Remote - -Ajoutez des serveurs MCP distants en définissant `type` sur `"remote"`. - -```json title="opencode.json" -{ - "$schema": "https://opencode.ai/config.json", - "mcp": { - "my-remote-mcp": { - "type": "remote", - "url": "https://my-mcp-server.com", - "enabled": true, - "headers": { - "Authorization": "Bearer MY_API_KEY" - } - } - } -} -``` - -Le champ `url` est l'URL du serveur MCP distant et l'option `headers` vous permet de transmettre des en-têtes. - ---- - -#### Options - -| Options | Tapez | Obligatoire | Descriptif | -| --------- | ------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------- | -| `type` | Chaîne | Oui | Le type de connexion au serveur MCP doit être `"remote"`. | -| `url` | Chaîne | Oui | URL du serveur MCP distant. | -| `enabled` | Booléen | | Activez ou désactivez le serveur MCP au démarrage. | -| `headers` | Objet | | En-têtes à envoyer avec la demande. | -| `oauth` | Objet | | Configuration de l'authentification OAuth. Voir la section [OAuth](#oauth) ci-dessous. | -| `timeout` | Numéro | | Délai d'expiration en ms pour la récupération des outils depuis le serveur MCP. La valeur par défaut est 5 000 (5 secondes). | - ---- - -## OAuth - -OpenCode gère automatiquement l'authentification OAuth pour les serveurs MCP distants. Lorsqu'un serveur nécessite une authentification, OpenCode : - -1. Détectez la réponse 401 et lancez le flux OAuth -2. Utilisez **Enregistrement client dynamique (RFC 7591)** s'il est pris en charge par le serveur. -3. Stockez les jetons en toute sécurité pour les demandes futures - ---- - -### Automatique - -Pour la plupart des serveurs MCP compatibles OAuth, aucune configuration particulière n'est nécessaire. Configurez simplement le serveur distant : - -```json title="opencode.json" -{ - "$schema": "https://opencode.ai/config.json", - "mcp": { - "my-oauth-server": { - "type": "remote", - "url": "https://mcp.example.com/mcp" - } - } -} -``` - -Si le serveur nécessite une authentification, OpenCode vous demandera de vous authentifier lorsque vous essayez de l'utiliser pour la première fois. Sinon, vous pouvez [déclencher manuellement le flux](#authenticating) avec `opencode mcp auth <server-name>`. - ---- - -### Pré-inscrit - -Si vous disposez des informations d'identification client du fournisseur de serveur MCP, vous pouvez les configurer : - -```json title="opencode.json" {7-11} -{ - "$schema": "https://opencode.ai/config.json", - "mcp": { - "my-oauth-server": { - "type": "remote", - "url": "https://mcp.example.com/mcp", - "oauth": { - "clientId": "{env:MY_MCP_CLIENT_ID}", - "clientSecret": "{env:MY_MCP_CLIENT_SECRET}", - "scope": "tools:read tools:execute" - } - } - } -} -``` - ---- - -### Authentification - -Vous pouvez déclencher manuellement l'authentification ou gérer les informations d'identification. - -Authentifiez-vous auprès d'un serveur MCP spécifique : - -```bash -opencode mcp auth my-oauth-server -``` - -Répertoriez tous les serveurs MCP et leur statut d'authentification : - -```bash -opencode mcp list -``` - -Supprimez les informations d'identification stockées : - -```bash -opencode mcp logout my-oauth-server -``` - -La commande `mcp auth` ouvrira votre navigateur pour autorisation. Après votre autorisation, OpenCode stockera les jetons en toute sécurité dans `~/.local/share/opencode/mcp-auth.json`. - ---- - -#### Désactivation de OAuth - -Si vous souhaitez désactiver le OAuth automatique pour un serveur (par exemple, pour les serveurs qui utilisent les clés API à la place), définissez `oauth` sur `false` : - -```json title="opencode.json" {7} -{ - "$schema": "https://opencode.ai/config.json", - "mcp": { - "my-api-key-server": { - "type": "remote", - "url": "https://mcp.example.com/mcp", - "oauth": false, - "headers": { - "Authorization": "Bearer {env:MY_API_KEY}" - } - } - } -} -``` - ---- - -#### Options OAuth - -| Options | Tapez | Descriptif | -| -------------- | ------------- | ---------------------------------------------------------------------------------------- | -| `oauth` | Objet \| faux | Objet de configuration OAuth, ou `false` pour désactiver la détection automatique OAuth. | -| `clientId` | Chaîne | ID client OAuth. S’il n’est pas fourni, l’enregistrement dynamique du client sera tenté. | -| `clientSecret` | Chaîne | OAuth secret client, si requis par le serveur d'autorisation. | -| `scope` | Chaîne | OAuth scopes à demander lors de l'autorisation. | - -#### Débogage - -Si un serveur MCP distant ne parvient pas à s'authentifier, vous pouvez diagnostiquer les problèmes avec : - -```bash -# View auth status for all OAuth-capable servers -opencode mcp auth list - -# Debug connection and OAuth flow for a specific server -opencode mcp debug my-oauth-server -``` - -La commande `mcp debug` affiche l'état d'authentification actuel, teste la connectivité HTTP et tente le flux de découverte OAuth. - ---- - -## Gérer - -Vos MCP sont disponibles sous forme d'outils dans OpenCode, aux côtés des outils intégrés. Vous pouvez donc les gérer via la configuration OpenCode comme n'importe quel autre outil. - ---- - -### Global - -Cela signifie que vous pouvez les activer ou les désactiver globalement. - -```json title="opencode.json" {14} -{ - "$schema": "https://opencode.ai/config.json", - "mcp": { - "my-mcp-foo": { - "type": "local", - "command": ["bun", "x", "my-mcp-command-foo"] - }, - "my-mcp-bar": { - "type": "local", - "command": ["bun", "x", "my-mcp-command-bar"] - } - }, - "tools": { - "my-mcp-foo": false - } -} -``` - -Nous pouvons également utiliser un modèle global pour désactiver tous les MCP correspondants. - -```json title="opencode.json" {14} -{ - "$schema": "https://opencode.ai/config.json", - "mcp": { - "my-mcp-foo": { - "type": "local", - "command": ["bun", "x", "my-mcp-command-foo"] - }, - "my-mcp-bar": { - "type": "local", - "command": ["bun", "x", "my-mcp-command-bar"] - } - }, - "tools": { - "my-mcp*": false - } -} -``` - -Ici, nous utilisons le modèle global `my-mcp*` pour désactiver tous les MCP. - ---- - -### Par agent - -Si vous disposez d'un grand nombre de serveurs MCP, vous souhaiterez peut-être les activer uniquement par agent et les désactiver globalement. Pour ce faire : - -1. Désactivez-le en tant qu'outil à l'échelle mondiale. -2. Dans votre [agent config](/docs/agents#tools), activez le serveur MCP en tant qu'outil. - -```json title="opencode.json" {11, 14-18} -{ - "$schema": "https://opencode.ai/config.json", - "mcp": { - "my-mcp": { - "type": "local", - "command": ["bun", "x", "my-mcp-command"], - "enabled": true - } - }, - "tools": { - "my-mcp*": false - }, - "agent": { - "my-agent": { - "tools": { - "my-mcp*": true - } - } - } -} -``` - ---- - -#### Modèles globaux - -Le modèle glob utilise des modèles de globbing regex simples : - -- `*` correspond à zéro ou plusieurs caractères (par exemple, `"my-mcp*"` correspond à `my-mcp_search`, `my-mcp_list`, etc.) -- `?` correspond exactement à un caractère -- Tous les autres caractères correspondent littéralement - -:::note -Les outils serveur MCP sont enregistrés avec le nom du serveur comme préfixe, donc pour désactiver tous les outils d'un serveur, utilisez simplement : - -``` -"mymcpservername_*": false -``` - -::: - ---- - -## Exemples - -Vous trouverez ci-dessous des exemples de serveurs MCP courants. Vous pouvez soumettre un PR si vous souhaitez documenter d'autres serveurs. - ---- - -### Sentry - -Ajoutez le [serveur Sentry MCP](https://mcp.sentry.dev) pour interagir avec vos projets et problèmes Sentry. - -```json title="opencode.json" {4-8} -{ - "$schema": "https://opencode.ai/config.json", - "mcp": { - "sentry": { - "type": "remote", - "url": "https://mcp.sentry.dev/mcp", - "oauth": {} - } - } -} -``` - -Après avoir ajouté la configuration, authentifiez-vous auprès de Sentry : - -```bash -opencode mcp auth sentry -``` - -Cela ouvrira une fenêtre de navigateur pour terminer le flux OAuth et connecter OpenCode à votre compte Sentry. - -Une fois authentifié, vous pouvez utiliser les outils Sentry dans vos invites pour interroger les problèmes, les projets et les données d'erreur. - -```txt "use sentry" -Show me the latest unresolved issues in my project. use sentry -``` - ---- - -### Contexte7 - -Ajoutez le [Context7 MCP server](https://github.com/upstash/context7) pour effectuer une recherche dans les documents. - -```json title="opencode.json" {4-7} -{ - "$schema": "https://opencode.ai/config.json", - "mcp": { - "context7": { - "type": "remote", - "url": "https://mcp.context7.com/mcp" - } - } -} -``` - -Si vous avez créé un compte gratuit, vous pouvez utiliser votre clé API et obtenir des limites de débit plus élevées. - -```json title="opencode.json" {7-9} -{ - "$schema": "https://opencode.ai/config.json", - "mcp": { - "context7": { - "type": "remote", - "url": "https://mcp.context7.com/mcp", - "headers": { - "CONTEXT7_API_KEY": "{env:CONTEXT7_API_KEY}" - } - } - } -} -``` - -Ici, nous supposons que la variable d'environnement `CONTEXT7_API_KEY` est définie. - -Ajoutez `use context7` à vos invites pour utiliser le serveur Context7 MCP. - -```txt "use context7" -Configure a Cloudflare Worker script to cache JSON API responses for five minutes. use context7 -``` - -Alternativement, vous pouvez ajouter quelque chose comme ceci à votre [AGENTS.md](/docs/rules/). - -```md title="AGENTS.md" -When you need to search docs, use `context7` tools. -``` - ---- - -### Grep by Vercel - -Ajoutez le serveur [Grep by Vercel](https://grep.app) MCP pour rechercher des extraits de code sur GitHub. - -```json title="opencode.json" {4-7} -{ - "$schema": "https://opencode.ai/config.json", - "mcp": { - "gh_grep": { - "type": "remote", - "url": "https://mcp.grep.app" - } - } -} -``` - -Puisque nous avons nommé notre serveur MCP `gh_grep`, vous pouvez ajouter `use the gh_grep tool` à vos invites pour que l'agent l'utilise. - -```txt "use the gh_grep tool" -What's the right way to set a custom domain in an SST Astro component? use the gh_grep tool -``` - -Alternativement, vous pouvez ajouter quelque chose comme ceci à votre [AGENTS.md](/docs/rules/). - -```md title="AGENTS.md" -If you are unsure how to do something, use `gh_grep` to search code examples from GitHub. -``` diff --git a/packages/web/src/content/docs/fr/providers.mdx b/packages/web/src/content/docs/fr/providers.mdx index b65e9c00a1..36e1ed2d2b 100644 --- a/packages/web/src/content/docs/fr/providers.mdx +++ b/packages/web/src/content/docs/fr/providers.mdx @@ -84,6 +84,38 @@ Il fonctionne comme n’importe quel autre fournisseur dans OpenCode et son util --- +## OpenCode Go + +OpenCode Go est un plan d'abonnement à faible coût qui offre un accès fiable aux modèles de codage ouverts populaires fournis par l'équipe OpenCode qui ont été +testé et vérifié pour fonctionner correctement avec OpenCode. + +1. Exécutez la commande `/connect` dans le TUI, sélectionnez `OpenCode Go` et rendez-vous sur [opencode.ai/auth](https://opencode.ai/zen). + + ```txt + /connect + ``` + +2. Connectez-vous, ajoutez vos informations de facturation et copiez votre clé API. + +3. Collez votre clé API. + + ```txt + ┌ API key + │ + │ + └ enter + ``` + +4. Exécutez `/models` dans le TUI pour voir la liste des modèles que nous recommandons. + + ```txt + /models + ``` + +Il fonctionne comme n’importe quel autre fournisseur dans OpenCode et son utilisation est totalement facultative. + +--- + ## Annuaire Examinons certains fournisseurs en détail. Si vous souhaitez ajouter un fournisseur au @@ -1487,6 +1519,39 @@ Ou ajoutez-le à votre profil bash : --- +### STACKIT + +STACKIT AI Model Serving fournit un environnement d'hébergement souverain entièrement géré pour les modèles d'IA, se concentrant sur les LLM comme Llama, Mistral et Qwen, avec une souveraineté maximale des données sur l'infrastructure européenne. + +1. Rendez-vous sur le [portail STACKIT](https://portal.stackit.cloud), accédez à **AI Model Serving** et créez un jeton d'authentification pour votre projet. + + :::tip + Vous avez besoin d'un compte client STACKIT, d'un compte utilisateur et d'un projet avant de créer des jetons d'authentification. + ::: + +2. Exécutez la commande `/connect` et recherchez **STACKIT**. + + ```txt + /connect + ``` + +3. Entrez votre jeton d'authentification STACKIT AI Model Serving. + + ```txt + ┌ API key + │ + │ + └ enter + ``` + +4. Exécutez la commande `/models` pour sélectionner parmi les modèles disponibles tels que _Qwen3-VL 235B_ ou _Llama 3.3 70B_. + + ```txt + /models + ``` + +--- + ### OVHcloud AI Endpoints 1. Rendez-vous sur le [Panneau OVHcloud](https://ovh.com/manager). Accédez à la section `Public Cloud`, `AI & Machine Learning` > `AI Endpoints` et dans l'onglet `API Keys`, cliquez sur **Créer une nouvelle clé API**. diff --git a/packages/web/src/content/docs/fr/sdk.mdx b/packages/web/src/content/docs/fr/sdk.mdx index 0e67aebd00..ee3a2dc49c 100644 --- a/packages/web/src/content/docs/fr/sdk.mdx +++ b/packages/web/src/content/docs/fr/sdk.mdx @@ -117,6 +117,78 @@ try { --- +## Sortie structurée + +Vous pouvez demander une sortie JSON structurée au modèle en spécifiant un `format` avec un schéma JSON. Le modèle utilisera un outil `StructuredOutput` pour renvoyer un JSON validé correspondant à votre schéma. + +### Utilisation de base + +```typescript +const result = await client.session.prompt({ + path: { id: sessionId }, + body: { + parts: [{ type: "text", text: "Research Anthropic and provide company info" }], + format: { + type: "json_schema", + schema: { + type: "object", + properties: { + company: { type: "string", description: "Company name" }, + founded: { type: "number", description: "Year founded" }, + products: { + type: "array", + items: { type: "string" }, + description: "Main products", + }, + }, + required: ["company", "founded"], + }, + }, + }, +}) + +// Access the structured output +console.log(result.data.info.structured_output) +// { company: "Anthropic", founded: 2021, products: ["Claude", "Claude API"] } +``` + +### Types de format de sortie + +| Type | Description | +| ------------- | ----------------------------------------------------------------- | +| `text` | Par défaut. Réponse textuelle standard (pas de sortie structurée) | +| `json_schema` | Renvoie un JSON validé correspondant au schéma fourni | + +### Format de schéma JSON + +Lors de l'utilisation de `type: 'json_schema'`, fournissez : + +| Champ | Type | Description | +| ------------ | --------------- | --------------------------------------------------------------- | +| `type` | `'json_schema'` | Requis. Spécifie le mode de schéma JSON | +| `schema` | `object` | Requis. Objet JSON Schema définissant la structure de sortie | +| `retryCount` | `number` | Facultatif. Nombre de tentatives de validation (par défaut : 2) | + +### Gestion des erreurs + +Si le modèle ne parvient pas à produire une sortie structurée valide après toutes les tentatives, la réponse inclura une `StructuredOutputError` : + +```typescript +if (result.data.info.error?.name === "StructuredOutputError") { + console.error("Failed to produce structured output:", result.data.info.error.message) + console.error("Attempts:", result.data.info.error.retries) +} +``` + +### Bonnes pratiques + +1. **Fournissez des descriptions claires** dans les propriétés de votre schéma pour aider le modèle à comprendre quelles données extraire +2. **Utilisez `required`** pour spécifier quels champs doivent être présents +3. **Gardez les schémas ciblés** - les schémas imbriqués complexes peuvent être plus difficiles à remplir correctement pour le modèle +4. **Définissez un `retryCount` approprié** - augmentez-le pour les schémas complexes, diminuez-le pour les simples + +--- + ## APIs Le SDK expose toutes les API du serveur via un client de type sécurisé. @@ -226,27 +298,27 @@ const { providers, default: defaults } = await client.config.providers() ### Séances -| Méthode | Descriptif | Remarques | -| ---------------------------------------------------------- | ------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `session.list()` | Liste des séances | Renvoie <a href={typesUrl}><code>Session[]</code></a> | -| `session.get({ path })` | Obtenir une session | Renvoie <a href={typesUrl}><code>Session</code></a> | -| `session.children({ path })` | Liste des sessions enfants | Renvoie <a href={typesUrl}><code>Session[]</code></a> | -| `session.create({ body })` | Créer une séance | Renvoie <a href={typesUrl}><code>Session</code></a> | -| `session.delete({ path })` | Supprimer la séance | Renvoie `boolean` | -| `session.update({ path, body })` | Mettre à jour les propriétés de la session | Renvoie <a href={typesUrl}><code>Session</code></a> | -| `session.init({ path, body })` | Analysez l'application et créez `AGENTS.md` | Renvoie `boolean` | -| `session.abort({ path })` | Abandonner une session en cours | Renvoie `boolean` | -| `session.share({ path })` | Séance de partage | Renvoie <a href={typesUrl}><code>Session</code></a> | -| `session.unshare({ path })` | Annuler le partage de la session | Renvoie <a href={typesUrl}><code>Session</code></a> | -| `session.summarize({ path, body })` | Résumer la séance | Renvoie `boolean` | -| `session.messages({ path })` | Liste des messages dans une session | Renvoie `{ info: `<a href={typesUrl}><code>Message</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}[]` | -| `session.message({ path })` | Obtenir les détails du message | Renvoie `{ info: `<a href={typesUrl}><code>Message</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}` | -| `session.prompt({ path, body })` | Envoyer un message d'invite | `body.noReply: true` renvoie UserMessage (contexte uniquement). La valeur par défaut renvoie <a href={typesUrl}><code>AssistantMessage</code></a> avec réponse IA | -| `session.command({ path, body })` | Envoyer la commande à la session | Renvoie `{ info: `<a href={typesUrl}><code>AssistantMessage</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}` | -| `session.shell({ path, body })` | Exécuter une commande shell | Renvoie <a href={typesUrl}><code>AssistantMessage</code></a> | -| `session.revert({ path, body })` | Rétablir un message | Renvoie <a href={typesUrl}><code>Session</code></a> | -| `session.unrevert({ path })` | Restaurer les messages annulés | Renvoie <a href={typesUrl}><code>Session</code></a> | -| `postSessionByIdPermissionsByPermissionId({ path, body })` | Répondre à une demande d'autorisation | Renvoie `boolean` | +| Méthode | Descriptif | Remarques | +| ---------------------------------------------------------- | ------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `session.list()` | Liste des séances | Renvoie <a href={typesUrl}><code>Session[]</code></a> | +| `session.get({ path })` | Obtenir une session | Renvoie <a href={typesUrl}><code>Session</code></a> | +| `session.children({ path })` | Liste des sessions enfants | Renvoie <a href={typesUrl}><code>Session[]</code></a> | +| `session.create({ body })` | Créer une séance | Renvoie <a href={typesUrl}><code>Session</code></a> | +| `session.delete({ path })` | Supprimer la séance | Renvoie `boolean` | +| `session.update({ path, body })` | Mettre à jour les propriétés de la session | Renvoie <a href={typesUrl}><code>Session</code></a> | +| `session.init({ path, body })` | Analysez l'application et créez `AGENTS.md` | Renvoie `boolean` | +| `session.abort({ path })` | Abandonner une session en cours | Renvoie `boolean` | +| `session.share({ path })` | Séance de partage | Renvoie <a href={typesUrl}><code>Session</code></a> | +| `session.unshare({ path })` | Annuler le partage de la session | Renvoie <a href={typesUrl}><code>Session</code></a> | +| `session.summarize({ path, body })` | Résumer la séance | Renvoie `boolean` | +| `session.messages({ path })` | Liste des messages dans une session | Renvoie `{ info: `<a href={typesUrl}><code>Message</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}[]` | +| `session.message({ path })` | Obtenir les détails du message | Renvoie `{ info: `<a href={typesUrl}><code>Message</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}` | +| `session.prompt({ path, body })` | Envoyer un message d'invite | `body.noReply: true` renvoie UserMessage (contexte uniquement). La valeur par défaut renvoie <a href={typesUrl}><code>AssistantMessage</code></a> avec réponse IA. Prend en charge `body.outputFormat` pour [sortie structurée](#structured-output) | +| `session.command({ path, body })` | Envoyer la commande à la session | Renvoie `{ info: `<a href={typesUrl}><code>AssistantMessage</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}` | +| `session.shell({ path, body })` | Exécuter une commande shell | Renvoie <a href={typesUrl}><code>AssistantMessage</code></a> | +| `session.revert({ path, body })` | Rétablir un message | Renvoie <a href={typesUrl}><code>Session</code></a> | +| `session.unrevert({ path })` | Restaurer les messages annulés | Renvoie <a href={typesUrl}><code>Session</code></a> | +| `postSessionByIdPermissionsByPermissionId({ path, body })` | Répondre à une demande d'autorisation | Renvoie `boolean` | --- diff --git a/packages/web/src/content/docs/fr/share.mdx b/packages/web/src/content/docs/fr/share.mdx index acc7c03f83..e6b067a8c8 100644 --- a/packages/web/src/content/docs/fr/share.mdx +++ b/packages/web/src/content/docs/fr/share.mdx @@ -41,7 +41,7 @@ Pour définir explicitement le mode manuel dans votre [fichier de configuration] ```json title="opencode.json" { - "$schema": "https://opncd.ai/config.json", + "$schema": "https://opencode.ai/config.json", "share": "manual" } ``` @@ -54,7 +54,7 @@ Vous pouvez activer le partage automatique pour toutes les nouvelles conversatio ```json title="opencode.json" { - "$schema": "https://opncd.ai/config.json", + "$schema": "https://opencode.ai/config.json", "share": "auto" } ``` @@ -69,7 +69,7 @@ Vous pouvez désactiver entièrement le partage en définissant l'option `share` ```json title="opencode.json" { - "$schema": "https://opncd.ai/config.json", + "$schema": "https://opencode.ai/config.json", "share": "disabled" } ``` diff --git a/packages/web/src/content/docs/fr/themes.mdx b/packages/web/src/content/docs/fr/themes.mdx index d17f2169c7..696e56d59c 100644 --- a/packages/web/src/content/docs/fr/themes.mdx +++ b/packages/web/src/content/docs/fr/themes.mdx @@ -61,11 +61,11 @@ Le thème système est destiné aux utilisateurs qui : ## Utiliser un thème -Vous pouvez sélectionner un thème en affichant la sélection de thème avec la commande `/theme`. Ou vous pouvez le spécifier dans votre [config](/docs/config). +Vous pouvez sélectionner un thème en affichant la sélection de thème avec la commande `/theme`. Ou vous pouvez le spécifier dans `tui.json`. -```json title="opencode.json" {3} +```json title="tui.json" {3} { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "theme": "tokyonight" } ``` diff --git a/packages/web/src/content/docs/fr/tui.mdx b/packages/web/src/content/docs/fr/tui.mdx index f9078508dd..8129eb2012 100644 --- a/packages/web/src/content/docs/fr/tui.mdx +++ b/packages/web/src/content/docs/fr/tui.mdx @@ -355,24 +355,34 @@ Certains éditeurs ont besoin d'arguments de ligne de commande pour s'exécuter ## Configurer -Vous pouvez personnaliser le comportement de TUI via votre fichier de configuration OpenCode. +Vous pouvez personnaliser le comportement de TUI via `tui.json` (ou `tui.jsonc`). -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", - "tui": { - "scroll_speed": 3, - "scroll_acceleration": { - "enabled": true - } - } + "$schema": "https://opencode.ai/tui.json", + "theme": "opencode", + "keybinds": { + "leader": "ctrl+x" + }, + "scroll_speed": 3, + "scroll_acceleration": { + "enabled": true + }, + "diff_style": "auto" } ``` +Ceci est séparé de `opencode.json`, qui configure le comportement du serveur/d'exécution. + ### Options -- `scroll_acceleration` - Activez l'accélération de défilement de style macOS pour un défilement fluide et naturel. Lorsqu'elle est activée, la vitesse de défilement augmente avec les gestes de défilement rapides et reste précise pour les mouvements plus lents. **Ce paramètre est prioritaire sur `scroll_speed` et le remplace lorsqu'il est activé.** -- `scroll_speed` - Contrôle la vitesse de défilement du TUI lors de l'utilisation des commandes de défilement (minimum : `1`). La valeur par défaut est `3`. **Remarque : Ceci est ignoré si `scroll_acceleration.enabled` est défini sur `true`.** +- `theme` - Définit votre thème d'interface utilisateur. [En savoir plus](/docs/themes). +- `keybinds` - Personnalise les raccourcis clavier. [En savoir plus](/docs/keybinds). +- `scroll_acceleration.enabled` - Activez l'accélération de défilement de style macOS pour un défilement fluide et naturel. Lorsqu'elle est activée, la vitesse de défilement augmente avec les gestes de défilement rapides et reste précise pour les mouvements plus lents. **Ce paramètre est prioritaire sur `scroll_speed` et le remplace lorsqu'il est activé.** +- `scroll_speed` - Contrôle la vitesse de défilement du TUI lors de l'utilisation des commandes de défilement (minimum : `0.001`, prend en charge les valeurs décimales). La valeur par défaut est `3`. **Remarque : Ceci est ignoré si `scroll_acceleration.enabled` est défini sur `true`.** +- `diff_style` - Contrôle le rendu différentiel. `"auto"` s'adapte à la largeur du terminal, `"stacked"` affiche toujours une seule colonne. + +Utilisez `OPENCODE_TUI_CONFIG` pour charger un chemin de configuration TUI personnalisé. --- diff --git a/packages/web/src/content/docs/fr/zen.mdx b/packages/web/src/content/docs/fr/zen.mdx index c69f2632f6..7310922aea 100644 --- a/packages/web/src/content/docs/fr/zen.mdx +++ b/packages/web/src/content/docs/fr/zen.mdx @@ -13,33 +13,25 @@ OpenCode Zen est une liste de modèles testés et vérifiés fournie par l'équi OpenCode Zen est actuellement en version bêta. ::: -Zen fonctionne comme n'importe quel autre fournisseur dans OpenCode. Vous vous connectez à OpenCode Zen et obtenez -votre clé API. C'est **complètement facultatif** et vous n'avez pas besoin de l'utiliser pour l'utiliser -OpenCode. +Zen fonctionne comme n'importe quel autre fournisseur dans OpenCode. Vous vous connectez à OpenCode Zen et obtenez votre clé API. C'est **complètement facultatif** et vous n'avez pas besoin de l'utiliser pour utiliser OpenCode. --- ## Arrière-plan -Il existe un grand nombre de modèles, mais seulement quelques-uns d'entre eux -ces modèles fonctionnent bien comme agents de codage. De plus, la plupart des fournisseurs sont -configuré très différemment; vous obtenez donc des performances et une qualité très différentes. +Il existe un grand nombre de modèles, mais seulement quelques-uns d'entre eux fonctionnent bien comme agents de codage. De plus, la plupart des fournisseurs sont configurés très différemment; vous obtenez donc des performances et une qualité très différentes. :::tip Nous avons testé un groupe sélectionné de modèles et de fournisseurs qui fonctionnent bien avec OpenCode. ::: -Donc, si vous utilisez un modèle via quelque chose comme OpenRouter, vous ne pourrez jamais être -assurez-vous que vous obtenez la meilleure version du modèle que vous souhaitez. +Donc, si vous utilisez un modèle via quelque chose comme OpenRouter, vous ne pourrez jamais être sûr que vous obtenez la meilleure version du modèle que vous souhaitez. -Pour résoudre ce problème, nous avons effectué plusieurs opérations : +Pour résoudre ce problème, nous avons effectué plusieurs opérations : -1. Nous avons testé un groupe sélectionné de modèles et discuté avec leurs équipes de la manière de - mieux vaut les exécuter. -2. Nous avons ensuite travaillé avec quelques prestataires pour nous assurer qu'ils étaient servis. - correctement. -3. Enfin, nous avons comparé la combinaison modèle/fournisseur et sommes arrivés - avec une liste que nous nous ferons un plaisir de recommander. +1. Nous avons testé un groupe sélectionné de modèles et discuté avec leurs équipes de la manière de mieux les exécuter. +2. Nous avons ensuite travaillé avec quelques prestataires pour nous assurer qu'ils étaient servis correctement. +3. Enfin, nous avons comparé la combinaison modèle/fournisseur et sommes arrivés avec une liste que nous nous ferons un plaisir de recommander. OpenCode Zen est une passerelle IA qui vous donne accès à ces modèles. @@ -49,8 +41,7 @@ OpenCode Zen est une passerelle IA qui vous donne accès à ces modèles. OpenCode Zen fonctionne comme n'importe quel autre fournisseur dans OpenCode. -1. Vous vous connectez à **<a href={console}>OpenCode Zen</a>**, ajoutez votre facturation - détails et copiez votre clé API. +1. Vous vous connectez à **<a href={console}>OpenCode Zen</a>**, ajoutez vos informations de facturation et copiez votre clé API. 2. Vous exécutez la commande `/connect` dans le TUI, sélectionnez OpenCode Zen et collez votre clé API. 3. Exécutez `/models` dans le TUI pour voir la liste des modèles que nous recommandons. @@ -64,6 +55,8 @@ Vous pouvez également accéder à nos modèles via les points de terminaison AP | Modèle | ID du modèle | Point de terminaison | Package SDK IA | | ------------------ | ------------------ | -------------------------------------------------- | --------------------------- | +| GPT 5.4 | gpt-5.4 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| GPT 5.3 Codex | gpt-5.3-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.2 | gpt-5.2 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.2 Codex | gpt-5.2-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.1 | gpt-5.1 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | @@ -73,36 +66,36 @@ Vous pouvez également accéder à nos modèles via les points de terminaison AP | GPT 5 | gpt-5 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5 Codex | gpt-5-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5 Nano | gpt-5-nano | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| Claude Opus 4.6 | claude-opus-4-6 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Opus 4.5 | claude-opus-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Opus 4.1 | claude-opus-4-1 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Sonnet 4.6 | claude-sonnet-4-6 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Sonnet 4.5 | claude-sonnet-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Sonnet 4 | claude-sonnet-4 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Haiku 4.5 | claude-haiku-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Haiku 3.5 | claude-3-5-haiku | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| Claude Opus 4.6 | claude-opus-4-6 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| Claude Opus 4.5 | claude-opus-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| Claude Opus 4.1 | claude-opus-4-1 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Gemini 3.1 Pro | gemini-3.1-pro | `https://opencode.ai/zen/v1/models/gemini-3.1-pro` | `@ai-sdk/google` | | Gemini 3 Pro | gemini-3-pro | `https://opencode.ai/zen/v1/models/gemini-3-pro` | `@ai-sdk/google` | | Gemini 3 Flash | gemini-3-flash | `https://opencode.ai/zen/v1/models/gemini-3-flash` | `@ai-sdk/google` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.5 Free | minimax-m2.5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.1 | minimax-m2.1 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.1 Free | minimax-m2.1-free | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| GLM 5 | glm-5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | GLM 4.7 | glm-4.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM 4.7 Free | glm-4.7-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | GLM 4.6 | glm-4.6 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 Free | kimi-k2.5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2 Thinking | kimi-k2-thinking | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2 | kimi-k2 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Qwen3 Coder 480B | qwen3-coder | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Big Pickle | big-pickle | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -Le [id du modèle](/docs/config/#models) dans votre configuration OpenCode -utilise le format `opencode/<model-id>`. Par exemple, pour GPT 5.2 Codex, vous devez -utilisez `opencode/gpt-5.2-codex` dans votre configuration. +Le [id du modèle](/docs/config/#models) dans votre configuration OpenCode utilise le format `opencode/<model-id>`. Par exemple, pour GPT 5.2 Codex, vous devez utilisez `opencode/gpt-5.2-codex` dans votre configuration. --- ### Modèles -Vous pouvez récupérer la liste complète des modèles disponibles et leurs métadonnées à partir de : +Vous pouvez récupérer la liste complète des modèles disponibles et leurs métadonnées à partir de : ``` https://opencode.ai/zen/v1/models @@ -117,29 +110,35 @@ Nous soutenons un modèle de paiement à l'utilisation. Vous trouverez ci-dessou | Modèle | Entrée | Sortie | Lecture en cache | Écriture en cache | | --------------------------------- | ------- | ------- | ---------------- | ----------------- | | Big Pickle | Gratuit | Gratuit | Gratuit | - | -| MiniMax M2.1 Free | Gratuit | Gratuit | Gratuit | - | +| MiniMax M2.5 Free | Gratuit | Gratuit | Gratuit | - | +| MiniMax M2.5 | 0,30 $ | 1,20 $ | 0,06 $ | - | | MiniMax M2.1 | 0,30 $ | 1,20 $ | 0,10 $ | - | -| GLM 4.7 Free | Gratuit | Gratuit | Gratuit | - | +| GLM 5 | 1,00 $ | 3,20 $ | 0,20 $ | - | | GLM 4.7 | 0,60 $ | 2,20 $ | 0,10 $ | - | | GLM 4.6 | 0,60 $ | 2,20 $ | 0,10 $ | - | -| Kimi K2.5 Free | Gratuit | Gratuit | Gratuit | - | | Kimi K2.5 | 0,60 $ | 3,00 $ | 0,08 $ | - | | Kimi K2 Thinking | 0,40 $ | 2,50 $ | - | - | | Kimi K2 | 0,40 $ | 2,50 $ | - | - | | Qwen3 Coder 480B | 0,45 $ | 1,50 $ | - | - | +| Claude Opus 4.6 (≤ 200K jetons) | 5,00 $ | 25,00 $ | 0,50 $ | 6,25 $ | +| Claude Opus 4.6 (> 200K jetons) | 10,00 $ | 37,50 $ | 1,00 $ | 12,50 $ | +| Claude Opus 4.5 | 5,00 $ | 25,00 $ | 0,50 $ | 6,25 $ | +| Claude Opus 4.1 | 15,00 $ | 75,00 $ | 1,50 $ | 18,75 $ | +| Claude Sonnet 4.6 (≤ 200K jetons) | 3,00 $ | 15,00 $ | 0,30 $ | 3,75 $ | +| Claude Sonnet 4.6 (> 200K jetons) | 6,00 $ | 22,50 $ | 0,60 $ | 7,50 $ | | Claude Sonnet 4.5 (≤ 200K jetons) | 3,00 $ | 15,00 $ | 0,30 $ | 3,75 $ | | Claude Sonnet 4.5 (> 200K jetons) | 6,00 $ | 22,50 $ | 0,60 $ | 7,50 $ | | Claude Sonnet 4 (≤ 200K jetons) | 3,00 $ | 15,00 $ | 0,30 $ | 3,75 $ | | Claude Sonnet 4 (> 200K jetons) | 6,00 $ | 22,50 $ | 0,60 $ | 7,50 $ | | Claude Haiku 4.5 | 1,00 $ | 5,00 $ | 0,10 $ | 1,25 $ | | Claude Haiku 3.5 | 0,80 $ | 4,00 $ | 0,08 $ | 1,00 $ | -| Claude Opus 4.6 (≤ 200K jetons) | 5,00 $ | 25,00 $ | 0,50 $ | 6,25 $ | -| Claude Opus 4.6 (> 200K jetons) | 10,00 $ | 37,50 $ | 1,00 $ | 12,50 $ | -| Claude Opus 4.5 | 5,00 $ | 25,00 $ | 0,50 $ | 6,25 $ | -| Claude Opus 4.1 | 15,00 $ | 75,00 $ | 1,50 $ | 18,75 $ | -| Gemini 3 Pro (≤ 200 000 jetons) | 2,00 $ | 12,00 $ | 0,20 $ | - | -| Gemini 3 Pro (> 200 000 jetons) | 4,00 $ | 18,00 $ | 0,40 $ | - | +| Gemini 3.1 Pro (≤ 200K jetons) | 2,00 $ | 12,00 $ | 0,20 $ | - | +| Gemini 3.1 Pro (> 200K jetons) | 4,00 $ | 18,00 $ | 0,40 $ | - | +| Gemini 3 Pro (≤ 200K jetons) | 2,00 $ | 12,00 $ | 0,20 $ | - | +| Gemini 3 Pro (> 200K jetons) | 4,00 $ | 18,00 $ | 0,40 $ | - | | Gemini 3 Flash | 0,50 $ | 3,00 $ | 0,05 $ | - | +| GPT 5.4 | 2,50 $ | 15,00 $ | 0,25 $ | - | +| GPT 5.3 Codex | 1,75 $ | 14,00 $ | 0,175 $ | - | | GPT 5.2 | 1,75 $ | 14,00 $ | 0,175 $ | - | | GPT 5.2 Codex | 1,75 $ | 14,00 $ | 0,175 $ | - | | GPT 5.1 | 1,07 $ | 8,50 $ | 0,107 $ | - | @@ -158,9 +157,7 @@ Les frais de carte de crédit sont répercutés au prix coûtant (4,4 % + 0,30 $ Les modèles gratuits : -- GLM 4.7 Free est disponible sur OpenCode pour une durée limitée. L’équipe profite de ce temps pour recueillir des commentaires et améliorer le modèle. -- Kimi K2.5 Free est disponible sur OpenCode pour une durée limitée. L’équipe profite de ce temps pour recueillir des commentaires et améliorer le modèle. -- MiniMax M2.1 Free est disponible sur OpenCode pour une durée limitée. L’équipe profite de ce temps pour recueillir des commentaires et améliorer le modèle. +- MiniMax M2.5 Free est disponible sur OpenCode pour une durée limitée. L’équipe profite de ce temps pour recueillir des commentaires et améliorer le modèle. - Big Pickle est un modèle furtif gratuit sur OpenCode pour une durée limitée. L’équipe profite de ce temps pour recueillir des commentaires et améliorer le modèle. <a href={email}>Contactez-nous</a> si vous avez des questions. @@ -177,48 +174,54 @@ Vous pouvez modifier le montant du rechargement automatique. Vous pouvez égalem ### Limites mensuelles -Vous pouvez également définir une limite d'utilisation mensuelle pour l'ensemble de l'espace de travail et pour chaque -membre de votre équipe. +Vous pouvez également définir une limite d'utilisation mensuelle pour l'ensemble de l'espace de travail et pour chaque membre de votre équipe. -Par exemple, disons que vous définissez une limite d'utilisation mensuelle à 20 $, Zen n'utilisera pas -plus de 20 $ par mois. Mais si le rechargement automatique est activé, Zen pourrait finir par -vous facturant plus de 20 $ si votre solde descend en dessous de 5 $. +Par exemple, disons que vous définissez une limite d'utilisation mensuelle à 20 $, Zen n'utilisera pas plus de 20 $ par mois. Mais si le rechargement automatique est activé, Zen pourrait finir par vous facturant plus de 20 $ si votre solde descend en dessous de 5 $. + +--- + +### Modèles obsolètes + +| Modèle | Date de dépréciation | +| ---------------- | -------------------- | +| Qwen3 Coder 480B | 6 février 2026 | +| Kimi K2 Thinking | 6 mars 2026 | +| Kimi K2 | 6 mars 2026 | +| MiniMax M2.1 | 15 mars 2026 | +| GLM 4.7 | 15 mars 2026 | +| GLM 4.6 | 15 mars 2026 | --- ## Confidentialité -Tous nos modèles sont hébergés aux États-Unis. Nos fournisseurs suivent une politique de rétention zéro et n'utilisent pas vos données pour la formation de modèles, avec les exceptions suivantes : +Tous nos modèles sont hébergés aux États-Unis. Nos fournisseurs suivent une politique de rétention zéro et n'utilisent pas vos données pour la formation de modèles, avec les exceptions suivantes : - Big Pickle : Pendant sa période gratuite, les données collectées peuvent être utilisées pour améliorer le modèle. -- GLM 4.7 Gratuit : Pendant sa période gratuite, les données collectées peuvent être utilisées pour améliorer le modèle. -- Kimi K2.5 Gratuit : Pendant sa période gratuite, les données collectées peuvent être utilisées pour améliorer le modèle. -- MiniMax M2.1 Gratuit : Pendant sa période gratuite, les données collectées peuvent être utilisées pour améliorer le modèle. -- API OpenAI : les demandes sont conservées pendant 30 jours conformément aux politiques de données de [OpenAI](https://platform.openai.com/docs/guides/your-data). -- API Anthropic : les demandes sont conservées pendant 30 jours conformément aux [Politiques de données d'Anthropic](https://docs.anthropic.com/en/docs/claude-code/data-usage). +- MiniMax M2.5 Free : Pendant sa période gratuite, les données collectées peuvent être utilisées pour améliorer le modèle. +- API OpenAI : Les demandes sont conservées pendant 30 jours conformément aux politiques de données de [OpenAI](https://platform.openai.com/docs/guides/your-data). +- API Anthropic : Les demandes sont conservées pendant 30 jours conformément aux [Politiques de données d'Anthropic](https://docs.anthropic.com/en/docs/claude-code/data-usage). --- ## Pour les équipes -Zen fonctionne également très bien pour les équipes. Vous pouvez inviter des coéquipiers, attribuer des rôles, organiser -les modèles utilisés par votre équipe, et bien plus encore. +Zen fonctionne également très bien pour les équipes. Vous pouvez inviter des coéquipiers, attribuer des rôles, organiser les modèles utilisés par votre équipe, et bien plus encore. :::note Les espaces de travail sont actuellement gratuits pour les équipes dans le cadre de la version bêta. ::: -La gestion de votre espace de travail est actuellement gratuite pour les équipes dans le cadre de la version bêta. Nous serons -partagera bientôt plus de détails sur les prix. +La gestion de votre espace de travail est actuellement gratuite pour les équipes dans le cadre de la version bêta. Nous partagerons bientôt plus de détails sur les prix. --- ### Rôles -Vous pouvez inviter des coéquipiers dans votre espace de travail et attribuer des rôles : +Vous pouvez inviter des coéquipiers dans votre espace de travail et attribuer des rôles : -- **Administrateur** : gérez les modèles, les membres, les clés API et la facturation. -- **Membre** : gérer uniquement ses propres clés API +- **Administrateur** : gérez les modèles, les membres, les clés API et la facturation. +- **Membre** : gérer uniquement ses propres clés API Les administrateurs peuvent également définir des limites de dépenses mensuelles pour chaque membre afin de garder les coûts sous contrôle. @@ -228,8 +231,7 @@ Les administrateurs peuvent également définir des limites de dépenses mensuel Les administrateurs peuvent activer ou désactiver des modèles spécifiques pour l'espace de travail. Les requêtes adressées à un modèle désactivé renverront une erreur. -Ceci est utile dans les cas où vous souhaitez désactiver l'utilisation d'un modèle qui -collecte des données. +Ceci est utile dans les cas où vous souhaitez désactiver l'utilisation d'un modèle qui collecte des données. --- @@ -239,8 +241,7 @@ Vous pouvez utiliser vos propres clés OpenAI ou Anthropic API tout en accédant Lorsque vous utilisez vos propres clés, les tokens sont facturés directement par le fournisseur et non par Zen. -Par exemple, votre organisation dispose peut-être déjà d'une clé pour OpenAI ou Anthropic -et vous souhaitez l'utiliser à la place de celui fourni par Zen. +Par exemple, votre organisation dispose peut-être déjà d'une clé pour OpenAI ou Anthropic et vous souhaitez l'utiliser à la place de celui fourni par Zen. --- @@ -250,5 +251,5 @@ Nous avons créé OpenCode Zen pour : 1. **Benchmark** les meilleurs modèles/fournisseurs d'agents de codage. 2. Ayez accès aux options de **la plus haute qualité** et ne dégradez pas les performances ni ne vous dirigez vers des fournisseurs moins chers. -3. Répercutez toute **baisse de prix** en vendant au prix coûtant ; la seule majoration est donc pour couvrir nos frais de traitement. +3. Répercutez toute **baisse de prix** en vendant au prix coûtant ; la seule majoration est donc pour couvrir nos frais de traitement. 4. N'ayez **aucun verrouillage** en vous permettant de l'utiliser avec n'importe quel autre agent de codage. Et laissez-vous toujours utiliser n'importe quel autre fournisseur avec OpenCode également. diff --git a/packages/web/src/content/docs/go.mdx b/packages/web/src/content/docs/go.mdx new file mode 100644 index 0000000000..5976f1a358 --- /dev/null +++ b/packages/web/src/content/docs/go.mdx @@ -0,0 +1,147 @@ +--- +title: Go +description: Low cost subscription for open coding models. +--- + +import config from "../../../config.mjs" +export const console = config.console +export const email = `mailto:${config.email}` + +OpenCode Go is a low cost **$10/month** subscription that gives you reliable access to popular open coding models. + +:::note +OpenCode Go is currently in beta. +::: + +Go works like any other provider in OpenCode. You subscribe to OpenCode Go and +get your API key. It's **completely optional** and you don't need to use it to +use OpenCode. + +It is designed primarily for international users, with models hosted in the US, EU, and Singapore for stable global access. + +--- + +## Background + +Open models have gotten really good. They now reach performance close to +proprietary models for coding tasks. And because many providers can serve them +competitively, they are usually far cheaper. + +However, getting reliable, low latency access to them can be difficult. Providers +vary in quality and availability. + +:::tip +We tested a select group of models and providers that work well with OpenCode. +::: + +To fix this, we did a couple of things: + +1. We tested a select group of open models and talked to their teams about how to + best run them. +2. We then worked with a few providers to make sure these were being served + correctly. +3. Finally, we benchmarked the combination of the model/provider and came up + with a list that we feel good recommending. + +OpenCode Go gives you access to these models for **$10/month**. + +--- + +## How it works + +OpenCode Go works like any other provider in OpenCode. + +1. You sign in to **<a href={console}>OpenCode Zen</a>**, subscribe to Go, and + copy your API key. +2. You run the `/connect` command in the TUI, select `OpenCode Go`, and paste + your API key. +3. Run `/models` in the TUI to see the list of models available through Go. + +:::note +Only one member per workspace can subscribe to OpenCode Go. +::: + +The current list of models includes: + +- **GLM-5** +- **Kimi K2.5** +- **MiniMax M2.5** + +The list of models may change as we test and add new ones. + +--- + +## Usage limits + +OpenCode Go includes the following limits: + +- **5 hour limit** — $12 of usage +- **Weekly limit** — $30 of usage +- **Monthly limit** — $60 of usage + +Limits are defined in dollar value. This means your actual request count depends on the model you use. Cheaper models like MiniMax M2.5 allow for more requests, while higher-cost models like GLM-5 allow for fewer. + +The table below provides an estimated request count based on typical Go usage patterns: + +| | GLM-5 | Kimi K2.5 | MiniMax M2.5 | +| ------------------- | ----- | --------- | ------------ | +| requests per 5 hour | 1,150 | 1,850 | 20,000 | +| requests per week | 2,880 | 4,630 | 50,000 | +| requests per month | 5,750 | 9,250 | 100,000 | + +Estimates are based on observed average request patterns: + +- GLM-5 — 700 input, 52,000 cached, 150 output tokens per request +- Kimi K2.5 — 870 input, 55,000 cached, 200 output tokens per request +- MiniMax M2.5 — 300 input, 55,000 cached, 125 output tokens per request + +You can track your current usage in the **<a href={console}>console</a>**. + +:::tip +If you reach the usage limit, you can continue using the free models. +::: + +Usage limits may change as we learn from early usage and feedback. + +--- + +### Usage beyond limits + +If you also have credits on your Zen balance, you can enable the **Use balance** +option in the console. When enabled, Go will fall back to your Zen balance +after you've reached your usage limits instead of blocking requests. + +--- + +## Endpoints + +You can also access Go models through the following API endpoints. + +| Model | Model ID | Endpoint | AI SDK Package | +| ------------ | ------------ | ------------------------------------------------ | --------------------------- | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | + +The [model id](/docs/config/#models) in your OpenCode config +uses the format `opencode-go/<model-id>`. For example, for Kimi K2.5, you would +use `opencode-go/kimi-k2.5` in your config. + +--- + +## Privacy + +The plan is designed primarily for international users, with models hosted in the US, EU, and Singapore for stable global access. + +<a href={email}>Contact us</a> if you have any questions. + +--- + +## Goals + +We created OpenCode Go to: + +1. Make AI coding **accessible** to more people with a low cost subscription. +2. Provide **reliable** access to the best open coding models. +3. Curate models that are **tested and benchmarked** for coding agent use. +4. Have **no lock-in** by allowing you to use any other provider with OpenCode as well. diff --git a/packages/web/src/content/docs/it/cli.mdx b/packages/web/src/content/docs/it/cli.mdx index a97bbde1c9..b35292a0a5 100644 --- a/packages/web/src/content/docs/it/cli.mdx +++ b/packages/web/src/content/docs/it/cli.mdx @@ -558,6 +558,7 @@ OpenCode può essere configurato tramite variabili d'ambiente. | `OPENCODE_AUTO_SHARE` | boolean | Condivide automaticamente le sessioni | | `OPENCODE_GIT_BASH_PATH` | string | Percorso all'eseguibile Git Bash su Windows | | `OPENCODE_CONFIG` | string | Percorso al file di configurazione | +| `OPENCODE_TUI_CONFIG` | string | Percorso al file di configurazione TUI | | `OPENCODE_CONFIG_DIR` | string | Percorso alla directory di configurazione | | `OPENCODE_CONFIG_CONTENT` | string | Contenuto JSON di config inline | | `OPENCODE_DISABLE_AUTOUPDATE` | boolean | Disabilita i controlli automatici di aggiornamento | diff --git a/packages/web/src/content/docs/it/config.mdx b/packages/web/src/content/docs/it/config.mdx index c94cc59a9b..05741e172e 100644 --- a/packages/web/src/content/docs/it/config.mdx +++ b/packages/web/src/content/docs/it/config.mdx @@ -14,10 +14,11 @@ OpenCode supporta sia **JSON** sia **JSONC** (JSON con commenti). ```jsonc title="opencode.jsonc" { "$schema": "https://opencode.ai/config.json", - // Theme configuration - "theme": "opencode", "model": "anthropic/claude-sonnet-4-5", "autoupdate": true, + "server": { + "port": 4096, + }, } ``` @@ -33,7 +34,7 @@ I file di configurazione vengono **uniti (merge)**, non sostituiti. I file di configurazione vengono uniti (merge), non sostituiti. Le impostazioni provenienti dalle posizioni qui sotto vengono combinate. Le configurazioni caricate dopo sovrascrivono quelle precedenti solo per le chiavi in conflitto. Le impostazioni non in conflitto vengono preservate. -Per esempio, se la tua configurazione globale imposta `theme: "opencode"` e `autoupdate: true`, e la configurazione del progetto imposta `model: "anthropic/claude-sonnet-4-5"`, la configurazione finale includera tutte e tre le impostazioni. +Per esempio, se la tua configurazione globale imposta `autoupdate: true` e la configurazione del progetto imposta `model: "anthropic/claude-sonnet-4-5"`, la configurazione finale includera entrambe le impostazioni. --- @@ -94,7 +95,9 @@ Puoi abilitare server specifici nella tua configurazione locale: ### Configurazione globale -Metti la configurazione globale di OpenCode in `~/.config/opencode/opencode.json`. Usa la configurazione globale per preferenze valide per l'utente (ad es. temi, provider o keybind). +Metti la configurazione globale di OpenCode in `~/.config/opencode/opencode.json`. Usa la configurazione globale per preferenze server/runtime valide per l'utente come provider, modelli e permessi. + +Per le impostazioni specifiche della TUI, usa `~/.config/opencode/tui.json`. La configurazione globale sovrascrive i default remoti dell'organizzazione. @@ -104,6 +107,8 @@ La configurazione globale sovrascrive i default remoti dell'organizzazione. Aggiungi `opencode.json` nella root del progetto. La configurazione di progetto ha la precedenza piu alta tra i file standard: sovrascrive sia la configurazione globale sia quella remota. +Per le impostazioni TUI specifiche del progetto, aggiungi `tui.json` nella stessa posizione. + :::tip Metti la configurazione specifica del progetto nella root del progetto. ::: @@ -144,34 +149,32 @@ La directory personalizzata viene caricata dopo la configurazione globale e le d Il file di configurazione ha uno schema definito in [**`opencode.ai/config.json`**](https://opencode.ai/config.json). +La configurazione TUI usa [**`opencode.ai/tui.json`**](https://opencode.ai/tui.json). + Il tuo editor dovrebbe poter validare e suggerire l'autocompletamento in base allo schema. --- ### TUI -Puoi configurare impostazioni specifiche della TUI tramite l'opzione `tui`. +Usa un file dedicato `tui.json` (o `tui.jsonc`) per le impostazioni specifiche della TUI. -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", - "tui": { - "scroll_speed": 3, - "scroll_acceleration": { - "enabled": true - }, - "diff_style": "auto" - } + "$schema": "https://opencode.ai/tui.json", + "scroll_speed": 3, + "scroll_acceleration": { + "enabled": true + }, + "diff_style": "auto" } ``` -Opzioni disponibili: +Usa `OPENCODE_TUI_CONFIG` per puntare a un file di configurazione TUI personalizzato. -- `scroll_acceleration.enabled` - Abilita l'accelerazione di scorrimento in stile macOS. **Ha precedenza su `scroll_speed`.** -- `scroll_speed` - Moltiplicatore personalizzato della velocita di scorrimento (predefinito: `3`, minimo: `1`). Ignorato se `scroll_acceleration.enabled` e `true`. -- `diff_style` - Controlla la resa delle diff. `"auto"` si adatta alla larghezza del terminale, `"stacked"` mostra sempre una singola colonna. +Le chiavi legacy `theme`, `keybinds` e `tui` in `opencode.json` sono deprecate e vengono migrate automaticamente quando possibile. -[Scopri di piu sull'uso della TUI](/docs/tui). +[Scopri di piu sulla configurazione TUI](/docs/tui#configure). --- @@ -297,12 +300,12 @@ I bearer token (`AWS_BEARER_TOKEN_BEDROCK` o `/connect`) hanno precedenza sull'a ### Temi -Puoi configurare il tema da usare in OpenCode tramite l'opzione `theme`. +Imposta il tuo tema UI in `tui.json`. -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", - "theme": "" + "$schema": "https://opencode.ai/tui.json", + "theme": "tokyonight" } ``` @@ -402,11 +405,11 @@ Puoi anche definire comandi usando file markdown in `~/.config/opencode/commands ### Scorciatoie -Puoi personalizzare i keybind tramite l'opzione `keybinds`. +Personalizza i keybind in `tui.json`. -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "keybinds": {} } ``` @@ -486,13 +489,15 @@ Puoi controllare il comportamento di compattazione del contesto tramite l'opzion "$schema": "https://opencode.ai/config.json", "compaction": { "auto": true, - "prune": true + "prune": true, + "reserved": 10000 } } ``` - `auto` - Compatta automaticamente la sessione quando il contesto e pieno (predefinito: `true`). - `prune` - Rimuove output vecchi degli strumenti per risparmiare token (predefinito: `true`). +- `reserved` - Token buffer per la compattazione. Lascia abbastanza margine per evitare overflow durante la compattazione --- diff --git a/packages/web/src/content/docs/it/custom-tools.mdx b/packages/web/src/content/docs/it/custom-tools.mdx index 43f69c43c6..a0ef1c46c2 100644 --- a/packages/web/src/content/docs/it/custom-tools.mdx +++ b/packages/web/src/content/docs/it/custom-tools.mdx @@ -79,6 +79,32 @@ Questo crea due strumenti: `math_add` e `math_multiply`. --- +#### Collisioni di nomi con strumenti integrati + +Gli strumenti personalizzati sono indicizzati per nome. Se uno strumento personalizzato usa lo stesso nome di uno strumento integrato, quello personalizzato ha la precedenza. + +Per esempio, questo file sostituisce lo strumento `bash` integrato: + +```ts title=".opencode/tools/bash.ts" +import { tool } from "@opencode-ai/plugin" + +export default tool({ + description: "Restricted bash wrapper", + args: { + command: tool.schema.string(), + }, + async execute(args) { + return `blocked: ${args.command}` + }, +}) +``` + +:::note +Preferisci nomi univoci a meno che tu non voglia intenzionalmente sostituire uno strumento integrato. Se vuoi disabilitare uno strumento integrato ma non sovrascriverlo, usa i [permessi](/docs/permissions). +::: + +--- + ### Argomenti Puoi usare `tool.schema`, che e semplicemente [Zod](https://zod.dev), per definire i tipi degli argomenti. diff --git a/packages/web/src/content/docs/it/ecosystem.mdx b/packages/web/src/content/docs/it/ecosystem.mdx index 54fcdb8dbd..d2cb9c4383 100644 --- a/packages/web/src/content/docs/it/ecosystem.mdx +++ b/packages/web/src/content/docs/it/ecosystem.mdx @@ -3,50 +3,52 @@ title: Ecosistema description: Progetti e integrazioni costruiti con OpenCode. --- -Una raccolta di progetti della comunita costruiti su OpenCode. +Una raccolta di progetti della comunità costruiti su OpenCode. :::note Vuoi aggiungere il tuo progetto legato a OpenCode a questa lista? Apri una PR. ::: -Puoi anche dare un'occhiata a [awesome-opencode](https://github.com/awesome-opencode/awesome-opencode) e [opencode.cafe](https://opencode.cafe), una comunita che aggrega ecosistema e community. +Puoi anche dare un'occhiata a [awesome-opencode](https://github.com/awesome-opencode/awesome-opencode) e [opencode.cafe](https://opencode.cafe), una comunità che aggrega ecosistema e community. --- ## Plugin -| Nome | Descrizione | -| --------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | -| [opencode-daytona](https://github.com/jamesmurdza/daytona/blob/main/guides/typescript/opencode/README.md) | Esegue automaticamente sessioni OpenCode in sandbox Daytona isolate con sync git e anteprime live | -| [opencode-helicone-session](https://github.com/H2Shami/opencode-helicone-session) | Inietta automaticamente gli header di sessione Helicone per raggruppare le richieste | -| [opencode-type-inject](https://github.com/nick-vi/opencode-type-inject) | Inietta automaticamente tipi TypeScript/Svelte nelle letture dei file con tool di lookup | -| [opencode-openai-codex-auth](https://github.com/numman-ali/opencode-openai-codex-auth) | Usa il tuo abbonamento ChatGPT Plus/Pro invece dei crediti API | -| [opencode-gemini-auth](https://github.com/jenslys/opencode-gemini-auth) | Usa il tuo piano Gemini esistente invece della fatturazione API | -| [opencode-antigravity-auth](https://github.com/NoeFabris/opencode-antigravity-auth) | Usa i modelli gratuiti di Antigravity invece della fatturazione API | -| [opencode-devcontainers](https://github.com/athal7/opencode-devcontainers) | Isolamento devcontainer multi-branch con shallow clone e porte assegnate automaticamente | -| [opencode-google-antigravity-auth](https://github.com/shekohex/opencode-google-antigravity-auth) | Plugin OAuth Google Antigravity, con supporto a Google Search e gestione API piu robusta | -| [opencode-dynamic-context-pruning](https://github.com/Tarquinen/opencode-dynamic-context-pruning) | Ottimizza l'uso dei token eliminando output obsoleti degli strumenti | -| [opencode-websearch-cited](https://github.com/ghoulr/opencode-websearch-cited.git) | Aggiunge supporto websearch nativo per provider supportati con stile grounded di Google | -| [opencode-pty](https://github.com/shekohex/opencode-pty.git) | Permette agli agenti AI di eseguire processi in background in una PTY e inviare input interattivo | -| [opencode-shell-strategy](https://github.com/JRedeker/opencode-shell-strategy) | Istruzioni per comandi shell non interattivi: evita blocchi dovuti a operazioni dipendenti da TTY | -| [opencode-wakatime](https://github.com/angristan/opencode-wakatime) | Traccia l'uso di OpenCode con Wakatime | -| [opencode-md-table-formatter](https://github.com/franlol/opencode-md-table-formatter/tree/main) | Ripulisce le tabelle markdown prodotte dai LLM | -| [opencode-morph-fast-apply](https://github.com/JRedeker/opencode-morph-fast-apply) | Editing del codice 10x piu veloce con Morph Fast Apply API e marker lazy edit | -| [oh-my-opencode](https://github.com/code-yeongyu/oh-my-opencode) | Agenti in background, tool LSP/AST/MCP predefiniti, agenti curati, compatibile con Claude Code | -| [opencode-notificator](https://github.com/panta82/opencode-notificator) | Notifiche desktop e avvisi sonori per le sessioni OpenCode | -| [opencode-notifier](https://github.com/mohak34/opencode-notifier) | Notifiche desktop e avvisi sonori per eventi di permesso, completamento ed errore | -| [opencode-zellij-namer](https://github.com/24601/opencode-zellij-namer) | Naming automatico delle sessioni Zellij basato sul contesto OpenCode | -| [opencode-skillful](https://github.com/zenobi-us/opencode-skillful) | Permette agli agenti OpenCode di caricare prompt al bisogno con discovery e injection di skill | -| [opencode-supermemory](https://github.com/supermemoryai/opencode-supermemory) | Memoria persistente tra sessioni usando Supermemory | -| [@plannotator/opencode](https://github.com/backnotprop/plannotator/tree/main/apps/opencode-plugin) | Revisione interattiva dei piani con annotazione visiva e condivisione privata/offline | -| [@openspoon/subtask2](https://github.com/spoons-and-mirrors/subtask2) | Estende opencode /commands in un sistema di orchestrazione con controllo di flusso granulare | -| [opencode-scheduler](https://github.com/different-ai/opencode-scheduler) | Pianifica job ricorrenti con launchd (Mac) o systemd (Linux) usando sintassi cron | -| [micode](https://github.com/vtemian/micode) | Workflow strutturato Brainstorm → Plan → Implement con continuita di sessione | -| [octto](https://github.com/vtemian/octto) | UI browser interattiva per brainstorming AI con moduli multi-domanda | -| [opencode-background-agents](https://github.com/kdcokenny/opencode-background-agents) | Agenti in background stile Claude Code con delega async e persistenza del contesto | -| [opencode-notify](https://github.com/kdcokenny/opencode-notify) | Notifiche native del sistema per OpenCode: sai quando i task finiscono | -| [opencode-workspace](https://github.com/kdcokenny/opencode-workspace) | Harness di orchestrazione multi-agente bundle: 16 componenti, una installazione | -| [opencode-worktree](https://github.com/kdcokenny/opencode-worktree) | Git worktree senza attriti per OpenCode | +| Nome | Descrizione | +| -------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | +| [opencode-daytona](https://github.com/daytonaio/daytona/tree/main/libs/opencode-plugin) | Esegue automaticamente sessioni OpenCode in sandbox Daytona isolate con sync git e anteprime live | +| [opencode-helicone-session](https://github.com/H2Shami/opencode-helicone-session) | Inietta automaticamente gli header di sessione Helicone per raggruppare le richieste | +| [opencode-type-inject](https://github.com/nick-vi/opencode-type-inject) | Inietta automaticamente tipi TypeScript/Svelte nelle letture dei file con tool di lookup | +| [opencode-openai-codex-auth](https://github.com/numman-ali/opencode-openai-codex-auth) | Usa il tuo abbonamento ChatGPT Plus/Pro invece dei crediti API | +| [opencode-gemini-auth](https://github.com/jenslys/opencode-gemini-auth) | Usa il tuo piano Gemini esistente invece della fatturazione API | +| [opencode-antigravity-auth](https://github.com/NoeFabris/opencode-antigravity-auth) | Usa i modelli gratuiti di Antigravity invece della fatturazione API | +| [opencode-devcontainers](https://github.com/athal7/opencode-devcontainers) | Isolamento devcontainer multi-branch con shallow clone e porte assegnate automaticamente | +| [opencode-google-antigravity-auth](https://github.com/shekohex/opencode-google-antigravity-auth) | Plugin OAuth Google Antigravity, con supporto a Google Search e gestione API più robusta | +| [opencode-dynamic-context-pruning](https://github.com/Tarquinen/opencode-dynamic-context-pruning) | Ottimizza l'uso dei token eliminando output obsoleti degli strumenti | +| [opencode-vibeguard](https://github.com/inkdust2021/opencode-vibeguard) | Oscura segreti/PII in placeholder stile VibeGuard prima delle chiamate LLM; ripristina localmente | +| [opencode-websearch-cited](https://github.com/ghoulr/opencode-websearch-cited.git) | Aggiunge supporto websearch nativo per provider supportati con stile grounded di Google | +| [opencode-pty](https://github.com/shekohex/opencode-pty.git) | Permette agli agenti AI di eseguire processi in background in una PTY e inviare input interattivo | +| [opencode-shell-strategy](https://github.com/JRedeker/opencode-shell-strategy) | Istruzioni per comandi shell non interattivi: evita blocchi dovuti a operazioni dipendenti da TTY | +| [opencode-wakatime](https://github.com/angristan/opencode-wakatime) | Traccia l'uso di OpenCode con Wakatime | +| [opencode-md-table-formatter](https://github.com/franlol/opencode-md-table-formatter/tree/main) | Ripulisce le tabelle markdown prodotte dai LLM | +| [opencode-morph-fast-apply](https://github.com/JRedeker/opencode-morph-fast-apply) | Editing del codice 10x più veloce con Morph Fast Apply API e marker lazy edit | +| [oh-my-opencode](https://github.com/code-yeongyu/oh-my-opencode) | Agenti in background, tool LSP/AST/MCP predefiniti, agenti curati, compatibile con Claude Code | +| [opencode-notificator](https://github.com/panta82/opencode-notificator) | Notifiche desktop e avvisi sonori per le sessioni OpenCode | +| [opencode-notifier](https://github.com/mohak34/opencode-notifier) | Notifiche desktop e avvisi sonori per eventi di permesso, completamento ed errore | +| [opencode-zellij-namer](https://github.com/24601/opencode-zellij-namer) | Naming automatico delle sessioni Zellij basato sul contesto OpenCode | +| [opencode-skillful](https://github.com/zenobi-us/opencode-skillful) | Permette agli agenti OpenCode di caricare prompt al bisogno con discovery e injection di skill | +| [opencode-supermemory](https://github.com/supermemoryai/opencode-supermemory) | Memoria persistente tra sessioni usando Supermemory | +| [@plannotator/opencode](https://github.com/backnotprop/plannotator/tree/main/apps/opencode-plugin) | Revisione interattiva dei piani con annotazione visiva e condivisione privata/offline | +| [@openspoon/subtask2](https://github.com/spoons-and-mirrors/subtask2) | Estende opencode /commands in un sistema di orchestrazione con controllo di flusso granulare | +| [opencode-scheduler](https://github.com/different-ai/opencode-scheduler) | Pianifica job ricorrenti con launchd (Mac) o systemd (Linux) usando sintassi cron | +| [micode](https://github.com/vtemian/micode) | Workflow strutturato Brainstorm → Plan → Implement con continuità di sessione | +| [octto](https://github.com/vtemian/octto) | UI browser interattiva per brainstorming AI con moduli multi-domanda | +| [opencode-background-agents](https://github.com/kdcokenny/opencode-background-agents) | Agenti in background stile Claude Code con delega async e persistenza del contesto | +| [opencode-notify](https://github.com/kdcokenny/opencode-notify) | Notifiche native del sistema per OpenCode: sai quando i task finiscono | +| [opencode-workspace](https://github.com/kdcokenny/opencode-workspace) | Harness di orchestrazione multi-agente bundle: 16 componenti, una installazione | +| [opencode-worktree](https://github.com/kdcokenny/opencode-worktree) | Git worktree senza attriti per OpenCode | +| [opencode-sentry-monitor](https://github.com/stolinski/opencode-sentry-monitor) | Traccia e debugga i tuoi agenti AI con Sentry AI Monitoring | --- diff --git a/packages/web/src/content/docs/it/formatters.mdx b/packages/web/src/content/docs/it/formatters.mdx index c264da3f4b..58e4c60ed0 100644 --- a/packages/web/src/content/docs/it/formatters.mdx +++ b/packages/web/src/content/docs/it/formatters.mdx @@ -11,33 +11,34 @@ OpenCode formatta automaticamente i file dopo che vengono scritti o modificati u OpenCode include diversi formattatori integrati per linguaggi e framework popolari. Qui sotto trovi la lista dei formattatori, delle estensioni supportate e dei comandi o opzioni di config richiesti. -| Formattatore | Estensioni | Requisiti | -| -------------------- | -------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- | -| gofmt | .go | `gofmt` command available | -| mix | .ex, .exs, .eex, .heex, .leex, .neex, .sface | `mix` command available | -| prettier | .js, .jsx, .ts, .tsx, .html, .css, .md, .json, .yaml, and [more](https://prettier.io/docs/en/index.html) | `prettier` dependency in `package.json` | -| biome | .js, .jsx, .ts, .tsx, .html, .css, .md, .json, .yaml, and [more](https://biomejs.dev/) | `biome.json(c)` config file | -| zig | .zig, .zon | `zig` command available | -| clang-format | .c, .cpp, .h, .hpp, .ino, and [more](https://clang.llvm.org/docs/ClangFormat.html) | `.clang-format` config file | -| ktlint | .kt, .kts | `ktlint` command available | -| ruff | .py, .pyi | `ruff` command available with config | -| rustfmt | .rs | `rustfmt` command available | -| cargofmt | .rs | `cargo fmt` command available | -| uv | .py, .pyi | `uv` command available | -| rubocop | .rb, .rake, .gemspec, .ru | `rubocop` command available | -| standardrb | .rb, .rake, .gemspec, .ru | `standardrb` command available | -| htmlbeautifier | .erb, .html.erb | `htmlbeautifier` command available | -| air | .R | `air` command available | -| dart | .dart | `dart` command available | -| dfmt | .d | `dfmt` command available | -| ocamlformat | .ml, .mli | `ocamlformat` command available and `.ocamlformat` config file | -| terraform | .tf, .tfvars | `terraform` command available | -| gleam | .gleam | `gleam` command available | -| nixfmt | .nix | `nixfmt` command available | -| shfmt | .sh, .bash | `shfmt` command available | -| pint | .php | `laravel/pint` dependency in `composer.json` | -| oxfmt (Experimental) | .js, .jsx, .ts, .tsx | `oxfmt` dependency in `package.json` and an [experimental env variable flag](/docs/cli/#experimental) | -| ormolu | .hs | `ormolu` command available | +| Formattatore | Estensioni | Requisiti | +| -------------------- | -------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ | +| air | .R | comando `air` disponibile | +| biome | .js, .jsx, .ts, .tsx, .html, .css, .md, .json, .yaml, and [more](https://biomejs.dev/) | file di configurazione `biome.json(c)` | +| cargofmt | .rs | comando `cargo fmt` disponibile | +| clang-format | .c, .cpp, .h, .hpp, .ino, and [more](https://clang.llvm.org/docs/ClangFormat.html) | file di configurazione `.clang-format` | +| cljfmt | .clj, .cljs, .cljc, .edn | comando `cljfmt` disponibile | +| dart | .dart | comando `dart` disponibile | +| dfmt | .d | comando `dfmt` disponibile | +| gleam | .gleam | comando `gleam` disponibile | +| gofmt | .go | comando `gofmt` disponibile | +| htmlbeautifier | .erb, .html.erb | comando `htmlbeautifier` disponibile | +| ktlint | .kt, .kts | comando `ktlint` disponibile | +| mix | .ex, .exs, .eex, .heex, .leex, .neex, .sface | comando `mix` disponibile | +| nixfmt | .nix | comando `nixfmt` disponibile | +| ocamlformat | .ml, .mli | comando `ocamlformat` disponibile e file di configurazione `.ocamlformat` | +| ormolu | .hs | comando `ormolu` disponibile | +| oxfmt (Experimental) | .js, .jsx, .ts, .tsx | dipendenza `oxfmt` in `package.json` e una [flag variabile d'ambiente sperimentale](/docs/cli/#experimental) | +| pint | .php | dipendenza `laravel/pint` in `composer.json` | +| prettier | .js, .jsx, .ts, .tsx, .html, .css, .md, .json, .yaml, and [more](https://prettier.io/docs/en/index.html) | dipendenza `prettier` in `package.json` | +| rubocop | .rb, .rake, .gemspec, .ru | comando `rubocop` disponibile | +| ruff | .py, .pyi | comando `ruff` disponibile con config | +| rustfmt | .rs | comando `rustfmt` disponibile | +| shfmt | .sh, .bash | comando `shfmt` disponibile | +| standardrb | .rb, .rake, .gemspec, .ru | comando `standardrb` disponibile | +| terraform | .tf, .tfvars | comando `terraform` disponibile | +| uv | .py, .pyi | comando `uv` disponibile | +| zig | .zig, .zon | comando `zig` disponibile | Quindi, se il progetto ha `prettier` in `package.json`, OpenCode lo usera automaticamente. diff --git a/packages/web/src/content/docs/it/go.mdx b/packages/web/src/content/docs/it/go.mdx new file mode 100644 index 0000000000..912cd29004 --- /dev/null +++ b/packages/web/src/content/docs/it/go.mdx @@ -0,0 +1,145 @@ +--- +title: Go +description: Abbonamento a basso costo per modelli di coding open source. +--- + +import config from "../../../../config.mjs" +export const console = config.console +export const email = `mailto:${config.email}` + +OpenCode Go è un abbonamento a basso costo di **$10/mese** che ti offre un accesso affidabile ai modelli di coding open source più popolari. + +:::note +OpenCode Go è attualmente in beta. +::: + +Go funziona come qualsiasi altro provider in OpenCode. Ti abboni a OpenCode Go e ottieni la tua chiave API. È **completamente opzionale** e non è necessario utilizzarlo per usare OpenCode. + +È progettato principalmente per utenti internazionali, con modelli ospitati negli Stati Uniti, UE e Singapore per un accesso globale stabile. + +--- + +## Contesto + +I modelli open source sono diventati davvero validi. Ora raggiungono prestazioni vicine ai modelli proprietari per le attività di coding. E poiché molti provider possono servirli in modo competitivo, sono solitamente molto più economici. + +Tuttavia, ottenere un accesso affidabile e a bassa latenza può essere difficile. I provider variano in termini di qualità e disponibilità. + +:::tip +Abbiamo testato un gruppo selezionato di modelli e provider che funzionano bene con OpenCode. +::: + +Per risolvere questo problema, abbiamo fatto un paio di cose: + +1. Abbiamo testato un gruppo selezionato di modelli open source e parlato con i loro team su come eseguirli al meglio. +2. Abbiamo poi lavorato con alcuni provider per assicurarci che questi venissero serviti correttamente. +3. Infine, abbiamo effettuato benchmark sulla combinazione modello/provider e abbiamo stilato un elenco che ci sentiamo di raccomandare. + +OpenCode Go ti dà accesso a questi modelli per **$10/mese**. + +--- + +## Come funziona + +OpenCode Go funziona come qualsiasi altro provider in OpenCode. + +1. Accedi a **<a href={console}>OpenCode Zen</a>**, abbonati a Go e copia la tua chiave API. +2. Esegui il comando `/connect` nella TUI, seleziona `OpenCode Go` e incolla la tua chiave API. +3. Esegui `/models` nella TUI per vedere l'elenco dei modelli disponibili tramite Go. + +:::note +Solo un membro per workspace può abbonarsi a OpenCode Go. +::: + +L'elenco attuale dei modelli include: + +- **GLM-5** +- **Kimi K2.5** +- **MiniMax M2.5** + +L'elenco dei modelli potrebbe cambiare man mano che ne testiamo e aggiungiamo di nuovi. + +--- + +## Limiti di utilizzo + +OpenCode Go include i seguenti limiti: + +- **Limite di 5 ore** — $12 di utilizzo +- **Limite settimanale** — $30 di utilizzo +- **Limite mensile** — $60 di utilizzo + +I limiti sono definiti in valore monetario. Ciò significa che il conteggio effettivo delle richieste dipende dal modello utilizzato. Modelli più economici come MiniMax M2.5 consentono più richieste, mentre modelli più costosi come GLM-5 ne consentono meno. + +La tabella seguente fornisce una stima del conteggio delle richieste basata su tipici modelli di utilizzo di Go: + +| | GLM-5 | Kimi K2.5 | MiniMax M2.5 | +| --------------------- | ----- | --------- | ------------ | +| richieste ogni 5 ore | 1.150 | 1.850 | 30.000 | +| richieste a settimana | 2.880 | 4.630 | 75.000 | +| richieste al mese | 5.750 | 9.250 | 150.000 | + +Le stime si basano sui modelli di richiesta medi osservati: + +- GLM-5 — 700 input, 52.000 cached, 150 output tokens per richiesta +- Kimi K2.5 — 870 input, 55.000 cached, 200 output tokens per richiesta +- MiniMax M2.5 — 300 input, 55.000 cached, 125 output tokens per richiesta + +Puoi monitorare il tuo utilizzo attuale nella **<a href={console}>console</a>**. + +:::tip +Se raggiungi il limite di utilizzo, puoi continuare a utilizzare i modelli gratuiti. +::: + +I limiti di utilizzo potrebbero cambiare man mano che impariamo dall'utilizzo iniziale e dai feedback. + +--- + +### Prezzi + +OpenCode Go è un piano di abbonamento da **$10/mese**. Di seguito sono riportati i prezzi **per 1M di token**. + +| Modello | Input | Output | Lettura Cached | +| ------------ | ----- | ------ | -------------- | +| GLM-5 | $1.00 | $3.20 | $0.20 | +| Kimi K2.5 | $0.60 | $3.00 | $0.10 | +| MiniMax M2.5 | $0.30 | $1.20 | $0.03 | + +--- + +### Utilizzo oltre i limiti + +Se hai anche crediti sul tuo saldo Zen, puoi abilitare l'opzione **Use balance** nella console. Quando abilitata, Go utilizzerà il tuo saldo Zen dopo aver raggiunto i limiti di utilizzo invece di bloccare le richieste. + +--- + +## Endpoint + +Puoi anche accedere ai modelli Go tramite i seguenti endpoint API. + +| Modello | ID Modello | Endpoint | Pacchetto AI SDK | +| ------------ | ------------ | ------------------------------------------------ | --------------------------- | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | + +Il [model id](/docs/config/#models) nella tua configurazione OpenCode utilizza il formato `opencode-go/<model-id>`. Ad esempio, per Kimi K2.5, useresti `opencode-go/kimi-k2.5` nella tua configurazione. + +--- + +## Privacy + +Il piano è progettato principalmente per utenti internazionali, con modelli ospitati negli Stati Uniti, UE e Singapore per un accesso globale stabile. + +<a href={email}>Contattaci</a> se hai domande. + +--- + +## Obiettivi + +Abbiamo creato OpenCode Go per: + +1. Rendere l'AI per il coding **accessibile** a più persone con un abbonamento a basso costo. +2. Fornire un accesso **affidabile** ai migliori modelli di coding open source. +3. Curare modelli che sono **testati e benchmarked** per l'uso con agenti di coding. +4. Non avere **alcun lock-in** permettendoti di utilizzare qualsiasi altro provider con OpenCode. diff --git a/packages/web/src/content/docs/it/keybinds.mdx b/packages/web/src/content/docs/it/keybinds.mdx index eb08c2c286..e599f4e417 100644 --- a/packages/web/src/content/docs/it/keybinds.mdx +++ b/packages/web/src/content/docs/it/keybinds.mdx @@ -3,11 +3,11 @@ title: Scorciatoie description: Personalizza le scorciatoie da tastiera. --- -OpenCode ha una lista di scorciatoie che puoi personalizzare tramite la configurazione di OpenCode. +OpenCode ha una lista di scorciatoie che puoi personalizzare tramite `tui.json`. -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "keybinds": { "leader": "ctrl+x", "app_exit": "ctrl+c,ctrl+d,<leader>q", @@ -28,6 +28,7 @@ OpenCode ha una lista di scorciatoie che puoi personalizzare tramite la configur "session_unshare": "none", "session_interrupt": "escape", "session_compact": "<leader>c", + "session_child_first": "<leader>down", "session_child_cycle": "<leader>right", "session_child_cycle_reverse": "<leader>left", "session_parent": "<leader>up", @@ -117,11 +118,11 @@ Non sei obbligato a usare un tasto leader per le scorciatoie, ma lo consigliamo. ## Disabilitare una scorciatoia -Puoi disabilitare una scorciatoia aggiungendo la chiave nella configurazione con valore "none". +Puoi disabilitare una scorciatoia aggiungendo la chiave in `tui.json` con valore "none". -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "keybinds": { "session_compact": "none" } diff --git a/packages/web/src/content/docs/it/lsp.mdx b/packages/web/src/content/docs/it/lsp.mdx index 765475dba0..a21133b141 100644 --- a/packages/web/src/content/docs/it/lsp.mdx +++ b/packages/web/src/content/docs/it/lsp.mdx @@ -27,6 +27,7 @@ OpenCode include diversi server LSP integrati per linguaggi popolari: | gopls | .go | comando `go` disponibile | | hls | .hs, .lhs | comando `haskell-language-server-wrapper` disponibile | | jdtls | .java | `Java SDK (version 21+)` installato | +| julials | .jl | `julia` e `LanguageServer.jl` installati | | kotlin-ls | .kt, .kts | Installazione automatica per progetti Kotlin | | lua-ls | .lua | Installazione automatica per progetti Lua | | nixd | .nix | comando `nixd` disponibile | diff --git a/packages/web/src/content/docs/it/plugins.mdx b/packages/web/src/content/docs/it/plugins.mdx index ea73f40ffd..3fc22a78c5 100644 --- a/packages/web/src/content/docs/it/plugins.mdx +++ b/packages/web/src/content/docs/it/plugins.mdx @@ -3,7 +3,7 @@ title: Plugin description: Scrivi plugin per estendere OpenCode. --- -I plugin ti permettono di estendere OpenCode agganciandoti a vari eventi e personalizzando il comportamento. Puoi creare plugin per aggiungere nuove funzionalita', integrare servizi esterni o modificare il comportamento predefinito di OpenCode. +I plugin ti permettono di estendere OpenCode agganciandoti a vari eventi e personalizzando il comportamento. Puoi creare plugin per aggiungere nuove funzionalità, integrare servizi esterni o modificare il comportamento predefinito di OpenCode. Per esempi, dai un'occhiata ai [plugin](/docs/ecosystem#plugins) creati dalla community. @@ -53,7 +53,7 @@ I **plugin locali** vengono caricati direttamente dalla directory dei plugin. Pe ### Ordine di caricamento -I plugin vengono caricati da tutte le sorgenti e tutti gli hook vengono eseguiti in sequenza. L'ordine di caricamento e': +I plugin vengono caricati da tutte le sorgenti e tutti gli hook vengono eseguiti in sequenza. L'ordine di caricamento è: 1. Config globale (`~/.config/opencode/opencode.json`) 2. Config di progetto (`opencode.json`) @@ -66,7 +66,7 @@ I pacchetti npm duplicati con lo stesso nome e versione vengono caricati una sol ## Creare un plugin -Un plugin e' un **modulo JavaScript/TypeScript** che esporta una o piu' funzioni di plugin. Ogni funzione riceve un oggetto di contesto e restituisce un oggetto di hook. +Un plugin è un **modulo JavaScript/TypeScript** che esporta una o più funzioni di plugin. Ogni funzione riceve un oggetto di contesto e restituisce un oggetto di hook. --- @@ -234,7 +234,7 @@ export const NotificationPlugin = async ({ project, client, $, directory, worktr Stiamo usando `osascript` per eseguire AppleScript su macOS. Qui lo usiamo per inviare notifiche. :::note -Se usi l'app desktop di OpenCode, puo' inviare automaticamente notifiche di sistema quando una risposta e' pronta o quando una sessione va in errore. +Se usi l'app desktop di OpenCode, può inviare automaticamente notifiche di sistema quando una risposta è pronta o quando una sessione va in errore. ::: --- @@ -299,7 +299,7 @@ export const CustomToolsPlugin: Plugin = async (ctx) => { } ``` -L'helper `tool` crea uno strumento personalizzato che opencode puo' chiamare. Accetta una funzione di schema Zod e restituisce una definizione di tool con: +L'helper `tool` crea uno strumento personalizzato che opencode può chiamare. Accetta una funzione di schema Zod e restituisce una definizione di tool con: - `description`: cosa fa lo strumento - `args`: schema Zod per gli argomenti dello strumento @@ -307,6 +307,10 @@ L'helper `tool` crea uno strumento personalizzato che opencode puo' chiamare. Ac I tuoi strumenti personalizzati saranno disponibili in opencode insieme agli strumenti integrati. +:::note +Se uno strumento di un plugin usa lo stesso nome di uno strumento integrato, lo strumento del plugin ha la precedenza. +::: + --- ### Logging @@ -381,4 +385,4 @@ Format as a structured prompt that a new agent can use to resume work. } ``` -Quando `output.prompt` e' impostato, sostituisce completamente il prompt di compaction predefinito. In questo caso l'array `output.context` viene ignorato. +Quando `output.prompt` è impostato, sostituisce completamente il prompt di compaction predefinito. In questo caso l'array `output.context` viene ignorato. diff --git a/packages/web/src/content/docs/it/providers.mdx b/packages/web/src/content/docs/it/providers.mdx index 9b4c07b665..c0c5489d08 100644 --- a/packages/web/src/content/docs/it/providers.mdx +++ b/packages/web/src/content/docs/it/providers.mdx @@ -818,7 +818,7 @@ Alcuni modelli devono essere abilitati manualmente nelle tue [impostazioni GitHu │ │ Enter code: 8F43-6FCF │ - └ Waiting for authorization... + │ └ Waiting for authorization... ``` 3. Ora esegui il comando `/models` per selezionare il modello che vuoi. @@ -1488,6 +1488,39 @@ SAP AI Core fornisce accesso a oltre 40 modelli di OpenAI, Anthropic, Google, Am --- +### STACKIT + +STACKIT AI Model Serving fornisce un ambiente di hosting completamente gestito e sovrano per modelli AI, concentrandosi su LLM come Llama, Mistral e Qwen, con la massima sovranità dei dati su infrastruttura europea. + +1. Vai al [Portale STACKIT](https://portal.stackit.cloud), naviga in **AI Model Serving** e crea un token di autenticazione per il tuo progetto. + + :::tip + Devi avere un account cliente STACKIT, un account utente e un progetto prima di creare token di autenticazione. + ::: + +2. Esegui il comando `/connect` e cerca **STACKIT**. + + ```txt + /connect + ``` + +3. Inserisci il tuo token di autenticazione STACKIT AI Model Serving. + + ```txt + ┌ API key + │ + │ + └ enter + ``` + +4. Esegui il comando `/models` per selezionare tra i modelli disponibili come _Qwen3-VL 235B_ o _Llama 3.3 70B_. + + ```txt + /models + ``` + +--- + ### OVHcloud AI Endpoints 1. Vai al [pannello OVHcloud](https://ovh.com/manager). Naviga nella sezione `Public Cloud`, `AI & Machine Learning` > `AI Endpoints` e nella scheda `API Keys`, clicca **Create a new API key**. diff --git a/packages/web/src/content/docs/it/sdk.mdx b/packages/web/src/content/docs/it/sdk.mdx index 9cf7e4eae5..2941bfb24c 100644 --- a/packages/web/src/content/docs/it/sdk.mdx +++ b/packages/web/src/content/docs/it/sdk.mdx @@ -117,6 +117,78 @@ try { --- +## Output Strutturato + +Puoi richiedere un output JSON strutturato dal modello specificando un `format` con uno schema JSON. Il modello usera un tool `StructuredOutput` per restituire JSON validato che corrisponde al tuo schema. + +### Uso Base + +```typescript +const result = await client.session.prompt({ + path: { id: sessionId }, + body: { + parts: [{ type: "text", text: "Research Anthropic and provide company info" }], + format: { + type: "json_schema", + schema: { + type: "object", + properties: { + company: { type: "string", description: "Company name" }, + founded: { type: "number", description: "Year founded" }, + products: { + type: "array", + items: { type: "string" }, + description: "Main products", + }, + }, + required: ["company", "founded"], + }, + }, + }, +}) + +// Access the structured output +console.log(result.data.info.structured_output) +// { company: "Anthropic", founded: 2021, products: ["Claude", "Claude API"] } +``` + +### Tipi di Formato Output + +| Tipo | Descrizione | +| ------------- | ------------------------------------------------------------------- | +| `text` | Predefinito. Risposta di testo standard (nessun output strutturato) | +| `json_schema` | Restituisce JSON validato che corrisponde allo schema fornito | + +### Formato Schema JSON + +Quando usi `type: 'json_schema'`, fornisci: + +| Campo | Tipo | Descrizione | +| ------------ | --------------- | --------------------------------------------------------------------- | +| `type` | `'json_schema'` | Richiesto. Specifica la modalita schema JSON | +| `schema` | `object` | Richiesto. Oggetto JSON Schema che definisce la struttura dell'output | +| `retryCount` | `number` | Opzionale. Numero di tentativi di validazione (default: 2) | + +### Gestione Errori + +Se il modello non riesce a produrre un output strutturato valido dopo tutti i tentativi, la risposta includera un `StructuredOutputError`: + +```typescript +if (result.data.info.error?.name === "StructuredOutputError") { + console.error("Failed to produce structured output:", result.data.info.error.message) + console.error("Attempts:", result.data.info.error.retries) +} +``` + +### Best Practices + +1. **Fornisci descrizioni chiare** nelle proprieta del tuo schema per aiutare il modello a capire quali dati estrarre +2. **Usa `required`** per specificare quali campi devono essere presenti +3. **Mantieni gli schemi focalizzati** - schemi annidati complessi potrebbero essere piu difficili da compilare correttamente per il modello +4. **Imposta un `retryCount` appropriato** - aumenta per schemi complessi, diminuisci per quelli semplici + +--- + ## API L'SDK espone tutte le API del server tramite un client type-safe. @@ -226,27 +298,27 @@ const { providers, default: defaults } = await client.config.providers() ### Sessioni -| Metodo | Descrizione | Note | -| ---------------------------------------------------------- | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | -| `session.list()` | Elenca le sessioni | Returns <a href={typesUrl}><code>Session[]</code></a> | -| `session.get({ path })` | Ottieni una sessione | Returns <a href={typesUrl}><code>Session</code></a> | -| `session.children({ path })` | Elenca sessioni figlie | Returns <a href={typesUrl}><code>Session[]</code></a> | -| `session.create({ body })` | Crea una sessione | Returns <a href={typesUrl}><code>Session</code></a> | -| `session.delete({ path })` | Elimina una sessione | Returns `boolean` | -| `session.update({ path, body })` | Aggiorna proprieta della sessione | Returns <a href={typesUrl}><code>Session</code></a> | -| `session.init({ path, body })` | Analizza app e crea `AGENTS.md` | Returns `boolean` | -| `session.abort({ path })` | Interrompe una sessione in corso | Returns `boolean` | -| `session.share({ path })` | Condivide la sessione | Returns <a href={typesUrl}><code>Session</code></a> | -| `session.unshare({ path })` | Rimuove la condivisione | Returns <a href={typesUrl}><code>Session</code></a> | -| `session.summarize({ path, body })` | Riassume la sessione | Returns `boolean` | -| `session.messages({ path })` | Elenca i messaggi della sessione | Returns `{ info: `<a href={typesUrl}><code>Message</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}[]` | -| `session.message({ path })` | Ottieni dettagli di un messaggio | Returns `{ info: `<a href={typesUrl}><code>Message</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}` | -| `session.prompt({ path, body })` | Invia un prompt | `body.noReply: true` returns UserMessage (solo contesto). Di default ritorna <a href={typesUrl}><code>AssistantMessage</code></a> con risposta AI | -| `session.command({ path, body })` | Invia un comando alla sessione | Returns `{ info: `<a href={typesUrl}><code>AssistantMessage</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}` | -| `session.shell({ path, body })` | Esegue un comando shell | Returns <a href={typesUrl}><code>AssistantMessage</code></a> | -| `session.revert({ path, body })` | Ripristina un messaggio | Returns <a href={typesUrl}><code>Session</code></a> | -| `session.unrevert({ path })` | Ripristina messaggi revertiti | Returns <a href={typesUrl}><code>Session</code></a> | -| `postSessionByIdPermissionsByPermissionId({ path, body })` | Risponde a una richiesta permessi | Returns `boolean` | +| Metodo | Descrizione | Note | +| ---------------------------------------------------------- | --------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `session.list()` | Elenca le sessioni | Returns <a href={typesUrl}><code>Session[]</code></a> | +| `session.get({ path })` | Ottieni una sessione | Returns <a href={typesUrl}><code>Session</code></a> | +| `session.children({ path })` | Elenca sessioni figlie | Returns <a href={typesUrl}><code>Session[]</code></a> | +| `session.create({ body })` | Crea una sessione | Returns <a href={typesUrl}><code>Session</code></a> | +| `session.delete({ path })` | Elimina una sessione | Returns `boolean` | +| `session.update({ path, body })` | Aggiorna proprieta della sessione | Returns <a href={typesUrl}><code>Session</code></a> | +| `session.init({ path, body })` | Analizza app e crea `AGENTS.md` | Returns `boolean` | +| `session.abort({ path })` | Interrompe una sessione in corso | Returns `boolean` | +| `session.share({ path })` | Condivide la sessione | Returns <a href={typesUrl}><code>Session</code></a> | +| `session.unshare({ path })` | Rimuove la condivisione | Returns <a href={typesUrl}><code>Session</code></a> | +| `session.summarize({ path, body })` | Riassume la sessione | Returns `boolean` | +| `session.messages({ path })` | Elenca i messaggi della sessione | Returns `{ info: `<a href={typesUrl}><code>Message</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}[]` | +| `session.message({ path })` | Ottieni dettagli di un messaggio | Returns `{ info: `<a href={typesUrl}><code>Message</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}` | +| `session.prompt({ path, body })` | Invia un prompt | `body.noReply: true` returns UserMessage (solo contesto). Di default ritorna <a href={typesUrl}><code>AssistantMessage</code></a> con risposta AI. Supporta `body.outputFormat` per [output strutturato](#output-strutturato) | +| `session.command({ path, body })` | Invia un comando alla sessione | Returns `{ info: `<a href={typesUrl}><code>AssistantMessage</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}` | +| `session.shell({ path, body })` | Esegue un comando shell | Returns <a href={typesUrl}><code>AssistantMessage</code></a> | +| `session.revert({ path, body })` | Ripristina un messaggio | Returns <a href={typesUrl}><code>Session</code></a> | +| `session.unrevert({ path })` | Ripristina messaggi revertiti | Returns <a href={typesUrl}><code>Session</code></a> | +| `postSessionByIdPermissionsByPermissionId({ path, body })` | Risponde a una richiesta permessi | Returns `boolean` | --- diff --git a/packages/web/src/content/docs/it/share.mdx b/packages/web/src/content/docs/it/share.mdx index f9eff6ca9b..9b410a6b86 100644 --- a/packages/web/src/content/docs/it/share.mdx +++ b/packages/web/src/content/docs/it/share.mdx @@ -41,7 +41,7 @@ Per impostare esplicitamente la modalita manuale nel tuo [file di config](/docs/ ```json title="opencode.json" { - "$schema": "https://opncd.ai/config.json", + "$schema": "https://opencode.ai/config.json", "share": "manual" } ``` @@ -54,7 +54,7 @@ Puoi abilitare la condivisione automatica per tutte le nuove conversazioni impos ```json title="opencode.json" { - "$schema": "https://opncd.ai/config.json", + "$schema": "https://opencode.ai/config.json", "share": "auto" } ``` @@ -69,7 +69,7 @@ Puoi disabilitare completamente la condivisione impostando l'opzione `share` su ```json title="opencode.json" { - "$schema": "https://opncd.ai/config.json", + "$schema": "https://opencode.ai/config.json", "share": "disabled" } ``` diff --git a/packages/web/src/content/docs/it/themes.mdx b/packages/web/src/content/docs/it/themes.mdx index 6752470e0f..055e108727 100644 --- a/packages/web/src/content/docs/it/themes.mdx +++ b/packages/web/src/content/docs/it/themes.mdx @@ -45,13 +45,13 @@ E altri ancora: aggiungiamo costantemente nuovi temi. ## Tema di sistema -Il tema `system` e progettato per adattarsi automaticamente allo schema colori del tuo terminale. A differenza dei temi tradizionali con colori fissi, il tema _system_: +Il tema `system` è progettato per adattarsi automaticamente allo schema colori del tuo terminale. A differenza dei temi tradizionali con colori fissi, il tema _system_: - **Genera una scala di grigi**: crea una scala di grigi personalizzata in base al colore di sfondo del terminale, garantendo un contrasto ottimale. - **Usa colori ANSI**: sfrutta i colori ANSI standard (0-15) per evidenziazione della sintassi ed elementi UI, rispettando la palette del terminale. - **Preserva i default del terminale**: usa `none` per testo e sfondo per mantenere l'aspetto nativo del terminale. -Il tema di sistema e pensato per chi: +Il tema di sistema è pensato per chi: - Vuole che OpenCode corrisponda all'aspetto del terminale - Usa schemi colori personalizzati del terminale @@ -61,11 +61,11 @@ Il tema di sistema e pensato per chi: ## Usare un tema -Puoi selezionare un tema aprendo la selezione temi con il comando `/theme`. In alternativa, puoi specificarlo nella tua [configurazione](/docs/config). +Puoi selezionare un tema aprendo la selezione temi con il comando `/theme`. In alternativa, puoi specificarlo in `tui.json`. -```json title="opencode.json" {3} +```json title="tui.json" {3} { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "theme": "tokyonight" } ``` @@ -80,14 +80,14 @@ OpenCode supporta un sistema di temi flessibile basato su JSON che permette di c ### Gerarchia -I temi vengono caricati da piu directory nel seguente ordine, dove le directory successive sovrascrivono le precedenti: +I temi vengono caricati da più directory nel seguente ordine, dove le directory successive sovrascrivono le precedenti: 1. **Temi integrati** - incorporati nel binario 2. **Directory di configurazione utente** - in `~/.config/opencode/themes/*.json` o `$XDG_CONFIG_HOME/opencode/themes/*.json` 3. **Directory root del progetto** - in `<project-root>/.opencode/themes/*.json` 4. **Directory di lavoro corrente** - in `./.opencode/themes/*.json` -Se piu directory contengono un tema con lo stesso nome, verra usato il tema della directory con priorita piu alta. +Se più directory contengono un tema con lo stesso nome, verrà usato il tema della directory con priorità più alta. --- @@ -125,13 +125,13 @@ I temi usano un formato JSON flessibile che supporta: ### Definizioni dei colori -La sezione `defs` e opzionale e ti permette di definire colori riutilizzabili che possono essere referenziati nel tema. +La sezione `defs` è opzionale e ti permette di definire colori riutilizzabili che possono essere referenziati nel tema. --- ### Valori predefiniti del terminale -Il valore speciale `"none"` puo essere usato per qualunque colore per ereditare il colore predefinito del terminale. E particolarmente utile per creare temi che si fondono con lo schema colori del terminale: +Il valore speciale `"none"` può essere usato per qualunque colore per ereditare il colore predefinito del terminale. È particolarmente utile per creare temi che si fondono con lo schema colori del terminale: - `"text": "none"` - usa il colore del testo predefinito del terminale - `"background": "none"` - usa il colore di sfondo predefinito del terminale diff --git a/packages/web/src/content/docs/it/troubleshooting.mdx b/packages/web/src/content/docs/it/troubleshooting.mdx index 5140571507..7c168979da 100644 --- a/packages/web/src/content/docs/it/troubleshooting.mdx +++ b/packages/web/src/content/docs/it/troubleshooting.mdx @@ -57,8 +57,8 @@ Se l'app desktop va in crash all'avvio, si blocca o si comporta in modo strano, Apri il tuo file di configurazione globale e cerca la chiave `plugin`. -- **macOS/Linux**: `~/.config/opencode/opencode.jsonc` (or `~/.config/opencode/opencode.json`) -- **macOS/Linux** (older installs): `~/.local/share/opencode/opencode.jsonc` +- **macOS/Linux**: `~/.config/opencode/opencode.jsonc` (o `~/.config/opencode/opencode.json`) +- **macOS/Linux** (installazioni vecchie): `~/.local/share/opencode/opencode.jsonc` - **Windows**: premi `WIN+R` e incolla `%USERPROFILE%\.config\opencode\opencode.jsonc` Se hai plugin configurati, disabilitali temporaneamente rimuovendo la chiave o impostandola a un array vuoto: @@ -88,14 +88,14 @@ Se l'app ricomincia a funzionare, riabilita i plugin uno alla volta per capire q Se disabilitare i plugin non aiuta (o l'installazione di un plugin e bloccata), svuota la cache in modo che OpenCode possa ricostruirla. -1. Quit OpenCode Desktop completely. +1. Chiudi completamente OpenCode Desktop. 2. Elimina la directory della cache: - **macOS**: Finder -> `Cmd+Shift+G` -> paste `~/.cache/opencode` - **Linux**: elimina `~/.cache/opencode` (oppure esegui `rm -rf ~/.cache/opencode`) - **Windows**: premi `WIN+R` e incolla `%USERPROFILE%\.cache\opencode` -3. Restart OpenCode Desktop. +3. Riavvia OpenCode Desktop. --- @@ -155,7 +155,7 @@ OpenCode Desktop mostra le notifiche di sistema solo quando: Se l'app non si avvia e non riesci a ripulire le impostazioni dall'interfaccia, reimposta lo stato salvato dell'app desktop. -1. Quit OpenCode Desktop. +1. Chiudi OpenCode Desktop. 2. Trova ed elimina questi file (si trovano nella directory dati dell'app OpenCode Desktop): - `opencode.settings.dat` (desktop default server URL) diff --git a/packages/web/src/content/docs/it/tui.mdx b/packages/web/src/content/docs/it/tui.mdx index 8a09c97a3e..2e4efa2608 100644 --- a/packages/web/src/content/docs/it/tui.mdx +++ b/packages/web/src/content/docs/it/tui.mdx @@ -63,7 +63,7 @@ Quando usi la TUI di OpenCode, puoi digitare `/` seguito dal nome di un comando /help ``` -Molti comandi hanno anche una scorciatoia da tastiera che usa `ctrl+x` come tasto leader (predefinito). [Scopri di piu](/docs/keybinds). +Molti comandi hanno anche una scorciatoia da tastiera che usa `ctrl+x` come tasto leader (predefinito). [Scopri di più](/docs/keybinds). Ecco tutti i comandi slash disponibili: @@ -105,7 +105,7 @@ Attiva/disattiva i dettagli di esecuzione degli strumenti. ### editor -Apre un editor esterno per comporre messaggi. Usa l'editor impostato nella variabile d'ambiente `EDITOR`. [Scopri di piu](#editor-setup). +Apre un editor esterno per comporre messaggi. Usa l'editor impostato nella variabile d'ambiente `EDITOR`. [Scopri di più](#editor-setup). ```bash frame="none" /editor @@ -129,7 +129,7 @@ Esce da OpenCode. _Alias_: `/quit`, `/q` ### esporta -Esporta la conversazione corrente in Markdown e la apre nell'editor predefinito. Usa l'editor impostato nella variabile d'ambiente `EDITOR`. [Scopri di piu](#editor-setup). +Esporta la conversazione corrente in Markdown e la apre nell'editor predefinito. Usa l'editor impostato nella variabile d'ambiente `EDITOR`. [Scopri di più](#editor-setup). ```bash frame="none" /export @@ -153,7 +153,7 @@ Mostra la finestra di aiuto. ### inizializza -Crea o aggiorna il file `AGENTS.md`. [Scopri di piu](/docs/rules). +Crea o aggiorna il file `AGENTS.md`. [Scopri di più](/docs/rules). ```bash frame="none" /init @@ -219,7 +219,7 @@ Elenca e passa tra le sessioni. _Alias_: `/resume`, `/continue` ### condividi -Condivide la sessione corrente. [Scopri di piu](/docs/share). +Condivide la sessione corrente. [Scopri di più](/docs/share). ```bash frame="none" /share @@ -234,7 +234,7 @@ Condivide la sessione corrente. [Scopri di piu](/docs/share). Elenca i temi disponibili. ```bash frame="none" -/theme +/themes ``` **Scorciatoia:** `ctrl+x t` @@ -243,10 +243,10 @@ Elenca i temi disponibili. ### ragionamento -Attiva/disattiva la visibilita dei blocchi thinking/reasoning nella conversazione. Quando abilitato, puoi vedere il ragionamento del modello per i modelli che supportano extended thinking. +Attiva/disattiva la visibilità dei blocchi thinking/reasoning nella conversazione. Quando abilitato, puoi vedere il ragionamento del modello per i modelli che supportano extended thinking. :::note -Questo comando controlla solo se i blocchi di thinking vengono **mostrati**: non abilita o disabilita le capacita di ragionamento del modello. Per cambiare le capacita di ragionamento effettive, usa `ctrl+t` per ciclare tra le varianti del modello. +Questo comando controlla solo se i blocchi di thinking vengono **mostrati**: non abilita o disabilita le capacità di ragionamento del modello. Per cambiare le capacità di ragionamento effettive, usa `ctrl+t` per ciclare tra le varianti del modello. ::: ```bash frame="none" @@ -275,7 +275,7 @@ Internamente usa Git per gestire le modifiche ai file. Quindi il progetto **deve ### annulla condivisione -Annulla la condivisione della sessione corrente. [Scopri di piu](/docs/share#un-sharing). +Annulla la condivisione della sessione corrente. [Scopri di più](/docs/share#un-sharing). ```bash frame="none" /unshare @@ -346,30 +346,40 @@ Opzioni comuni per l'editor includono: Alcuni editor come VS Code devono essere avviati con il flag `--wait`. ::: -Alcuni editor richiedono argomenti da riga di comando per funzionare in modalita bloccante. Il flag `--wait` fa si che il processo dell'editor resti in attesa finche non viene chiuso. +Alcuni editor richiedono argomenti da riga di comando per funzionare in modalità bloccante. Il flag `--wait` fa sì che il processo dell'editor resti in attesa finché non viene chiuso. --- ## Configurazione -Puoi personalizzare il comportamento della TUI tramite il file di config di OpenCode. +Puoi personalizzare il comportamento della TUI tramite `tui.json` (o `tui.jsonc`). -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", - "tui": { - "scroll_speed": 3, - "scroll_acceleration": { - "enabled": true - } - } + "$schema": "https://opencode.ai/tui.json", + "theme": "opencode", + "keybinds": { + "leader": "ctrl+x" + }, + "scroll_speed": 3, + "scroll_acceleration": { + "enabled": true + }, + "diff_style": "auto" } ``` +Questo è separato da `opencode.json`, che configura il comportamento di server/runtime. + ### Opzioni -- `scroll_acceleration` - Abilita l'accelerazione di scroll in stile macOS per uno scorrimento fluido e naturale. Quando abilitata, la velocita aumenta con gesture rapide e resta precisa con movimenti lenti. **Questa impostazione ha precedenza su `scroll_speed` e lo sovrascrive quando attiva.** -- `scroll_speed` - Controlla la velocita di scorrimento della TUI quando usi i comandi di scroll (minimo: `1`). Default: `3`. **Nota: viene ignorata se `scroll_acceleration.enabled` e impostato a `true`.** +- `theme` - Imposta il tema della UI. [Scopri di più](/docs/themes). +- `keybinds` - Personalizza le scorciatoie da tastiera. [Scopri di più](/docs/keybinds). +- `scroll_acceleration.enabled` - Abilita l'accelerazione di scroll in stile macOS per uno scorrimento fluido e naturale. Quando abilitata, la velocità aumenta con gesture rapide e resta precisa con movimenti lenti. **Questa impostazione ha precedenza su `scroll_speed` e lo sovrascrive quando attiva.** +- `scroll_speed` - Controlla la velocità di scorrimento della TUI quando usi i comandi di scroll (minimo: `0.001`, supporta valori decimali). Default: `3`. **Nota: viene ignorata se `scroll_acceleration.enabled` è impostato a `true`.** +- `diff_style` - Controlla il rendering delle diff. `"auto"` si adatta alla larghezza del terminale, `"stacked"` mostra sempre un layout a colonna singola. + +Usa `OPENCODE_TUI_CONFIG` per caricare un path di configurazione TUI personalizzato. --- diff --git a/packages/web/src/content/docs/it/zen.mdx b/packages/web/src/content/docs/it/zen.mdx index 8ea628aee2..0f21684448 100644 --- a/packages/web/src/content/docs/it/zen.mdx +++ b/packages/web/src/content/docs/it/zen.mdx @@ -7,19 +7,19 @@ import config from "../../../../config.mjs" export const console = config.console export const email = `mailto:${config.email}` -OpenCode Zen e una lista di modelli testati e verificati dal team di OpenCode. +OpenCode Zen è una lista di modelli testati e verificati dal team di OpenCode. :::note -OpenCode Zen e attualmente in beta. +OpenCode Zen è attualmente in beta. ::: -Zen funziona come qualunque altro provider in OpenCode. Accedi a OpenCode Zen e ottieni la tua chiave API. E **completamente opzionale**: non devi usarlo per usare OpenCode. +Zen funziona come qualunque altro provider in OpenCode. Accedi a OpenCode Zen e ottieni la tua chiave API. È **completamente opzionale**: non devi usarlo per usare OpenCode. --- ## Contesto -Ci sono moltissimi modelli, ma solo pochi funzionano bene come agenti di coding. Inoltre, la maggior parte dei provider e configurata in modo molto diverso, quindi prestazioni e qualita possono variare parecchio. +Ci sono moltissimi modelli, ma solo pochi funzionano bene come agenti di coding. Inoltre, la maggior parte dei provider è configurata in modo molto diverso, quindi prestazioni e qualità possono variare parecchio. :::tip Abbiamo testato un gruppo selezionato di modelli e provider che funzionano bene con OpenCode. @@ -33,7 +33,7 @@ Per risolvere, abbiamo fatto alcune cose: 2. Poi abbiamo lavorato con alcuni provider per assicurarci che venissero serviti correttamente. 3. Infine, abbiamo fatto benchmark delle combinazioni modello/provider e creato una lista che ci sentiamo di raccomandare. -OpenCode Zen e un gateway AI che ti da accesso a questi modelli. +OpenCode Zen e un gateway AI che ti dà accesso a questi modelli. --- @@ -55,6 +55,8 @@ Puoi anche accedere ai nostri modelli tramite i seguenti endpoint API. | Modello | ID modello | Endpoint | Pacchetto AI SDK | | ------------------ | ------------------ | -------------------------------------------------- | --------------------------- | +| GPT 5.4 | gpt-5.4 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| GPT 5.3 Codex | gpt-5.3-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.2 | gpt-5.2 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.2 Codex | gpt-5.2-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.1 | gpt-5.1 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | @@ -64,22 +66,24 @@ Puoi anche accedere ai nostri modelli tramite i seguenti endpoint API. | GPT 5 | gpt-5 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5 Codex | gpt-5-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5 Nano | gpt-5-nano | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| Claude Opus 4.6 | claude-opus-4-6 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Opus 4.5 | claude-opus-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Opus 4.1 | claude-opus-4-1 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Sonnet 4.6 | claude-sonnet-4-6 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Sonnet 4.5 | claude-sonnet-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Sonnet 4 | claude-sonnet-4 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Haiku 4.5 | claude-haiku-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Haiku 3.5 | claude-3-5-haiku | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| Claude Opus 4.6 | claude-opus-4-6 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| Claude Opus 4.5 | claude-opus-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| Claude Opus 4.1 | claude-opus-4-1 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Gemini 3.1 Pro | gemini-3.1-pro | `https://opencode.ai/zen/v1/models/gemini-3.1-pro` | `@ai-sdk/google` | | Gemini 3 Pro | gemini-3-pro | `https://opencode.ai/zen/v1/models/gemini-3-pro` | `@ai-sdk/google` | | Gemini 3 Flash | gemini-3-flash | `https://opencode.ai/zen/v1/models/gemini-3-flash` | `@ai-sdk/google` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.5 Free | minimax-m2.5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.1 | minimax-m2.1 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.1 Free | minimax-m2.1-free | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| GLM 5 | glm-5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | GLM 4.7 | glm-4.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM 4.7 Free | glm-4.7-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | GLM 4.6 | glm-4.6 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 Free | kimi-k2.5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2 Thinking | kimi-k2-thinking | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2 | kimi-k2 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Qwen3 Coder 480B | qwen3-coder | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -106,29 +110,35 @@ Supportiamo un modello pay-as-you-go. Qui sotto trovi i prezzi **per 1M token**. | Modello | Input | Output | Lettura in cache | Scrittura in cache | | --------------------------------- | ------ | ------ | ---------------- | ------------------ | | Big Pickle | Gratis | Gratis | Gratis | - | -| MiniMax M2.1 Free | Gratis | Gratis | Gratis | - | +| MiniMax M2.5 Free | Gratis | Gratis | Gratis | - | +| MiniMax M2.5 | $0.30 | $1.20 | $0.06 | - | | MiniMax M2.1 | $0.30 | $1.20 | $0.10 | - | -| GLM 4.7 Free | Gratis | Gratis | Gratis | - | +| GLM 5 | $1.00 | $3.20 | $0.20 | - | | GLM 4.7 | $0.60 | $2.20 | $0.10 | - | | GLM 4.6 | $0.60 | $2.20 | $0.10 | - | -| Kimi K2.5 Free | Gratis | Gratis | Gratis | - | | Kimi K2.5 | $0.60 | $3.00 | $0.08 | - | | Kimi K2 Thinking | $0.40 | $2.50 | - | - | | Kimi K2 | $0.40 | $2.50 | - | - | | Qwen3 Coder 480B | $0.45 | $1.50 | - | - | +| Claude Opus 4.6 (≤ 200K tokens) | $5.00 | $25.00 | $0.50 | $6.25 | +| Claude Opus 4.6 (> 200K tokens) | $10.00 | $37.50 | $1.00 | $12.50 | +| Claude Opus 4.5 | $5.00 | $25.00 | $0.50 | $6.25 | +| Claude Opus 4.1 | $15.00 | $75.00 | $1.50 | $18.75 | +| Claude Sonnet 4.6 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 | +| Claude Sonnet 4.6 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 | | Claude Sonnet 4.5 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 | | Claude Sonnet 4.5 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 | | Claude Sonnet 4 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 | | Claude Sonnet 4 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 | | Claude Haiku 4.5 | $1.00 | $5.00 | $0.10 | $1.25 | | Claude Haiku 3.5 | $0.80 | $4.00 | $0.08 | $1.00 | -| Claude Opus 4.6 (≤ 200K tokens) | $5.00 | $25.00 | $0.50 | $6.25 | -| Claude Opus 4.6 (> 200K tokens) | $10.00 | $37.50 | $1.00 | $12.50 | -| Claude Opus 4.5 | $5.00 | $25.00 | $0.50 | $6.25 | -| Claude Opus 4.1 | $15.00 | $75.00 | $1.50 | $18.75 | +| Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | +| Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | | Gemini 3 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | +| GPT 5.4 | $2.50 | $15.00 | $0.25 | - | +| GPT 5.3 Codex | $1.75 | $14.00 | $0.175 | - | | GPT 5.2 | $1.75 | $14.00 | $0.175 | - | | GPT 5.2 Codex | $1.75 | $14.00 | $0.175 | - | | GPT 5.1 | $1.07 | $8.50 | $0.107 | - | @@ -147,10 +157,8 @@ Le commissioni della carta di credito vengono ribaltate al costo (4.4% + $0.30 p I modelli gratuiti: -- GLM 4.7 Free e disponibile su OpenCode per un periodo limitato. Il team usa questo tempo per raccogliere feedback e migliorare il modello. -- Kimi K2.5 Free e disponibile su OpenCode per un periodo limitato. Il team usa questo tempo per raccogliere feedback e migliorare il modello. -- MiniMax M2.1 Free e disponibile su OpenCode per un periodo limitato. Il team usa questo tempo per raccogliere feedback e migliorare il modello. -- Big Pickle e un modello stealth gratuito su OpenCode per un periodo limitato. Il team usa questo tempo per raccogliere feedback e migliorare il modello. +- MiniMax M2.5 Free e disponibile su OpenCode per un periodo limitato. Il team usa questo tempo per raccogliere feedback e migliorare il modello. +- Big Pickle è un modello stealth gratuito su OpenCode per un periodo limitato. Il team usa questo tempo per raccogliere feedback e migliorare il modello. <a href={email}>Contattaci</a> se hai domande. @@ -172,14 +180,25 @@ Per esempio, se imposti un limite mensile a $20, Zen non usera piu di $20 in un --- +### Modelli deprecati + +| Modello | Data di deprecazione | +| ---------------- | -------------------- | +| Qwen3 Coder 480B | 6 feb 2026 | +| Kimi K2 Thinking | 6 mar 2026 | +| Kimi K2 | 6 mar 2026 | +| MiniMax M2.1 | 15 mar 2026 | +| GLM 4.7 | 15 mar 2026 | +| GLM 4.6 | 15 mar 2026 | + +--- + ## Privacy Tutti i nostri modelli sono ospitati negli US. I nostri provider seguono una policy di zero-retention e non usano i tuoi dati per training dei modelli, con le seguenti eccezioni: - Big Pickle: durante il periodo gratuito, i dati raccolti potrebbero essere usati per migliorare il modello. -- GLM 4.7 Free: durante il periodo gratuito, i dati raccolti potrebbero essere usati per migliorare il modello. -- Kimi K2.5 Free: durante il periodo gratuito, i dati raccolti potrebbero essere usati per migliorare il modello. -- MiniMax M2.1 Free: durante il periodo gratuito, i dati raccolti potrebbero essere usati per migliorare il modello. +- MiniMax M2.5 Free: durante il periodo gratuito, i dati raccolti potrebbero essere usati per migliorare il modello. - OpenAI APIs: le richieste vengono conservate per 30 giorni in conformita alle [OpenAI's Data Policies](https://platform.openai.com/docs/guides/your-data). - Anthropic APIs: le richieste vengono conservate per 30 giorni in conformita alle [Anthropic's Data Policies](https://docs.anthropic.com/en/docs/claude-code/data-usage). @@ -193,7 +212,7 @@ Zen funziona benissimo anche per i team. Puoi invitare colleghi, assegnare ruoli I workspace sono attualmente gratuiti per i team come parte della beta. ::: -Gestire il workspace e attualmente gratuito per i team come parte della beta. Condivideremo presto piu dettagli sul pricing. +Gestire il workspace è attualmente gratuito per i team come parte della beta. Condivideremo presto piu dettagli sul pricing. --- @@ -212,7 +231,7 @@ Gli admin possono anche impostare limiti mensili di spesa per ogni membro per te Gli admin possono abilitare o disabilitare modelli specifici per il workspace. Le richieste verso un modello disabilitato restituiscono un errore. -Questo e utile quando vuoi disabilitare l'uso di un modello che raccoglie dati. +Questo è utile quando vuoi disabilitare l'uso di un modello che raccoglie dati. --- diff --git a/packages/web/src/content/docs/ja/cli.mdx b/packages/web/src/content/docs/ja/cli.mdx index aeae74731f..dcb411c833 100644 --- a/packages/web/src/content/docs/ja/cli.mdx +++ b/packages/web/src/content/docs/ja/cli.mdx @@ -335,20 +335,20 @@ opencode run --attach http://localhost:4096 "Explain async/await in JavaScript" #### フラグ -| フラグ | ショート | 説明 | -| ------------ | ----------- | ----------------------------------------------------------------------------------------- | -| `--command` | | 実行するコマンド。引数には message を使用します。 | -| `--continue` | `-c` | 最後のセッションを続行 | -| `--session` | | 続行時にセッションをフォーク (`-s` または `--fork` と併用) | -| `--continue` | `--session` | 続行するセッション ID | -| `--share` | | セッションを共有する | -| `--model` | `-m` | プロバイダー/モデルの形式で使用するモデル | -| `--agent` | | 使用するエージェント | -| `--file` | `-f` | メッセージに添付するファイル | -| `--format` | | 形式: デフォルト (フォーマット済み) または json (生の JSON イベント) | -| `--title` | | セッションのタイトル (値が指定されていない場合は、切り詰められたプロンプトが使用されます) | -| `--attach` | | 実行中の opencode サーバー (http://localhost:4096 など) に接続します。 | -| `--port` | | ローカルサーバーのポート (デフォルトはランダムポート) | +| フラグ | ショート | 説明 | +| ------------ | -------- | ----------------------------------------------------------------------------------------- | +| `--command` | | 実行するコマンド。引数には message を使用します。 | +| `--continue` | `-c` | 最後のセッションを続行 | +| `--session` | `-s` | 続行するセッション ID | +| `--fork` | | 続行時にセッションをフォーク (`--continue` または `--session` と併用) | +| `--share` | | セッションを共有する | +| `--model` | `-m` | プロバイダー/モデルの形式で使用するモデル | +| `--agent` | | 使用するエージェント | +| `--file` | `-f` | メッセージに添付するファイル | +| `--format` | | 形式: デフォルト (フォーマット済み) または json (生の JSON イベント) | +| `--title` | | セッションのタイトル (値が指定されていない場合は、切り詰められたプロンプトが使用されます) | +| `--attach` | | 実行中の opencode サーバー (http://localhost:4096 など) に接続します。 | +| `--port` | | ローカルサーバーのポート (デフォルトはランダムポート) | --- diff --git a/packages/web/src/content/docs/ja/config.mdx b/packages/web/src/content/docs/ja/config.mdx index 114336d43c..20e29190da 100644 --- a/packages/web/src/content/docs/ja/config.mdx +++ b/packages/web/src/content/docs/ja/config.mdx @@ -14,10 +14,11 @@ OpenCode は、**JSON** と **JSONC** (コメント付きの JSON) 形式の両 ```jsonc title="opencode.jsonc" { "$schema": "https://opencode.ai/config.json", - // Theme configuration - "theme": "opencode", "model": "anthropic/claude-sonnet-4-5", "autoupdate": true, + "server": { + "port": 4096, + }, } ``` @@ -25,14 +26,15 @@ OpenCode は、**JSON** と **JSONC** (コメント付きの JSON) 形式の両 ## ファイルの場所 -設定をいくつかの異なる場所に配置できます。 -優先順位が異なります。 +設定をいくつかの異なる場所に配置できます。それらは異なる優先順位を持ちます。 :::note -設定ファイルは置き換えられるのではなく、**マージ**されます。設定は、次の構成場所から結合されます。後続の設定は、競合するキーに対してのみ以前の設定をオーバーライドします。すべての設定の競合しない設定は保持されます。 +設定ファイルは置き換えられるのではなく、**マージ**されます。 ::: -たとえば、グローバル設定で `theme: "opencode"` と `autoupdate: true` が設定され、プロジェクト設定で `model: "anthropic/claude-sonnet-4-5"` が設定されている場合、最終的な設定には 3 つの設定がすべて含まれます。 +設定ファイルは結合され、置き換えられません。次の構成場所からの設定が結合されます。競合するキーに対してのみ、後の設定が前の設定を上書きします。すべての構成からの競合しない設定は保持されます。 + +たとえば、グローバル設定で `autoupdate: true` を設定し、プロジェクト設定で `model: "anthropic/claude-sonnet-4-5"` を設定した場合、最終的な構成には両方の設定が含まれます。 --- @@ -93,7 +95,9 @@ OpenCode は、**JSON** と **JSONC** (コメント付きの JSON) 形式の両 ### グローバル -グローバル OpenCode 設定を `~/.config/opencode/opencode.json` に配置します。テーマ、プロバイダー、キーバインドなどのユーザー全体の設定にはグローバル設定を使用します。 +グローバル OpenCode 設定を `~/.config/opencode/opencode.json` に配置します。プロバイダー、モデル、権限などのユーザー全体の設定にはグローバル設定を使用します。 + +TUI 固有の設定には、`~/.config/opencode/tui.json` を使用します。 グローバル設定はリモート組織のデフォルトをオーバーライドします。 @@ -103,6 +107,8 @@ OpenCode は、**JSON** と **JSONC** (コメント付きの JSON) 形式の両 プロジェクトのルートに `opencode.json` を追加します。プロジェクト設定は、標準設定ファイルの中で最も高い優先順位を持ち、グローバル設定とリモート設定の両方をオーバーライドします。 +プロジェクト固有の TUI 設定については、その横に `tui.json` を追加します。 + :::tip プロジェクト固有の設定をプロジェクトのルートに配置します。 ::: @@ -144,7 +150,9 @@ opencode run "Hello world" ## スキーマ -設定ファイルには、[**`opencode.ai/config.json`**](https://opencode.ai/config.json) を使用します。 +サーバー/ランタイム構成スキーマは [**`opencode.ai/config.json`**](https://opencode.ai/config.json) で定義されています。 + +TUI 設定は [**`opencode.ai/tui.json`**](https://opencode.ai/tui.json) を使用します。 エディターはスキーマに基づいて検証し、オートコンプリートできる必要があります。 @@ -152,28 +160,24 @@ opencode run "Hello world" ### TUI -`tui` オプションを使用して TUI 固有の設定を構成できます。 +TUI 固有の設定には、専用の `tui.json` (または `tui.jsonc`) ファイルを使用します。 -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", - "tui": { - "scroll_speed": 3, - "scroll_acceleration": { - "enabled": true - }, - "diff_style": "auto" - } + "$schema": "https://opencode.ai/tui.json", + "scroll_speed": 3, + "scroll_acceleration": { + "enabled": true + }, + "diff_style": "auto" } ``` -利用可能なオプション: +カスタム TUI 設定ファイルを指定するには、`OPENCODE_TUI_CONFIG` を使用します。 -- `scroll_acceleration.enabled` - macOS スタイルのスクロールアクセラレーションを有効にします。 **`scroll_speed` よりも優先されます。** -- `scroll_speed` - カスタムのスクロール速度乗数 (デフォルト: `3`、最小: `1`)。 `scroll_acceleration.enabled` が `true` の場合は無視されます。 -- `diff_style` - 差分レンダリングを制御します。 `"auto"` はターミナルの幅に適応し、`"stacked"` は常に 1 列を表示します。 +`opencode.json` 内の従来の `theme`、`keybinds`、および `tui` キーは非推奨となり、可能であれば自動的に移行されます。 -[TUI の使用方法の詳細については、こちら](/docs/tui) をご覧ください。 +[TUI の設定の詳細については、こちら](/docs/tui#configure) をご覧ください。 --- @@ -237,7 +241,7 @@ LLM が使用できるツールは、`tools` オプションを通じて管理 } ``` -`small_model` オプションは、タイトル生成などの軽量タスク用に別のモデルを構成します。デフォルトでは、OpenCode は、プロバイダーから安価なモデルが入手可能な場合は、より安価なモデルを使用しようとします。そうでない場合は、メインモデルにフォールバックします。 +`small_model` オプションは、タイトルの生成などの軽量タスク用に個別のモデルを構成します。デフォルトでは、OpenCode は、プロバイダーから安価なモデルが入手可能な場合は、より安価なモデルを使用しようとします。そうでない場合は、メインモデルにフォールバックします。 プロバイダーオプションには、`timeout` および `setCacheKey` を含めることができます。 @@ -258,7 +262,7 @@ LLM が使用できるツールは、`tools` オプションを通じて管理 - `timeout` - リクエストのタイムアウト (ミリ秒単位) (デフォルト: 300000)。無効にするには、`false` に設定します。 - `setCacheKey` - 指定されたプロバイダーに対してキャッシュキーが常に設定されていることを確認します。 -[ローカルモデル](/docs/models#local). [詳細はこちら](/docs/models)。 +[ローカルモデル](/docs/models#local) も設定できます。[詳細はこちら](/docs/models)。 --- @@ -290,21 +294,21 @@ Amazon Bedrock は、AWS 固有の設定をサポートしています。 - `endpoint` - VPC エンドポイントのカスタムエンドポイント URL。これは、AWS 固有の用語を使用した汎用 `baseURL` オプションのエイリアスです。両方を指定した場合は、`endpoint` が優先されます。 :::note -ベアラー トークン (`AWS_BEARER_TOKEN_BEDROCK` または `/connect`) は、プロファイルベースの認証より優先されます。詳細については、「認証優先順位](/docs/providers#authentication-precedence)」を参照してください。 +ベアラー トークン (`AWS_BEARER_TOKEN_BEDROCK` または `/connect`) は、プロファイルベースの認証より優先されます。詳細については、「[認証優先順位](/docs/providers#authentication-precedence)」を参照してください。 ::: -[Amazon Bedrock 設定 ](/docs/providers#amazon-bedrock) の詳細をご覧ください。 +[Amazon Bedrock 設定](/docs/providers#amazon-bedrock) の詳細をご覧ください。 --- ### テーマ -`theme` オプションを使用して、OpenCode 設定で使用するテーマを構成できます。 +UI テーマを `tui.json` で設定します。 -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", - "theme": "" + "$schema": "https://opencode.ai/tui.json", + "theme": "tokyonight" } ``` @@ -404,11 +408,11 @@ Amazon Bedrock は、AWS 固有の設定をサポートしています。 ### キーバインド -`keybinds` オプションを使用してキーバインドをカスタマイズできます。 +`tui.json` でキーバインドをカスタマイズします。 -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "keybinds": {} } ``` diff --git a/packages/web/src/content/docs/ja/custom-tools.mdx b/packages/web/src/content/docs/ja/custom-tools.mdx index badf50c627..2377fc7730 100644 --- a/packages/web/src/content/docs/ja/custom-tools.mdx +++ b/packages/web/src/content/docs/ja/custom-tools.mdx @@ -79,6 +79,32 @@ export const multiply = tool({ --- +#### 組み込みツールとの名前の衝突 + +カスタムツールはツール名でキー設定されます。カスタムツールが組み込みツールと同じ名前を使用する場合、カスタムツールが優先されます。 + +たとえば、このファイルは組み込みの `bash` ツールを置き換えます。 + +```ts title=".opencode/tools/bash.ts" +import { tool } from "@opencode-ai/plugin" + +export default tool({ + description: "Restricted bash wrapper", + args: { + command: tool.schema.string(), + }, + async execute(args) { + return `blocked: ${args.command}` + }, +}) +``` + +:::note +組み込みツールを意図的に置き換えたい場合を除き、一意の名前を使用することをお勧めします。組み込みツールを無効にしたいがオーバーライドしたくない場合は、[権限](/docs/permissions) を使用してください。 +::: + +--- + ### 引数 引数の型を定義するには、`tool.schema` (つまり [Zod](https://zod.dev)) を使用できます。 diff --git a/packages/web/src/content/docs/ja/ecosystem.mdx b/packages/web/src/content/docs/ja/ecosystem.mdx index 479fdfbdc3..b1a24a7dbf 100644 --- a/packages/web/src/content/docs/ja/ecosystem.mdx +++ b/packages/web/src/content/docs/ja/ecosystem.mdx @@ -8,44 +8,47 @@ OpenCode に基づいて構築されたコミュニティプロジェクトの :::note OpenCode 関連プロジェクトをこのリストに追加したいですか? PR を送信してください。 ::: + [awesome-opencode](https://github.com/awesome-opencode/awesome-opencode) および [opencode.cafe](https://opencode.cafe) もチェックしてください。 --- ## プラグイン -| 名前 | 説明 | -| --------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- | -| [opencode-daytona](https://github.com/jamesmurdza/daytona/blob/main/guides/typescript/opencode/README.md) | git sync とライブプレビューを使用して、隔離された Daytona サンドボックスで OpenCode セッションを自動的に実行します。 | -| [opencode-helicone-session](https://github.com/H2Shami/opencode-helicone-session) | リクエストのグループ化のために Helicone セッションヘッダーを自動的に挿入する | -| [opencode-type-inject](https://github.com/nick-vi/opencode-type-inject) | ルックアップツールを使用して TypeScript/Svelte 型をファイル読み取りに自動挿入する | -| [opencode-openai-codex-auth](https://github.com/numman-ali/opencode-openai-codex-auth) | API クレジットの代わりに ChatGPT Plus/Pro サブスクリプションを使用する | -| [opencode-gemini-auth](https://github.com/jenslys/opencode-gemini-auth) | API 課金の代わりに既存の Gemini プランを使用する | -| [opencode-antigravity-auth](https://github.com/NoeFabris/opencode-antigravity-auth) | API 課金の代わりに Antigravity の無料モデルを使用する | -| [opencode-devcontainers](https://github.com/athal7/opencode-devcontainers) | 浅いクローンと自動割り当てポートを使用したマルチブランチ devcontainer の分離 | -| [opencode-google-antigravity-auth](https://github.com/shekohex/opencode-google-antigravity-auth) | Google Antigravity OAuth プラグイン、Google 検索のサポート、およびより堅牢な API 処理 | -| [opencode-dynamic-context-pruning](https://github.com/Tarquinen/opencode-dynamic-context-pruning) | 古いツールの出力を削除してトークンの使用を最適化する | -| [opencode-websearch-cited](https://github.com/ghoulr/opencode-websearch-cited.git) | Google ベースのスタイルでサポートされているプロバイダーにネイティブ Web 検索サポートを追加 | -| [opencode-pty](https://github.com/shekohex/opencode-pty.git) | AI エージェントが PTY でバックグラウンドプロセスを実行し、インタラクティブな入力を送信できるようにします。 | -| [opencode-shell-strategy](https://github.com/JRedeker/opencode-shell-strategy) | 非対話型シェルコマンドの手順 - TTY に依存する操作によるハングの防止 | -| [opencode-wakatime](https://github.com/angristan/opencode-wakatime) | wakatime で OpenCode の使用状況を追跡する | -| [opencode-md-table-formatter](https://github.com/franlol/opencode-md-table-formatter/tree/main) | LLM によって生成された Markdown テーブルをクリーンアップする | -| [opencode-morph-fast-apply](https://github.com/JRedeker/opencode-morph-fast-apply) | Morph Fast apply API と遅延編集マーカーにより 10 倍高速なコード編集 | -| [oh-my-opencode](https://github.com/code-yeongyu/oh-my-opencode) | バックグラウンドエージェント、事前構築された LSP/AST/MCP ツール、厳選されたエージェント、Claude Code 互換 | -| [opencode-notificator](https://github.com/panta82/opencode-notificator) | OpenCode セッションのデスクトップ通知とサウンドアラート | -| [opencode-notifier](https://github.com/mohak34/opencode-notifier) | 許可、完了、エラーイベントのデスクトップ通知とサウンドアラート | -| [opencode-zellij-namer](https://github.com/24601/opencode-zellij-namer) | OpenCode コンテキストに基づいた AI による自動 Zellij セッション命名 | -| [opencode-skillful](https://github.com/zenobi-us/opencode-skillful) | OpenCode エージェントがスキルの検出と挿入を使用してオンデマンドでプロンプトを遅延ロードできるようにする | -| [opencode-supermemory](https://github.com/supermemoryai/opencode-supermemory) | スーパーメモリを使用したセッション間での永続メモリ | -| [@plannotator/opencode](https://github.com/backnotprop/plannotator/tree/main/apps/opencode-plugin) | 視覚的な注釈とプライベート/オフライン共有による対話型の計画レビュー | -| [@openspoon/subtask2](https://github.com/spoons-and-mirrors/subtask2) | OpenCode/コマンドをきめ細かいフロー制御を備えた強力なオーケストレーションシステムに拡張 | -| [opencode-scheduler](https://github.com/different-ai/opencode-scheduler) | launchd (Mac) または systemd (Linux) を cron 構文で使用して、定期的なジョブをスケジュールする | -| [micode](https://github.com/vtemian/micode) | 構造化されたブレインストーミング → 計画 → セッション継続性のあるワークフローの実装 | -| [octto](https://github.com/vtemian/octto) | 複数の質問フォームを使用した AI ブレインストーミング用のインタラクティブなブラウザ UI | -| [opencode-background-agents](https://github.com/kdcokenny/opencode-background-agents) | 非同期委任とコンテキスト永続性を備えた Claude Code スタイルのバックグラウンドエージェント | -| [opencode-notify](https://github.com/kdcokenny/opencode-notify) | OpenCode のネイティブ OS 通知 – タスクがいつ完了したかを知る | -| [opencode-workspace](https://github.com/kdcokenny/opencode-workspace) | バンドルされたマルチエージェントオーケストレーションハーネス – 16 コンポーネント、1 回のインストール | -| [opencode-worktree](https://github.com/kdcokenny/opencode-worktree) | OpenCode 用のゼロフリクション Git ワークツリー | +| 名前 | 説明 | +| -------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- | +| [opencode-daytona](https://github.com/daytonaio/daytona/tree/main/libs/opencode-plugin) | git sync とライブプレビューを使用して、隔離された Daytona サンドボックスで OpenCode セッションを自動的に実行します。 | +| [opencode-helicone-session](https://github.com/H2Shami/opencode-helicone-session) | リクエストのグループ化のために Helicone セッションヘッダーを自動的に挿入する | +| [opencode-type-inject](https://github.com/nick-vi/opencode-type-inject) | ルックアップツールを使用して TypeScript/Svelte 型をファイル読み取りに自動挿入する | +| [opencode-openai-codex-auth](https://github.com/numman-ali/opencode-openai-codex-auth) | API クレジットの代わりに ChatGPT Plus/Pro サブスクリプションを使用する | +| [opencode-gemini-auth](https://github.com/jenslys/opencode-gemini-auth) | API 課金の代わりに既存の Gemini プランを使用する | +| [opencode-antigravity-auth](https://github.com/NoeFabris/opencode-antigravity-auth) | API 課金の代わりに Antigravity の無料モデルを使用する | +| [opencode-devcontainers](https://github.com/athal7/opencode-devcontainers) | 浅いクローンと自動割り当てポートを使用したマルチブランチ devcontainer の分離 | +| [opencode-google-antigravity-auth](https://github.com/shekohex/opencode-google-antigravity-auth) | Google Antigravity OAuth プラグイン、Google 検索のサポート、およびより堅牢な API 処理 | +| [opencode-dynamic-context-pruning](https://github.com/Tarquinen/opencode-dynamic-context-pruning) | 古いツールの出力を削除してトークンの使用を最適化する | +| [opencode-vibeguard](https://github.com/inkdust2021/opencode-vibeguard) | LLM 呼び出しの前にシークレット/PII を VibeGuard スタイルのプレースホルダーに編集し、ローカルで復元する | +| [opencode-websearch-cited](https://github.com/ghoulr/opencode-websearch-cited.git) | Google ベースのスタイルでサポートされているプロバイダーにネイティブ Web 検索サポートを追加 | +| [opencode-pty](https://github.com/shekohex/opencode-pty.git) | AI エージェントが PTY でバックグラウンドプロセスを実行し、インタラクティブな入力を送信できるようにします。 | +| [opencode-shell-strategy](https://github.com/JRedeker/opencode-shell-strategy) | 非対話型シェルコマンドの手順 - TTY に依存する操作によるハングの防止 | +| [opencode-wakatime](https://github.com/angristan/opencode-wakatime) | wakatime で OpenCode の使用状況を追跡する | +| [opencode-md-table-formatter](https://github.com/franlol/opencode-md-table-formatter/tree/main) | LLM によって生成された Markdown テーブルをクリーンアップする | +| [opencode-morph-fast-apply](https://github.com/JRedeker/opencode-morph-fast-apply) | Morph Fast apply API と遅延編集マーカーにより 10 倍高速なコード編集 | +| [oh-my-opencode](https://github.com/code-yeongyu/oh-my-opencode) | バックグラウンドエージェント、事前構築された LSP/AST/MCP ツール、厳選されたエージェント、Claude Code 互換 | +| [opencode-notificator](https://github.com/panta82/opencode-notificator) | OpenCode セッションのデスクトップ通知とサウンドアラート | +| [opencode-notifier](https://github.com/mohak34/opencode-notifier) | 許可、完了、エラーイベントのデスクトップ通知とサウンドアラート | +| [opencode-zellij-namer](https://github.com/24601/opencode-zellij-namer) | OpenCode コンテキストに基づいた AI による自動 Zellij セッション命名 | +| [opencode-skillful](https://github.com/zenobi-us/opencode-skillful) | OpenCode エージェントがスキルの検出と挿入を使用してオンデマンドでプロンプトを遅延ロードできるようにする | +| [opencode-supermemory](https://github.com/supermemoryai/opencode-supermemory) | スーパーメモリを使用したセッション間での永続メモリ | +| [@plannotator/opencode](https://github.com/backnotprop/plannotator/tree/main/apps/opencode-plugin) | 視覚的な注釈とプライベート/オフライン共有による対話型の計画レビュー | +| [@openspoon/subtask2](https://github.com/spoons-and-mirrors/subtask2) | OpenCode/コマンドをきめ細かいフロー制御を備えた強力なオーケストレーションシステムに拡張 | +| [opencode-scheduler](https://github.com/different-ai/opencode-scheduler) | launchd (Mac) または systemd (Linux) を cron 構文で使用して、定期的なジョブをスケジュールする | +| [micode](https://github.com/vtemian/micode) | 構造化されたブレインストーミング → 計画 → セッション継続性のあるワークフローの実装 | +| [octto](https://github.com/vtemian/octto) | 複数の質問フォームを使用した AI ブレインストーミング用のインタラクティブなブラウザ UI | +| [opencode-background-agents](https://github.com/kdcokenny/opencode-background-agents) | 非同期委任とコンテキスト永続性を備えた Claude Code スタイルのバックグラウンドエージェント | +| [opencode-notify](https://github.com/kdcokenny/opencode-notify) | OpenCode のネイティブ OS 通知 – タスクがいつ完了したかを知る | +| [opencode-workspace](https://github.com/kdcokenny/opencode-workspace) | バンドルされたマルチエージェントオーケストレーションハーネス – 16 コンポーネント、1 回のインストール | +| [opencode-worktree](https://github.com/kdcokenny/opencode-worktree) | OpenCode 用のゼロフリクション Git ワークツリー | +| [opencode-sentry-monitor](https://github.com/stolinski/opencode-sentry-monitor) | Sentry AI Monitoring を使用して AI エージェントをトレースおよびデバッグする | --- diff --git a/packages/web/src/content/docs/ja/formatters.mdx b/packages/web/src/content/docs/ja/formatters.mdx index 26bcbb5de5..8769b9760d 100644 --- a/packages/web/src/content/docs/ja/formatters.mdx +++ b/packages/web/src/content/docs/ja/formatters.mdx @@ -13,31 +13,32 @@ OpenCode には、一般的な言語およびフレームワーク用のいく | Formatter | Extensions | Requirements | | -------------------- | -------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- | -| gofmt | .go | `gofmt` command available | -| mix | .ex, .exs, .eex, .heex, .leex, .neex, .sface | `mix` command available | -| prettier | .js, .jsx, .ts, .tsx, .html, .css, .md, .json, .yaml, and [more](https://prettier.io/docs/en/index.html) | `prettier` dependency in `package.json` | -| biome | .js, .jsx, .ts, .tsx, .html, .css, .md, .json, .yaml, and [more](https://biomejs.dev/) | `biome.json(c)` config file | -| zig | .zig, .zon | `zig` command available | -| clang-format | .c, .cpp, .h, .hpp, .ino, and [more](https://clang.llvm.org/docs/ClangFormat.html) | `.clang-format` config file | -| ktlint | .kt, .kts | `ktlint` command available | -| ruff | .py, .pyi | `ruff` command available with config | -| rustfmt | .rs | `rustfmt` command available | -| cargofmt | .rs | `cargo fmt` command available | -| uv | .py, .pyi | `uv` command available | -| rubocop | .rb, .rake, .gemspec, .ru | `rubocop` command available | -| standardrb | .rb, .rake, .gemspec, .ru | `standardrb` command available | -| htmlbeautifier | .erb, .html.erb | `htmlbeautifier` command available | | air | .R | `air` command available | +| biome | .js, .jsx, .ts, .tsx, .html, .css, .md, .json, .yaml, and [more](https://biomejs.dev/) | `biome.json(c)` config file | +| cargofmt | .rs | `cargo fmt` command available | +| clang-format | .c, .cpp, .h, .hpp, .ino, and [more](https://clang.llvm.org/docs/ClangFormat.html) | `.clang-format` config file | +| cljfmt | .clj, .cljs, .cljc, .edn | `cljfmt` command available | | dart | .dart | `dart` command available | | dfmt | .d | `dfmt` command available | -| ocamlformat | .ml, .mli | `ocamlformat` command available and `.ocamlformat` config file | -| terraform | .tf, .tfvars | `terraform` command available | | gleam | .gleam | `gleam` command available | +| gofmt | .go | `gofmt` command available | +| htmlbeautifier | .erb, .html.erb | `htmlbeautifier` command available | +| ktlint | .kt, .kts | `ktlint` command available | +| mix | .ex, .exs, .eex, .heex, .leex, .neex, .sface | `mix` command available | | nixfmt | .nix | `nixfmt` command available | -| shfmt | .sh, .bash | `shfmt` command available | -| pint | .php | `laravel/pint` dependency in `composer.json` | -| oxfmt (Experimental) | .js, .jsx, .ts, .tsx | `oxfmt` dependency in `package.json` and an [experimental env variable flag](/docs/cli/#experimental) | +| ocamlformat | .ml, .mli | `ocamlformat` command available and `.ocamlformat` config file | | ormolu | .hs | `ormolu` command available | +| oxfmt (Experimental) | .js, .jsx, .ts, .tsx | `oxfmt` dependency in `package.json` and an [experimental env variable flag](/docs/cli/#experimental) | +| pint | .php | `laravel/pint` dependency in `composer.json` | +| prettier | .js, .jsx, .ts, .tsx, .html, .css, .md, .json, .yaml, and [more](https://prettier.io/docs/en/index.html) | `prettier` dependency in `package.json` | +| rubocop | .rb, .rake, .gemspec, .ru | `rubocop` command available | +| ruff | .py, .pyi | `ruff` command available with config | +| rustfmt | .rs | `rustfmt` command available | +| shfmt | .sh, .bash | `shfmt` command available | +| standardrb | .rb, .rake, .gemspec, .ru | `standardrb` command available | +| terraform | .tf, .tfvars | `terraform` command available | +| uv | .py, .pyi | `uv` command available | +| zig | .zig, .zon | `zig` command available | したがって、プロジェクトの `prettier` に `package.json` が含まれている場合、OpenCode は自動的にそれを使用します。 diff --git a/packages/web/src/content/docs/ja/go.mdx b/packages/web/src/content/docs/ja/go.mdx new file mode 100644 index 0000000000..17ec4acb93 --- /dev/null +++ b/packages/web/src/content/docs/ja/go.mdx @@ -0,0 +1,145 @@ +--- +title: Go +description: オープンコーディングモデル向けの低価格サブスクリプション。 +--- + +import config from "../../../../config.mjs" +export const console = config.console +export const email = `mailto:${config.email}` + +OpenCode Goは、人気のあるオープンコーディングモデルへの信頼性の高いアクセスを提供する、低価格な**月額10ドル**のサブスクリプションです。 + +:::note +OpenCode Goは現在ベータ版です。 +::: + +GoはOpenCodeの他のプロバイダーと同様に機能します。OpenCode Goに登録してAPIキーを取得します。これは**完全にオプション**であり、OpenCodeを使用するために必須ではありません。 + +主に海外ユーザー向けに設計されており、安定したグローバルアクセスのためにモデルは米国、EU、シンガポールでホストされています。 + +--- + +## 背景 + +オープンモデルは非常に高性能になりました。現在では、コーディングタスクにおいてプロプライエタリモデルに近いパフォーマンスを発揮します。また、多くのプロバイダーが競争力のある価格で提供できるため、通常はずっと安価です。 + +しかし、信頼性が高く低遅延なアクセスを得ることは難しい場合があります。プロバイダーによって品質や可用性が異なるためです。 + +:::tip +OpenCodeとうまく連携する厳選されたモデルとプロバイダーをテストしました。 +::: + +これを解決するために、私たちはいくつかのことを行いました。 + +1. 厳選されたオープンモデルをテストし、それらを最適に実行する方法についてチームと話し合いました。 +2. 次に、いくつかのプロバイダーと協力して、これらが正しく提供されていることを確認しました。 +3. 最後に、モデルとプロバイダーの組み合わせをベンチマークし、自信を持って推奨できるリストを作成しました。 + +OpenCode Goでは、これらのモデルに**月額10ドル**でアクセスできます。 + +--- + +## 仕組み + +OpenCode GoはOpenCodeの他のプロバイダーと同様に機能します。 + +1. **<a href={console}>OpenCode Zen</a>**にサインインし、Goに登録してAPIキーをコピーします。 +2. TUIで`/connect`コマンドを実行し、`OpenCode Go`を選択してAPIキーを貼り付けます。 +3. TUIで`/models`を実行して、Go経由で利用可能なモデルのリストを確認します。 + +:::note +ワークスペースごとに1人のメンバーのみがOpenCode Goに登録できます。 +::: + +現在のモデルリストには以下が含まれます: + +- **GLM-5** +- **Kimi K2.5** +- **MiniMax M2.5** + +モデルのリストは、テストや新しいモデルの追加に伴い変更される可能性があります。 + +--- + +## 利用制限 + +OpenCode Goには以下の制限が含まれます: + +- **5時間制限** — 12ドル分の利用 +- **週間制限** — 30ドル分の利用 +- **月間制限** — 60ドル分の利用 + +制限は金額で定義されています。つまり、実際のリクエスト数は使用するモデルによって異なります。MiniMax M2.5のような安価なモデルではより多くのリクエストが可能ですが、GLM-5のような高価なモデルでは少なくなります。 + +下の表は、典型的なGoの使用パターンに基づいた推定リクエスト数を示しています: + +| | GLM-5 | Kimi K2.5 | MiniMax M2.5 | +| ------------------------- | ----- | --------- | ------------ | +| 5時間あたりのリクエスト数 | 1,150 | 1,850 | 30,000 | +| 週間リクエスト数 | 2,880 | 4,630 | 75,000 | +| 月間リクエスト数 | 5,750 | 9,250 | 150,000 | + +推定値は、観測された平均的なリクエストパターンに基づいています: + +- GLM-5 — 1リクエストあたり入力700、キャッシュ52,000、出力150トークン +- Kimi K2.5 — 1リクエストあたり入力870、キャッシュ55,000、出力200トークン +- MiniMax M2.5 — 1リクエストあたり入力300、キャッシュ55,000、出力125トークン + +現在の使用状況は**<a href={console}>コンソール</a>**で確認できます。 + +:::tip +利用制限に達した場合でも、無料モデルを引き続き使用できます。 +::: + +利用制限は、初期の使用状況やフィードバックに基づいて変更される可能性があります。 + +--- + +### 価格 + +OpenCode Goは**月額10ドル**のサブスクリプションプランです。以下は**100万トークンあたり**の価格です。 + +| モデル | 入力 | 出力 | キャッシュ読み込み | +| ------------ | ----- | ----- | ------------------ | +| GLM-5 | $1.00 | $3.20 | $0.20 | +| Kimi K2.5 | $0.60 | $3.00 | $0.10 | +| MiniMax M2.5 | $0.30 | $1.20 | $0.03 | + +--- + +### 制限を超えた利用 + +Zen残高にクレジットがある場合、コンソールで**残高を使用 (Use balance)**オプションを有効にできます。有効にすると、利用制限に達した後、リクエストをブロックする代わりにZen残高が使用されます。 + +--- + +## エンドポイント + +以下のAPIエンドポイントを通じてGoモデルにアクセスすることもできます。 + +| モデル | モデルID | エンドポイント | AI SDKパッケージ | +| ------------ | ------------ | ------------------------------------------------ | --------------------------- | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | + +OpenCode設定の[モデルID](/docs/config/#models)は、`opencode-go/<model-id>`という形式を使用します。たとえば、Kimi K2.5の場合、設定で`opencode-go/kimi-k2.5`を使用します。 + +--- + +## プライバシー + +このプランは主に海外ユーザー向けに設計されており、安定したグローバルアクセスのためにモデルは米国、EU、シンガポールでホストされています。 + +ご質問がある場合は<a href={email}>お問い合わせください</a>。 + +--- + +## 目標 + +OpenCode Goを作成した目的は以下の通りです: + +1. 低価格のサブスクリプションで、より多くの人々がAIコーディングに**アクセス**できるようにすること。 +2. 最高のオープンコーディングモデルへの**信頼性の高い**アクセスを提供すること。 +3. コーディングエージェントでの使用向けに**テストおよびベンチマーク**されたモデルを厳選すること。 +4. OpenCodeで他のプロバイダーも使用できるようにすることで、**ロックインを排除**すること。 diff --git a/packages/web/src/content/docs/ja/keybinds.mdx b/packages/web/src/content/docs/ja/keybinds.mdx index 66466a7f72..3ec9ca94d5 100644 --- a/packages/web/src/content/docs/ja/keybinds.mdx +++ b/packages/web/src/content/docs/ja/keybinds.mdx @@ -3,11 +3,11 @@ title: キーバインド description: キーバインドをカスタマイズします。 --- -OpenCode には、OpenCode 設定を通じてカスタマイズできるキーバインドのリストがあります。 +OpenCode には、`tui.json` を通じてカスタマイズできるキーバインドのリストがあります。 -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "keybinds": { "leader": "ctrl+x", "app_exit": "ctrl+c,ctrl+d,<leader>q", @@ -28,6 +28,7 @@ OpenCode には、OpenCode 設定を通じてカスタマイズできるキー "session_unshare": "none", "session_interrupt": "escape", "session_compact": "<leader>c", + "session_child_first": "<leader>down", "session_child_cycle": "<leader>right", "session_child_cycle_reverse": "<leader>left", "session_parent": "<leader>up", @@ -117,11 +118,11 @@ OpenCode は、ほとんどのキーバインドに `leader` キーを使用し ## キーバインドを無効にする -キーバインドを無効にするには、値「none」を指定してキーを構成に追加します。 +キーバインドを無効にするには、値「none」を指定してキーを `tui.json` に追加します。 -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "keybinds": { "session_compact": "none" } diff --git a/packages/web/src/content/docs/ja/lsp.mdx b/packages/web/src/content/docs/ja/lsp.mdx index 7b42c37332..948e743503 100644 --- a/packages/web/src/content/docs/ja/lsp.mdx +++ b/packages/web/src/content/docs/ja/lsp.mdx @@ -27,6 +27,7 @@ OpenCode には、一般的な言語用のいくつかの組み込み LSP サー | gopls | .go | `go` command available | | hls | .hs, .lhs | `haskell-language-server-wrapper` command available | | jdtls | .java | `Java SDK (version 21+)` installed | +| julials | .jl | `julia` and `LanguageServer.jl` installed | | kotlin-ls | .kt, .kts | Auto-installs for Kotlin projects | | lua-ls | .lua | Auto-installs for Lua projects | | nixd | .nix | `nixd` command available | diff --git a/packages/web/src/content/docs/ja/mcp-servers.mdx b/packages/web/src/content/docs/ja/mcp-servers.mdx index a4b2485337..3ac9edc811 100644 --- a/packages/web/src/content/docs/ja/mcp-servers.mdx +++ b/packages/web/src/content/docs/ja/mcp-servers.mdx @@ -16,7 +16,8 @@ MCP サーバーを使用すると、コンテキストが追加されます。 :::tip MCP サーバーはコンテキストに追加されるため、どのサーバーを有効にするかには注意してください。 ::: -特定の MCP サーバーは、大量のトークンを追加する傾向があり、コンテキスト制限を簡単に超える可能性があります。 + +特定の MCP サーバー (GitHub MCP サーバーなど) は、大量のトークンを追加する傾向があり、コンテキスト制限を簡単に超える可能性があります。 --- @@ -157,7 +158,7 @@ use the mcp_everything tool to add the number 3 and 4 | `url` | 文字列 | Y | リモート MCP サーバーの URL。 | | `enabled` | ブール値 | | 起動時に MCP サーバーを有効または無効にします。 | | `headers` | オブジェクト | | リクエストとともに送信するヘッダー。 | -| `oauth` | オブジェクト | | OAuth 認証設定。以下の「OAuth](#oauth)」セクションを参照してください。 | +| `oauth` | オブジェクト | | OAuth 認証設定。以下の「[OAuth](#oauth)」セクションを参照してください。 | | `timeout` | 数値 | | MCP サーバーからツールを取得する際のタイムアウト (ミリ秒)。デフォルトは 5000 (5 秒) です。 | --- @@ -391,6 +392,8 @@ MCP サーバーツールはサーバー名をプレフィックスとして登 ::: +--- + ## 例 以下に、一般的な MCP サーバーの例をいくつか示します。他のサーバーを文書化したい場合は、PR を送信できます。 @@ -506,471 +509,3 @@ What's the right way to set a custom domain in an SST Astro component? use the g ```md title="AGENTS.md" If you are unsure how to do something, use `gh_grep` to search code examples from GitHub. ``` - -`enabled` を `false` に設定してサーバーを無効にすることもできます。これは、サーバーを構成から削除せずに一時的に無効にする場合に便利です。 - ---- - -### リモートのデフォルトを上書きする - -組織は、`.well-known/opencode` エンドポイント経由でデフォルトの MCP サーバーを提供できます。これらのサーバーはデフォルトで無効になっている場合があり、ユーザーは必要なサーバーにオプトインできます。 - -組織のリモート構成から特定のサーバーを有効にするには、`enabled: true` を使用してローカル構成に追加します。 - -```json title="opencode.json" -{ - "$schema": "https://opencode.ai/config.json", - "mcp": { - "jira": { - "type": "remote", - "url": "https://jira.example.com/mcp", - "enabled": true - } - } -} -``` - -ローカルの設定値はリモートのデフォルト値をオーバーライドします。詳細については、「config precedence](/docs/config#precedence-order)」を参照してください。 - ---- - -## ローカル - -MCP オブジェクト内の `type` から `"local"` を使用してローカル MCP サーバーを追加します。 - -```jsonc title="opencode.jsonc" {15} -{ - "$schema": "https://opencode.ai/config.json", - "mcp": { - "my-local-mcp-server": { - "type": "local", - // Or ["bun", "x", "my-mcp-command"] - "command": ["npx", "-y", "my-mcp-command"], - "enabled": true, - "environment": { - "MY_ENV_VAR": "my_env_var_value", - }, - }, - }, -} -``` - -このコマンドは、ローカル MCP サーバーの起動方法を示します。環境変数のリストを渡すこともできます。 - -たとえば、テスト [`@modelcontextprotocol/server-everything`](https://www.npmjs.com/package/@modelcontextprotocol/server-everything) MCP サーバー] を追加する方法は次のとおりです。 - -```jsonc title="opencode.jsonc" -{ - "$schema": "https://opencode.ai/config.json", - "mcp": { - "mcp_everything": { - "type": "local", - "command": ["npx", "-y", "@modelcontextprotocol/server-everything"], - }, - }, -} -``` - -これを使用するには、プロンプトに `use the mcp_everything tool` を追加します。 - -```txt "mcp_everything" -use the mcp_everything tool to add the number 3 and 4 -``` - ---- - -#### オプション - -ここでは、ローカル MCP サーバーを構成するためのすべてのオプションを示します。 - -| オプション | タイプ | 必須 | 説明 | -| ------------- | ------------ | ---- | ------------------------------------------------------------------------------------------ | -| `type` | 文字列 | Y | MCP サーバー接続のタイプは、`"local"` である必要があります。 | -| `command` | 配列 | Y | MCP サーバーを実行するためのコマンドと引数。 | -| `environment` | オブジェクト | | サーバーの実行時に設定する環境変数。 | -| `enabled` | ブール値 | | 起動時に MCP サーバーを有効または無効にします。 | -| `timeout` | 番号 | | MCP サーバーからツールを取得する際のタイムアウト (ミリ秒)。デフォルトは 5000 (5 秒) です。 | - ---- - -## リモート - -`type` を `"remote"` に設定して、リモート MCP サーバーを追加します。 - -```json title="opencode.json" -{ - "$schema": "https://opencode.ai/config.json", - "mcp": { - "my-remote-mcp": { - "type": "remote", - "url": "https://my-mcp-server.com", - "enabled": true, - "headers": { - "Authorization": "Bearer MY_API_KEY" - } - } - } -} -``` - -`url` はリモート MCP サーバーの URL で、`headers` オプションを使用するとヘッダーのリストを渡すことができます。 - ---- - -#### オプション - -| オプション | タイプ | 必須 | 説明 | -| ---------- | ------------ | ---- | ------------------------------------------------------------------------------------------ | -| `type` | 文字列 | Y | MCP サーバー接続のタイプは、`"remote"` である必要があります。 | -| `url` | 文字列 | Y | リモート MCP サーバーの URL。 | -| `enabled` | ブール値 | | 起動時に MCP サーバーを有効または無効にします。 | -| `headers` | オブジェクト | | リクエストとともに送信するヘッダー。 | -| `oauth` | オブジェクト | | OAuth認証構成。以下の「OAuth](#oauth)」セクションを参照してください。 | -| `timeout` | 番号 | | MCP サーバーからツールを取得する際のタイムアウト (ミリ秒)。デフォルトは 5000 (5 秒) です。 | - ---- - -## OAuth - -OpenCode は、リモート MCP サーバーの OAuth 認証を自動的に処理します。サーバーが認証を必要とする場合、OpenCode は次のことを行います。 - -1. 401 応答を検出し、OAuth フローを開始します。 -2. サーバーでサポートされている場合は **動的クライアント登録 (RFC 7591)** を使用します -3. 今後のリクエストに備えてトークンを安全に保管する - ---- - -### 自動 - -ほとんどの OAuth 対応 MCP サーバーでは、特別な構成は必要ありません。リモートサーバーを設定するだけです。 - -```json title="opencode.json" -{ - "$schema": "https://opencode.ai/config.json", - "mcp": { - "my-oauth-server": { - "type": "remote", - "url": "https://mcp.example.com/mcp" - } - } -} -``` - -サーバーが認証を必要とする場合、OpenCode を初めて使用しようとすると、認証を求めるプロンプトが表示されます。そうでない場合は、`opencode mcp auth <server-name>` を使用して flow](#authenticating) を手動でトリガーできます。 - ---- - -### 事前登録済み - -MCP サーバープロバイダーからクライアント認証情報を取得している場合は、それらを構成できます。 - -```json title="opencode.json" {7-11} -{ - "$schema": "https://opencode.ai/config.json", - "mcp": { - "my-oauth-server": { - "type": "remote", - "url": "https://mcp.example.com/mcp", - "oauth": { - "clientId": "{env:MY_MCP_CLIENT_ID}", - "clientSecret": "{env:MY_MCP_CLIENT_SECRET}", - "scope": "tools:read tools:execute" - } - } - } -} -``` - ---- - -### 認証中 - -手動で認証をトリガーしたり、資格情報を管理したりできます。 - -特定の MCP サーバーで認証します。 - -```bash -opencode mcp auth my-oauth-server -``` - -すべての MCP サーバーとその認証ステータスをリストします。 - -```bash -opencode mcp list -``` - -保存されている認証情報を削除します。 - -```bash -opencode mcp logout my-oauth-server -``` - -`mcp auth` コマンドは、認証のためにブラウザを開きます。承認後、OpenCode はトークンを `~/.local/share/opencode/mcp-auth.json` に安全に保存します。 - ---- - -#### OAuthの無効化 - -サーバー (代わりに API キーを使用するサーバーなど) の自動 OAuth を無効にする場合は、`oauth` を `false` に設定します。 - -```json title="opencode.json" {7} -{ - "$schema": "https://opencode.ai/config.json", - "mcp": { - "my-api-key-server": { - "type": "remote", - "url": "https://mcp.example.com/mcp", - "oauth": false, - "headers": { - "Authorization": "Bearer {env:MY_API_KEY}" - } - } - } -} -``` - ---- - -#### OAuth オプション - -| オプション | タイプ | 説明 | -| -------------- | --------------- | -------------------------------------------------------------------------------- | -| `oauth` | Object \| false | OAuth config object, or `false` to disable OAuth auto-detection. | -| `clientId` | String | OAuth client ID. If not provided, dynamic client registration will be attempted. | -| `clientSecret` | String | OAuth client secret, if required by the authorization server. | -| `scope` | String | OAuth scopes to request during authorization. | - -#### デバッグ - -リモート MCP サーバーが認証に失敗した場合は、次の方法で問題を診断できます。 - -```bash -# View auth status for all OAuth-capable servers -opencode mcp auth list - -# Debug connection and OAuth flow for a specific server -opencode mcp debug my-oauth-server -``` - -`mcp debug` コマンドは、現在の認証ステータスを表示し、HTTP 接続をテストし、OAuth 検出フローを試行します。 - ---- - -## 管理 - -MCP は、組み込みツールと並んで、OpenCode のツールとして利用できます。したがって、他のツールと同様に、OpenCode config を通じてそれらを管理できます。 - ---- - -### グローバル - -これは、それらをグローバルに有効または無効にできることを意味します。 - -```json title="opencode.json" {14} -{ - "$schema": "https://opencode.ai/config.json", - "mcp": { - "my-mcp-foo": { - "type": "local", - "command": ["bun", "x", "my-mcp-command-foo"] - }, - "my-mcp-bar": { - "type": "local", - "command": ["bun", "x", "my-mcp-command-bar"] - } - }, - "tools": { - "my-mcp-foo": false - } -} -``` - -グロブ パターンを使用して、一致するすべての MCP を無効にすることもできます。 - -```json title="opencode.json" {14} -{ - "$schema": "https://opencode.ai/config.json", - "mcp": { - "my-mcp-foo": { - "type": "local", - "command": ["bun", "x", "my-mcp-command-foo"] - }, - "my-mcp-bar": { - "type": "local", - "command": ["bun", "x", "my-mcp-command-bar"] - } - }, - "tools": { - "my-mcp*": false - } -} -``` - -ここでは、グロブ パターン `my-mcp*` を使用して、すべての MCP を無効にしています。 - ---- - -### エージェントごと - -多数の MCP サーバーがある場合は、エージェントごとにのみ有効にし、グローバルに無効にすることができます。これを行うには: - -1. ツールとしてグローバルに無効にします。 -2. [エージェント config](/docs/agents#tools) で、MCP サーバーをツールとして有効にします。 - -```json title="opencode.json" {11, 14-18} -{ - "$schema": "https://opencode.ai/config.json", - "mcp": { - "my-mcp": { - "type": "local", - "command": ["bun", "x", "my-mcp-command"], - "enabled": true - } - }, - "tools": { - "my-mcp*": false - }, - "agent": { - "my-agent": { - "tools": { - "my-mcp*": true - } - } - } -} -``` - ---- - -#### グロブパターン - -グロブ パターンでは、単純な正規表現のグロブ パターンを使用します。 - -- `*` は 0 個以上の任意の文字に一致します (例: `"my-mcp*"` は `my-mcp_search`、`my-mcp_list` などに一致します)。 -- `?` は 1 つの文字に正確に一致します -- 他のすべての文字は文字通り一致します - -:::note -MCP サーバー ツールはサーバー名をプレフィックスとして登録されているため、サーバーのすべてのツールを無効にするには、次のコマンドを使用するだけです。 - -``` -"mymcpservername_*": false -``` - -::: - -## 例 - -以下に、一般的な MCP サーバーの例をいくつか示します。他のサーバーを文書化したい場合は、PR を送信できます。 - ---- - -### Sentry - -[Sentry MCP サーバー ](https://mcp.sentry.dev) を追加して、Sentry プロジェクトや問題と対話します。 - -```json title="opencode.json" {4-8} -{ - "$schema": "https://opencode.ai/config.json", - "mcp": { - "sentry": { - "type": "remote", - "url": "https://mcp.sentry.dev/mcp", - "oauth": {} - } - } -} -``` - -構成を追加した後、Sentry で認証します。 - -```bash -opencode mcp auth sentry -``` - -これにより、ブラウザ ウィンドウが開き、OAuth フローが完了し、OpenCode が Sentry アカウントに接続されます。 - -認証が完了すると、プロンプトで Sentry ツールを使用して、問題、プロジェクト、エラー データをクエリできるようになります。 - -```txt "use sentry" -Show me the latest unresolved issues in my project. use sentry -``` - ---- - -### Context7 - -ドキュメントを検索するために [Context7 MCP server](https://github.com/upstash/context7) を追加します。 - -```json title="opencode.json" {4-7} -{ - "$schema": "https://opencode.ai/config.json", - "mcp": { - "context7": { - "type": "remote", - "url": "https://mcp.context7.com/mcp" - } - } -} -``` - -無料アカウントにサインアップしている場合は、API キーを使用して、より高いレート制限を取得できます。 - -```json title="opencode.json" {7-9} -{ - "$schema": "https://opencode.ai/config.json", - "mcp": { - "context7": { - "type": "remote", - "url": "https://mcp.context7.com/mcp", - "headers": { - "CONTEXT7_API_KEY": "{env:CONTEXT7_API_KEY}" - } - } - } -} -``` - -ここでは、`CONTEXT7_API_KEY` 環境変数が設定されていることを前提としています。 - -Context7 MCP サーバーを使用するには、プロンプトに `use context7` を追加します。 - -```txt "use context7" -Configure a Cloudflare Worker script to cache JSON API responses for five minutes. use context7 -``` - -あるいは、次のようなものを [AGENTS.md](/docs/rules/). - -```md title="AGENTS.md" -When you need to search docs, use `context7` tools. -``` - ---- - -### Grep by Vercel - -GitHub 上のコード スニペットを検索するには、[Grep by Vercel](https://grep.app) MCP サーバーを追加します。 - -```json title="opencode.json" {4-7} -{ - "$schema": "https://opencode.ai/config.json", - "mcp": { - "gh_grep": { - "type": "remote", - "url": "https://mcp.grep.app" - } - } -} -``` - -MCP サーバーに `gh_grep` という名前を付けたので、プロンプトに `use the gh_grep tool` を追加して、エージェントにそれを使用させることができます。 - -```txt "use the gh_grep tool" -What's the right way to set a custom domain in an SST Astro component? use the gh_grep tool -``` - -あるいは、次のようなものを [AGENTS.md](/docs/rules/). - -```md title="AGENTS.md" -If you are unsure how to do something, use `gh_grep` to search code examples from GitHub. -``` diff --git a/packages/web/src/content/docs/ja/plugins.mdx b/packages/web/src/content/docs/ja/plugins.mdx index 39fc1dda21..06a0dca9ad 100644 --- a/packages/web/src/content/docs/ja/plugins.mdx +++ b/packages/web/src/content/docs/ja/plugins.mdx @@ -235,11 +235,87 @@ export const NotificationPlugin = async ({ project, client, $, directory, worktr macOS 上で AppleScript を実行するために `osascript` を使用しています。ここでは通知を送信するために使用しています。 :::note -OpenCode デスクトップアプリを使用している場合は、応答の準備ができたとき、またはセッションエラーが発生したときにシステム通知を自動的に送信できます。 +組み込みツールと同じ名前のプラグインツールを使用すると、プラグインツールが優先されます。 ::: --- +### ロギング + +構造化ログには `console.log` の代わりに `client.app.log()` を使用します。 + +```ts title=".opencode/plugins/my-plugin.ts" +export const MyPlugin = async ({ client }) => { + await client.app.log({ + body: { + service: "my-plugin", + level: "info", + message: "Plugin initialized", + extra: { foo: "bar" }, + }, + }) +} +``` + +レベル: `debug`、`info`、`warn`、`error`。詳細については、[SDK ドキュメント](https://opencode.ai/docs/sdk) を参照してください。 + +--- + +### 圧縮フック + +セッションが圧縮されたときに含まれるコンテキストをカスタマイズします。 + +```ts title=".opencode/plugins/compaction.ts" +import type { Plugin } from "@opencode-ai/plugin" + +export const CompactionPlugin: Plugin = async (ctx) => { + return { + "experimental.session.compacting": async (input, output) => { + // Inject additional context into the compaction prompt + output.context.push(` +## Custom Context + +Include any state that should persist across compaction: +- Current task status +- Important decisions made +- Files being actively worked on +`) + }, + } +} +``` + +`experimental.session.compacting` フックは、LLM が継続概要を生成する前に起動します。これを使用して、デフォルトの圧縮プロンプトでは見逃されるドメイン固有のコンテキストを挿入します。 + +`output.prompt` を設定することで、圧縮プロンプトを完全に置き換えることもできます。 + +```ts title=".opencode/plugins/custom-compaction.ts" +import type { Plugin } from "@opencode-ai/plugin" + +export const CustomCompactionPlugin: Plugin = async (ctx) => { + return { + "experimental.session.compacting": async (input, output) => { + // Replace the entire compaction prompt + output.prompt = ` +You are generating a continuation prompt for a multi-agent swarm session. + +Summarize: +1. The current task and its status +2. Which files are being modified and by whom +3. Any blockers or dependencies between agents +4. The next steps to complete the work + +Format as a structured prompt that a new agent can use to resume work. +` + }, + } +} +``` + +`output.prompt` を設定すると、デフォルトの圧縮プロンプトが完全に置き換えられます。この場合、`output.context` 配列は無視されます。 + +--- + ### .env の保護 OpenCode が `.env` ファイルを読み取らないようにします。 diff --git a/packages/web/src/content/docs/ja/providers.mdx b/packages/web/src/content/docs/ja/providers.mdx index 2602f8ef22..388dc8e41d 100644 --- a/packages/web/src/content/docs/ja/providers.mdx +++ b/packages/web/src/content/docs/ja/providers.mdx @@ -57,7 +57,38 @@ OpenCode で適切に動作することがテストおよび検証されてい 初めての方は、OpenCode Zen から始めることをお勧めします。 ::: -1. TUI で `/connect` コマンドを実行し、opencode を選択して、[opencode.ai/auth](https://opencode.ai/auth) で認証します。 +1. TUI で `/connect` コマンドを実行し、`OpenCode Zen` を選択して、[opencode.ai/zen](https://opencode.ai/zen) にアクセスします。 + + ```txt + /connect + ``` + +2. サインインし、お支払いの詳細を追加し、API キーをコピーします。 + +3. API キーを貼り付けます。 + + ```txt + ┌ API key + │ + │ + └ enter + ``` + +4. TUI で `/models` を実行すると、推奨されるモデルのリストが表示されます。 + + ```txt + /models + ``` + +これは OpenCode の他のプロバイダーと同様に機能し、使用は完全にオプションです。 + +--- + +## OpenCode Go + +OpenCode Go は、OpenCode チームによって提供される、人気のあるオープンコーディングモデルへの信頼性の高いアクセスを提供する低コストのサブスクリプションプランです。これらは OpenCode でうまく機能することがテストおよび検証されています。 + +1. TUI で `/connect` コマンドを実行し、`OpenCode Go` を選択して、[opencode.ai/zen](https://opencode.ai/zen) にアクセスします。 ```txt /connect @@ -126,105 +157,111 @@ OpenCode で適切に動作することがテストおよび検証されてい OpenCode で Amazon Bedrock を使用するには: -1. Amazon Bedrock コンソールの **モデルカタログ** に移動してリクエストします。 - 必要なモデルにアクセスします。 +1. Amazon Bedrock コンソールの **モデルカタログ** に移動し、必要なモデルへのアクセスをリクエストします。 -:::tip -Amazon Bedrock で必要なモデルにアクセスできる必要があります。 -::: + :::tip + Amazon Bedrock で必要なモデルにアクセスできる必要があります。 + ::: -2. **次のいずれかの方法を使用して認証を構成します**。 +2. **次のいずれかの方法を使用して認証を構成します**: + + *** #### 環境変数 (クイックスタート) -opencode の実行中に次の環境変数のいずれかを設定します。 + opencode の実行中に次の環境変数のいずれかを設定します。 -```bash - # Option 1: Using AWS access keys + ```bash + # オプション 1: AWS アクセスキーの使用 AWS_ACCESS_KEY_ID=XXX AWS_SECRET_ACCESS_KEY=YYY opencode - # Option 2: Using named AWS profile + # オプション 2: 名前付き AWS プロファイルの使用 AWS_PROFILE=my-profile opencode - # Option 3: Using Bedrock bearer token + # オプション 3: Bedrock ベアラートークンの使用 AWS_BEARER_TOKEN_BEDROCK=XXX opencode -``` + ``` -または、それらを bash プロファイルに追加します。 + または、それらを bash プロファイルに追加します。 -```bash title="~/.bash_profile" + ```bash title="~/.bash_profile" export AWS_PROFILE=my-dev-profile export AWS_REGION=us-east-1 -``` + ``` -#### 設定ファイル (推奨) + *** -プロジェクト固有の設定または永続的な設定の場合は、`opencode.json` を使用します。 + #### 設定ファイル (推奨) -```json title="opencode.json" -{ - "$schema": "https://opencode.ai/config.json", - "provider": { - "amazon-bedrock": { - "options": { - "region": "us-east-1", - "profile": "my-aws-profile" - } - } - } -} -``` + プロジェクト固有の設定または永続的な設定の場合は、`opencode.json` を使用します。 -**利用可能なオプション:** + ```json title="opencode.json" + { + "$schema": "https://opencode.ai/config.json", + "provider": { + "amazon-bedrock": { + "options": { + "region": "us-east-1", + "profile": "my-aws-profile" + } + } + } + } + ``` -- `region` - AWS リージョン (例: `us-east-1`、`eu-west-1`) -- `profile` - `~/.aws/credentials` からの AWS 名前付きプロファイル -- `endpoint` - VPC エンドポイントのカスタムエンドポイント URL (汎用 `baseURL` オプションのエイリアス) + **利用可能なオプション:** + - `region` - AWS リージョン (例: `us-east-1`、`eu-west-1`) + - `profile` - `~/.aws/credentials` からの AWS 名前付きプロファイル + - `endpoint` - VPC エンドポイントのカスタムエンドポイント URL (汎用 `baseURL` オプションのエイリアス) -:::tip -設定ファイルのオプションは環境変数より優先されます。 -::: + :::tip + 設定ファイルのオプションは環境変数より優先されます。 + ::: -#### 上級: VPC エンドポイント + *** -Bedrock の VPC エンドポイントを使用している場合: + #### 上級: VPC エンドポイント -```json title="opencode.json" -{ - "$schema": "https://opencode.ai/config.json", - "provider": { - "amazon-bedrock": { - "options": { - "region": "us-east-1", - "profile": "production", - "endpoint": "https://bedrock-runtime.us-east-1.vpce-xxxxx.amazonaws.com" - } - } - } -} -``` + Bedrock の VPC エンドポイントを使用している場合: -:::note -`endpoint` オプションは、AWS 固有の用語を使用した汎用の `baseURL` オプションのエイリアスです。 `endpoint` と `baseURL` の両方が指定された場合は、`endpoint` が優先されます。 -::: + ```json title="opencode.json" + { + "$schema": "https://opencode.ai/config.json", + "provider": { + "amazon-bedrock": { + "options": { + "region": "us-east-1", + "profile": "production", + "endpoint": "https://bedrock-runtime.us-east-1.vpce-xxxxx.amazonaws.com" + } + } + } + } + ``` -#### 認証方法 + :::note + `endpoint` オプションは、AWS 固有の用語を使用した汎用の `baseURL` オプションのエイリアスです。 `endpoint` と `baseURL` の両方が指定された場合は、`endpoint` が優先されます。 + ::: -- **`AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY`**: IAM ユーザーを作成し、AWS コンソールでアクセスキーを生成します。 -- **`AWS_PROFILE`**: `~/.aws/credentials` の名前付きプロファイルを使用します。最初に `aws configure --profile my-profile` または `aws sso login` を設定します -- **`AWS_BEARER_TOKEN_BEDROCK`**: Amazon Bedrock コンソールから長期 API キーを生成します -- **`AWS_WEB_IDENTITY_TOKEN_FILE` / `AWS_ROLE_ARN`**: EKS IRSA (サービスアカウントの IAM ロール) または OIDC フェデレーションを備えた他の Kubernetes 環境の場合。これらの環境変数は、サービスアカウントアノテーションを使用するときに Kubernetes によって自動的に挿入されます。 + *** -#### 認証の優先順位 + #### 認証方法 + - **`AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY`**: IAM ユーザーを作成し、AWS コンソールでアクセスキーを生成します + - **`AWS_PROFILE`**: `~/.aws/credentials` の名前付きプロファイルを使用します。最初に `aws configure --profile my-profile` または `aws sso login` を設定します + - **`AWS_BEARER_TOKEN_BEDROCK`**: Amazon Bedrock コンソールから長期 API キーを生成します + - **`AWS_WEB_IDENTITY_TOKEN_FILE` / `AWS_ROLE_ARN`**: EKS IRSA (サービスアカウントの IAM ロール) または OIDC フェデレーションを備えた他の Kubernetes 環境の場合。これらの環境変数は、サービスアカウントアノテーションを使用するときに Kubernetes によって自動的に挿入されます。 -Amazon Bedrock は次の認証優先度を使用します。 + *** -1. **ベアラー トークン** - `AWS_BEARER_TOKEN_BEDROCK` 環境変数または `/connect` コマンドからのトークン -2. **AWS 認証情報チェーン** - プロファイル、アクセスキー、共有認証情報、IAM ロール、Web ID トークン (EKS IRSA)、インスタンスメタデータ + #### 認証の優先順位 -:::note -ベアラー トークンが (`/connect` または `AWS_BEARER_TOKEN_BEDROCK` 経由で) 設定されると、設定されたプロファイルを含むすべての AWS 認証情報方法よりも優先されます。 -::: + Amazon Bedrock は次の認証優先度を使用します。 + 1. **ベアラー トークン** - `AWS_BEARER_TOKEN_BEDROCK` 環境変数または `/connect` コマンドからのトークン + 2. **AWS 認証情報チェーン** - プロファイル、アクセスキー、共有認証情報、IAM ロール、Web ID トークン (EKS IRSA)、インスタンスメタデータ + + :::note + ベアラー トークンが (`/connect` または `AWS_BEARER_TOKEN_BEDROCK` 経由で) 設定されると、設定されたプロファイルを含むすべての AWS 認証情報方法よりも優先されます。 + ::: 3. `/models` コマンドを実行して、必要なモデルを選択します。 @@ -234,6 +271,7 @@ Amazon Bedrock は次の認証優先度を使用します。 :::note カスタム推論プロファイルの場合、キーでモデルとプロバイダー名を使用し、`id` プロパティを arn に設定します。これにより、正しいキャッシュが保証されます。 +::: ```json title="opencode.json" { @@ -251,8 +289,6 @@ Amazon Bedrock は次の認証優先度を使用します。 } ``` -::: - --- ### Anthropic @@ -672,9 +708,42 @@ GitLab Duo は、GitLab の Anthropic プロキシを介したネイティブツ 6. `/models` コマンドを実行して、利用可能なモデルを確認します。 - ```txt - /models - ``` +```txt +/models +``` + +--- + +### STACKIT + +STACKIT AI Model Serving は、Llama、Mistral、Qwen などの LLM に焦点を当て、ヨーロッパのインフラストラクチャでの最大限のデータ主権を備えた、AI モデル用の完全に管理された主権ホスティング環境を提供します。 + +1. [STACKIT Portal](https://portal.stackit.cloud) に移動し、**AI Model Serving** に移動して、プロジェクトの認証トークンを作成します。 + + :::tip + 認証トークンを作成する前に、STACKIT 顧客アカウント、ユーザーアカウント、およびプロジェクトが必要です。 + ::: + +2. `/connect` コマンドを実行し、**STACKIT** を検索します。 + + ```txt + /connect + ``` + +3. STACKIT AI Model Serving 認証トークンを入力します。 + + ```txt + ┌ API key + │ + │ + └ enter + ``` + +4. `/models` コマンドを実行して、_Qwen3-VL 235B_ や _Llama 3.3 70B_ などの利用可能なモデルから選択します。 + + ```txt + /models + ``` 3 つの Claude ベースのモデルが利用可能です。 diff --git a/packages/web/src/content/docs/ja/sdk.mdx b/packages/web/src/content/docs/ja/sdk.mdx index ee5fd3645a..5afaeb4a13 100644 --- a/packages/web/src/content/docs/ja/sdk.mdx +++ b/packages/web/src/content/docs/ja/sdk.mdx @@ -117,6 +117,78 @@ try { --- +## 構造化出力 + +`format` を JSON スキーマで指定することで、モデルから構造化された JSON 出力をリクエストできます。モデルは `StructuredOutput` ツールを使用して、スキーマに一致する検証済み JSON を返します。 + +### 基本的な使用法 + +```typescript +const result = await client.session.prompt({ + path: { id: sessionId }, + body: { + parts: [{ type: "text", text: "Research Anthropic and provide company info" }], + format: { + type: "json_schema", + schema: { + type: "object", + properties: { + company: { type: "string", description: "Company name" }, + founded: { type: "number", description: "Year founded" }, + products: { + type: "array", + items: { type: "string" }, + description: "Main products", + }, + }, + required: ["company", "founded"], + }, + }, + }, +}) + +// Access the structured output +console.log(result.data.info.structured_output) +// { company: "Anthropic", founded: 2021, products: ["Claude", "Claude API"] } +``` + +### 出力フォーマットの種類 + +| タイプ | 説明 | +| ------------- | ---------------------------------------------------- | +| `text` | デフォルト。標準テキスト応答 (構造化出力なし) | +| `json_schema` | 提供されたスキーマに一致する検証済み JSON を返します | + +### JSON スキーマフォーマット + +`type: 'json_schema'` を使用する場合は、以下を指定します: + +| フィールド | タイプ | 説明 | +| ------------ | --------------- | -------------------------------------------------- | +| `type` | `'json_schema'` | 必須。JSON スキーマモードを指定します | +| `schema` | `object` | 必須。出力構造を定義する JSON スキーマオブジェクト | +| `retryCount` | `number` | オプション。検証の再試行回数 (デフォルト: 2) | + +### エラー処理 + +すべての再試行後にモデルが有効な構造化出力を生成できない場合、応答には `StructuredOutputError` が含まれます: + +```typescript +if (result.data.info.error?.name === "StructuredOutputError") { + console.error("Failed to produce structured output:", result.data.info.error.message) + console.error("Attempts:", result.data.info.error.retries) +} +``` + +### ベストプラクティス + +1. **明確な説明を提供する**: モデルが抽出するデータを理解できるように、スキーマプロパティに明確な説明を提供します +2. **`required` を使用する**: 存在する必要があるフィールドを指定します +3. **スキーマを焦点を絞ったものにする**: 複雑なネストされたスキーマは、モデルが正しく入力するのが難しい場合があります +4. **適切な `retryCount` を設定する**: 複雑なスキーマの場合は増やし、単純なスキーマの場合は減らします + +--- + ## API SDK は、型安全なクライアントを通じてすべてのサーバー API を公開します。 @@ -226,27 +298,27 @@ const { providers, default: defaults } = await client.config.providers() ### Sessions -| メソッド | 説明 | 詳細 | -| ---------------------------------------------------------- | --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `session.list()` | セッションをリストする | 戻り値 <a href={typesUrl}><code>Session[]</code></a> | -| `session.get({ path })` | セッションを取得 | 戻り値 <a href={typesUrl}><code>Session</code></a> | -| `session.children({ path })` | 子セッションをリストする | 戻り値 <a href={typesUrl}><code>Session[]</code></a> | -| `session.create({ body })` | セッションの作成 | 戻り値 <a href={typesUrl}><code>Session</code></a> | -| `session.delete({ path })` | セッションを削除 | 戻り値 `boolean` | -| `session.update({ path, body })` | セッションのプロパティを更新する | 戻り値 <a href={typesUrl}><code>Session</code></a> | -| `session.init({ path, body })` | アプリを分析して `AGENTS.md` を作成する | 戻り値 `boolean` | -| `session.abort({ path })` | 実行中のセッションを中止する | 戻り値 `boolean` | -| `session.share({ path })` | セッションを共有する | 戻り値 <a href={typesUrl}><code>Session</code></a> | -| `session.unshare({ path })` | セッションの共有を解除 | 戻り値 <a href={typesUrl}><code>Session</code></a> | -| `session.summarize({ path, body })` | セッションを要約する | 戻り値 `boolean` | -| `session.messages({ path })` | セッション内のメッセージをリストする | 戻り値 `{ info: `<a href={typesUrl}><code>Message</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}[]` | -| `session.message({ path })` | メッセージの詳細を取得する | 戻り値 `{ info: `<a href={typesUrl}><code>Message</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}` | -| `session.prompt({ path, body })` | プロンプトメッセージを送信する | `body.noReply: true` は UserMessage (コンテキストのみ) を返します。デフォルトでは、AI 応答を含む <a href={typesUrl}><code>AssistantMessage</code></a> を返します。 | -| `session.command({ path, body })` | コマンドをセッションに送信 | 戻り値 `{ info: `<a href={typesUrl}><code>AssistantMessage</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}` | -| `session.shell({ path, body })` | シェルコマンドを実行する | 戻り値 <a href={typesUrl}><code>AssistantMessage</code></a> | -| `session.revert({ path, body })` | メッセージを元に戻す | 戻り値 <a href={typesUrl}><code>Session</code></a> | -| `session.unrevert({ path })` | 元に戻したメッセージを復元する | 戻り値 <a href={typesUrl}><code>Session</code></a> | -| `postSessionByIdPermissionsByPermissionId({ path, body })` | 許可リクエストに応答する | 戻り値 `boolean` | +| メソッド | 説明 | 詳細 | +| ---------------------------------------------------------- | --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `session.list()` | セッションをリストする | 戻り値 <a href={typesUrl}><code>Session[]</code></a> | +| `session.get({ path })` | セッションを取得 | 戻り値 <a href={typesUrl}><code>Session</code></a> | +| `session.children({ path })` | 子セッションをリストする | 戻り値 <a href={typesUrl}><code>Session[]</code></a> | +| `session.create({ body })` | セッションの作成 | 戻り値 <a href={typesUrl}><code>Session</code></a> | +| `session.delete({ path })` | セッションを削除 | 戻り値 `boolean` | +| `session.update({ path, body })` | セッションのプロパティを更新する | 戻り値 <a href={typesUrl}><code>Session</code></a> | +| `session.init({ path, body })` | アプリを分析して `AGENTS.md` を作成する | 戻り値 `boolean` | +| `session.abort({ path })` | 実行中のセッションを中止する | 戻り値 `boolean` | +| `session.share({ path })` | セッションを共有する | 戻り値 <a href={typesUrl}><code>Session</code></a> | +| `session.unshare({ path })` | セッションの共有を解除 | 戻り値 <a href={typesUrl}><code>Session</code></a> | +| `session.summarize({ path, body })` | セッションを要約する | 戻り値 `boolean` | +| `session.messages({ path })` | セッション内のメッセージをリストする | 戻り値 `{ info: `<a href={typesUrl}><code>Message</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}[]` | +| `session.message({ path })` | メッセージの詳細を取得する | 戻り値 `{ info: `<a href={typesUrl}><code>Message</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}` | +| `session.prompt({ path, body })` | プロンプトメッセージを送信する | `body.noReply: true` は UserMessage (コンテキストのみ) を返します。デフォルトでは、AI 応答を含む <a href={typesUrl}><code>AssistantMessage</code></a> を返します。[構造化出力](#構造化出力) のための `body.outputFormat` をサポートします。 | +| `session.command({ path, body })` | コマンドをセッションに送信 | 戻り値 `{ info: `<a href={typesUrl}><code>AssistantMessage</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}` | +| `session.shell({ path, body })` | シェルコマンドを実行する | 戻り値 <a href={typesUrl}><code>AssistantMessage</code></a> | +| `session.revert({ path, body })` | メッセージを元に戻す | 戻り値 <a href={typesUrl}><code>Session</code></a> | +| `session.unrevert({ path })` | 元に戻したメッセージを復元する | 戻り値 <a href={typesUrl}><code>Session</code></a> | +| `postSessionByIdPermissionsByPermissionId({ path, body })` | 許可リクエストに応答する | 戻り値 `boolean` | --- diff --git a/packages/web/src/content/docs/ja/share.mdx b/packages/web/src/content/docs/ja/share.mdx index 7995ba9a07..606e807dc8 100644 --- a/packages/web/src/content/docs/ja/share.mdx +++ b/packages/web/src/content/docs/ja/share.mdx @@ -41,7 +41,7 @@ OpenCode は、会話の共有方法を制御する 3 つの共有モードを ```json title="opencode.json" { - "$schema": "https://opncd.ai/config.json", + "$schema": "https://opencode.ai/config.json", "share": "manual" } ``` @@ -54,7 +54,7 @@ OpenCode は、会話の共有方法を制御する 3 つの共有モードを ```json title="opencode.json" { - "$schema": "https://opncd.ai/config.json", + "$schema": "https://opencode.ai/config.json", "share": "auto" } ``` @@ -69,7 +69,7 @@ OpenCode は、会話の共有方法を制御する 3 つの共有モードを ```json title="opencode.json" { - "$schema": "https://opncd.ai/config.json", + "$schema": "https://opencode.ai/config.json", "share": "disabled" } ``` diff --git a/packages/web/src/content/docs/ja/themes.mdx b/packages/web/src/content/docs/ja/themes.mdx index dd76651d6a..1e4bf42180 100644 --- a/packages/web/src/content/docs/ja/themes.mdx +++ b/packages/web/src/content/docs/ja/themes.mdx @@ -61,11 +61,11 @@ OpenCode にはいくつかの組み込みテーマが付属しています。 ## テーマの使用 -テーマを選択するには、`/theme` コマンドでテーマ選択を表示します。または、[config](/docs/config) で設定します。 +テーマを選択するには、`/theme` コマンドでテーマ選択を表示します。または、`tui.json` で指定することもできます。 -```json title="opencode.json" {3} +```json title="tui.json" {3} { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "theme": "tokyonight" } ``` diff --git a/packages/web/src/content/docs/ja/tui.mdx b/packages/web/src/content/docs/ja/tui.mdx index 36c94fffcf..0049c7b014 100644 --- a/packages/web/src/content/docs/ja/tui.mdx +++ b/packages/web/src/content/docs/ja/tui.mdx @@ -349,24 +349,34 @@ VS Code などの一部のエディターは、`--wait` フラグを使用して ## 設定 -OpenCode 設定ファイルを通じて TUI の動作をカスタマイズできます。 +`tui.json` (または `tui.jsonc`) ファイルを通じて TUI の動作をカスタマイズできます。 -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", - "tui": { - "scroll_speed": 3, - "scroll_acceleration": { - "enabled": true - } - } + "$schema": "https://opencode.ai/tui.json", + "theme": "opencode", + "keybinds": { + "leader": "ctrl+x" + }, + "scroll_speed": 3, + "scroll_acceleration": { + "enabled": true + }, + "diff_style": "auto" } ``` +これは、サーバー/ランタイムの動作を構成する `opencode.json` とは別です。 + ### オプション -- `scroll_acceleration` - macOS スタイルのスクロールアクセラレーションを有効にして、スムーズで自然なスクロールを実現します。有効にすると、高速スクロールジェスチャではスクロール速度が向上し、ゆっくりとした動きでは正確なままになります。 **この設定は `scroll_speed` よりも優先され、有効になっている場合は上書きされます。** -- `scroll_speed` - スクロールコマンドを使用するときに TUI がスクロールする速度を制御します (最小: `1`)。デフォルトは `3` です。 **注: `scroll_acceleration.enabled` が `true` に設定されている場合、これは無視されます。** +- `theme` - UI テーマを設定します。[詳細はこちら](/docs/themes)。 +- `keybinds` - キーボードショートカットをカスタマイズします。[詳細はこちら](/docs/keybinds)。 +- `scroll_acceleration.enabled` - macOS スタイルのスクロールアクセラレーションを有効にして、スムーズで自然なスクロールを実現します。有効にすると、高速スクロールジェスチャではスクロール速度が向上し、ゆっくりとした動きでは正確なままになります。 **この設定は `scroll_speed` よりも優先され、有効になっている場合は上書きされます。** +- `scroll_speed` - スクロールコマンドを使用するときに TUI がスクロールする速度を制御します (最小: `0.001`、小数をサポート)。デフォルトは `3` です。 **注: `scroll_acceleration.enabled` が `true` に設定されている場合、これは無視されます。** +- `diff_style` - 差分レンダリングを制御します。 `"auto"` はターミナルの幅に適応し、`"stacked"` は常に 1 列のレイアウトを表示します。 + +カスタム TUI 設定パスをロードするには、`OPENCODE_TUI_CONFIG` を使用します。 --- diff --git a/packages/web/src/content/docs/ja/zen.mdx b/packages/web/src/content/docs/ja/zen.mdx index 751ca45e45..7a380aa9fb 100644 --- a/packages/web/src/content/docs/ja/zen.mdx +++ b/packages/web/src/content/docs/ja/zen.mdx @@ -18,23 +18,19 @@ Zen は OpenCode の他のプロバイダーと同様に機能します。 OpenC ## 背景 -モデルはたくさんありますが、そのうちのほんの一部です -これらのモデルはコーディングエージェントとしてうまく機能します。さらに、ほとんどのプロバイダーは、 -構成が大きく異なります。したがって、まったく異なるパフォーマンスと品質が得られます。 +世の中には多数のモデルがありますが、コーディングエージェントとしてうまく機能するのはごく一部です。さらに、ほとんどのプロバイダーは構成が大きく異なるため、パフォーマンスと品質も大きく異なります。 :::tip -私たちは、OpenCode で適切に動作するモデルとプロバイダーの選択されたグループをテストしました。 +OpenCode で適切に動作する、厳選されたモデルとプロバイダーのグループをテストしました。 ::: -OpenRouter などを通じてモデルを使用している場合は、決してそうすることはできません。 -必要なモデルの最高のバージョンを入手しているかどうかを確認してください。 + +OpenRouter などを通じてモデルを使用している場合、必要なモデルの最高のバージョンを取得できているか確信が持てません。 これを修正するために、いくつかのことを行いました。 -1. 私たちは選択したモデルのグループをテストし、その方法についてチームと話し合いました。 - それらを実行するのが最善です。 +1. 選抜したモデルグループをテストし、それらを最適に実行する方法についてチームと話し合いました。 2. その後、いくつかのプロバイダーと協力して、これらが確実に提供されるようにしました。 -3. 最後に、モデルとプロバイダーの組み合わせをベンチマークし、次の結果を導き出しました。 - 私たちが自信を持ってお勧めするリストをご紹介します。 +3. 最後に、モデルとプロバイダーの組み合わせをベンチマークし、自信を持ってお勧めできるリストを作成しました。 OpenCode Zen は、これらのモデルへのアクセスを可能にする AI ゲートウェイです。 @@ -44,8 +40,7 @@ OpenCode Zen は、これらのモデルへのアクセスを可能にする AI OpenCode Zen は、OpenCode の他のプロバイダーと同様に機能します。 -1. **<a href={console}>OpenCode Zen</a>** にログインし、請求内容を追加します - 詳細を確認し、API キーをコピーします。 +1. **<a href={console}>OpenCode Zen</a>** にサインインし、請求情報を追加して、API キーをコピーします。 2. TUI で `/connect` コマンドを実行し、OpenCode Zen を選択して API キーを貼り付けます。 3. TUI で `/models` を実行すると、推奨されるモデルのリストが表示されます。 @@ -59,6 +54,8 @@ OpenCode Zen は、OpenCode の他のプロバイダーと同様に機能しま | Model | Model ID | Endpoint | AI SDK Package | | ------------------ | ------------------ | -------------------------------------------------- | --------------------------- | +| GPT 5.4 | gpt-5.4 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| GPT 5.3 Codex | gpt-5.3-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.2 | gpt-5.2 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.2 Codex | gpt-5.2-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.1 | gpt-5.1 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | @@ -68,22 +65,24 @@ OpenCode Zen は、OpenCode の他のプロバイダーと同様に機能しま | GPT 5 | gpt-5 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5 Codex | gpt-5-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5 Nano | gpt-5-nano | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| Claude Opus 4.6 | claude-opus-4-6 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Opus 4.5 | claude-opus-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Opus 4.1 | claude-opus-4-1 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Sonnet 4.6 | claude-sonnet-4-6 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Sonnet 4.5 | claude-sonnet-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Sonnet 4 | claude-sonnet-4 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Haiku 4.5 | claude-haiku-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Haiku 3.5 | claude-3-5-haiku | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| Claude Opus 4.6 | claude-opus-4-6 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| Claude Opus 4.5 | claude-opus-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| Claude Opus 4.1 | claude-opus-4-1 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Gemini 3.1 Pro | gemini-3.1-pro | `https://opencode.ai/zen/v1/models/gemini-3.1-pro` | `@ai-sdk/google` | | Gemini 3 Pro | gemini-3-pro | `https://opencode.ai/zen/v1/models/gemini-3-pro` | `@ai-sdk/google` | | Gemini 3 Flash | gemini-3-flash | `https://opencode.ai/zen/v1/models/gemini-3-flash` | `@ai-sdk/google` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.5 Free | minimax-m2.5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.1 | minimax-m2.1 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.1 Free | minimax-m2.1-free | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| GLM 5 | glm-5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | GLM 4.7 | glm-4.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM 4.7 Free | glm-4.7-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | GLM 4.6 | glm-4.6 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 Free | kimi-k2.5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2 Thinking | kimi-k2-thinking | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2 | kimi-k2 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Qwen3 Coder 480B | qwen3-coder | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -112,29 +111,35 @@ https://opencode.ai/zen/v1/models | Model | Input | Output | Cached Read | Cached Write | | --------------------------------- | ------ | ------ | ----------- | ------------ | | Big Pickle | Free | Free | Free | - | -| MiniMax M2.1 Free | Free | Free | Free | - | +| MiniMax M2.5 Free | Free | Free | Free | - | +| MiniMax M2.5 | $0.30 | $1.20 | $0.06 | - | | MiniMax M2.1 | $0.30 | $1.20 | $0.10 | - | -| GLM 4.7 Free | Free | Free | Free | - | +| GLM 5 | $1.00 | $3.20 | $0.20 | - | | GLM 4.7 | $0.60 | $2.20 | $0.10 | - | | GLM 4.6 | $0.60 | $2.20 | $0.10 | - | -| Kimi K2.5 Free | Free | Free | Free | - | | Kimi K2.5 | $0.60 | $3.00 | $0.08 | - | | Kimi K2 Thinking | $0.40 | $2.50 | - | - | | Kimi K2 | $0.40 | $2.50 | - | - | | Qwen3 Coder 480B | $0.45 | $1.50 | - | - | +| Claude Opus 4.6 (≤ 200K tokens) | $5.00 | $25.00 | $0.50 | $6.25 | +| Claude Opus 4.6 (> 200K tokens) | $10.00 | $37.50 | $1.00 | $12.50 | +| Claude Opus 4.5 | $5.00 | $25.00 | $0.50 | $6.25 | +| Claude Opus 4.1 | $15.00 | $75.00 | $1.50 | $18.75 | +| Claude Sonnet 4.6 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 | +| Claude Sonnet 4.6 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 | | Claude Sonnet 4.5 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 | | Claude Sonnet 4.5 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 | | Claude Sonnet 4 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 | | Claude Sonnet 4 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 | | Claude Haiku 4.5 | $1.00 | $5.00 | $0.10 | $1.25 | | Claude Haiku 3.5 | $0.80 | $4.00 | $0.08 | $1.00 | -| Claude Opus 4.6 (≤ 200K tokens) | $5.00 | $25.00 | $0.50 | $6.25 | -| Claude Opus 4.6 (> 200K tokens) | $10.00 | $37.50 | $1.00 | $12.50 | -| Claude Opus 4.5 | $5.00 | $25.00 | $0.50 | $6.25 | -| Claude Opus 4.1 | $15.00 | $75.00 | $1.50 | $18.75 | +| Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | +| Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | | Gemini 3 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | +| GPT 5.4 | $2.50 | $15.00 | $0.25 | - | +| GPT 5.3 Codex | $1.75 | $14.00 | $0.175 | - | | GPT 5.2 | $1.75 | $14.00 | $0.175 | - | | GPT 5.2 Codex | $1.75 | $14.00 | $0.175 | - | | GPT 5.1 | $1.07 | $8.50 | $0.107 | - | @@ -151,10 +156,10 @@ https://opencode.ai/zen/v1/models クレジットカード手数料は実費で引き継がれます (4.4% + 取引ごとに 0.30 ドル)。それ以上の料金はかかりません。 ::: -- GLM 4.7 Free は期間限定で OpenCode で入手できます。チームはこの時間を利用してフィードバックを収集し、モデルを改善します。 -- Kim K2.5 Free は OpenCode で期間限定で利用可能です。チームはこの時間を利用してフィードバックを収集し、モデルを改善します。 -- MiniMax M2.1 Free は期間限定で OpenCode で入手できます。チームはこの時間を利用してフィードバックを収集し、モデルを改善します。 -- Big Pickle は、期間限定で OpenCode で無料で利用できるステルスモデルです。チームはこの時間を利用してフィードバックを収集し、モデルを改善します。 +無料のモデル: + +- MiniMax M2.5 Free は期間限定で OpenCode で利用可能です。チームはこの期間を利用してフィードバックを収集し、モデルを改善します。 +- Big Pickle は、期間限定で OpenCode で無料で利用できるステルスモデルです。チームはこの期間を利用してフィードバックを収集し、モデルを改善します。 ご質問がございましたら、<a href={email}>お問い合わせ</a>ください。 @@ -170,12 +175,22 @@ https://opencode.ai/zen/v1/models ### 月ごとの制限 -ワークスペース全体およびワークスペースごとに月ごとの使用制限を設定することもできます。 -あなたのチームのメンバー。 +ワークスペース全体およびチームの各メンバーの月ごとの使用制限を設定することもできます。 -たとえば、毎月の使用制限を 20 ドルに設定したとします。Zen は使用しません。 -月に20ドル以上。ただし、自動リロードを有効にしている場合、Zen が終了する可能性があります。 -残高が 5 ドルを下回ると、20 ドル以上の請求が行われます。 +たとえば、毎月の使用制限を 20 ドルに設定したとします。Zen は月に 20 ドル以上を使用しません。ただし、自動リロードを有効にしている場合、残高が 5 ドルを下回ると、Zen が 20 ドル以上の請求を行う可能性があります。 + +--- + +### 非推奨モデル + +| Model | Deprecation date | +| ---------------- | ---------------- | +| Qwen3 Coder 480B | 2026年2月6日 | +| Kimi K2 Thinking | 2026年3月6日 | +| Kimi K2 | 2026年3月6日 | +| MiniMax M2.1 | 2026年3月15日 | +| GLM 4.7 | 2026年3月15日 | +| GLM 4.6 | 2026年3月15日 | --- @@ -183,24 +198,22 @@ https://opencode.ai/zen/v1/models すべてのモデルは米国でホストされています。当社のプロバイダーはゼロ保持ポリシーに従い、次の例外を除いて、モデルのトレーニングにデータを使用しません。 -- Big Pickle: 無料期間中に、収集されたデータはモデルの改善に使用される場合があります。 -- GLM 4.7 無料: 無料期間中、収集されたデータはモデルを改善するために使用される場合があります。 -- Kimi K2.5 Free: 無料期間中、収集されたデータはモデルの改善に使用される場合があります。 -- MiniMax M2.1 無料: 無料期間中、収集されたデータはモデルを改善するために使用される場合があります。 -- OpenAI API: リクエストは [OpenAI のデータポリシー](https://platform.openai.com/docs/guides/your-data)に従います。 -- Anthropic API: リクエストは、[Anthropic のデータポリシー](https://docs.anthropic.com/en/docs/claude-code/data-usage)に従います。 +- Big Pickle: 無料期間中、収集されたデータはモデルの改善に使用される場合があります。 +- MiniMax M2.5 Free: 無料期間中、収集されたデータはモデルの改善に使用される場合があります。 +- OpenAI API: リクエストは [OpenAI のデータポリシー](https://platform.openai.com/docs/guides/your-data) に従い、30 日間保持されます。 +- Anthropic API: リクエストは [Anthropic のデータポリシー](https://docs.anthropic.com/en/docs/claude-code/data-usage) に従い、30 日間保持されます。 --- ## チーム向け -Zen はチームにも効果的です。チームメイトを招待し、役割を割り当て、キュレートすることができます -チームが使用するモデルなど。 +Zen はチームにも効果的です。チームメイトを招待し、役割を割り当て、チームが使用するモデルをキュレートすることなどができます。 :::note ワークスペースは現在、ベータ版の一部としてチームに無料で提供されています。 ::: -価格の詳細については近日中にお知らせします。 + +ワークスペースの管理は現在、ベータ版の一部としてチームに無料で提供されています。価格の詳細については近日中にお知らせします。 --- diff --git a/packages/web/src/content/docs/keybinds.mdx b/packages/web/src/content/docs/keybinds.mdx index 25fe2a1d91..54c15e8621 100644 --- a/packages/web/src/content/docs/keybinds.mdx +++ b/packages/web/src/content/docs/keybinds.mdx @@ -3,11 +3,11 @@ title: Keybinds description: Customize your keybinds. --- -OpenCode has a list of keybinds that you can customize through the OpenCode config. +OpenCode has a list of keybinds that you can customize through `tui.json`. -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "keybinds": { "leader": "ctrl+x", "app_exit": "ctrl+c,ctrl+d,<leader>q", @@ -28,6 +28,7 @@ OpenCode has a list of keybinds that you can customize through the OpenCode conf "session_unshare": "none", "session_interrupt": "escape", "session_compact": "<leader>c", + "session_child_first": "<leader>down", "session_child_cycle": "<leader>right", "session_child_cycle_reverse": "<leader>left", "session_parent": "<leader>up", @@ -117,11 +118,11 @@ You don't need to use a leader key for your keybinds but we recommend doing so. ## Disable keybind -You can disable a keybind by adding the key to your config with a value of "none". +You can disable a keybind by adding the key to `tui.json` with a value of "none". -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "keybinds": { "session_compact": "none" } diff --git a/packages/web/src/content/docs/ko/config.mdx b/packages/web/src/content/docs/ko/config.mdx index e906eaf47b..2f08824d69 100644 --- a/packages/web/src/content/docs/ko/config.mdx +++ b/packages/web/src/content/docs/ko/config.mdx @@ -14,10 +14,11 @@ OpenCode는 **JSON**과 **JSONC**(주석이 포함된 JSON) 형식을 모두 지 ```jsonc title="opencode.jsonc" { "$schema": "https://opencode.ai/config.json", - // Theme configuration - "theme": "opencode", "model": "anthropic/claude-sonnet-4-5", "autoupdate": true, + "server": { + "port": 4096, + }, } ``` @@ -33,7 +34,7 @@ config 파일은 **교체되지 않고 병합**됩니다. config 파일은 서로 대체되는 방식이 아니라 병합됩니다. 아래 config 위치의 설정이 결합되며, 충돌하는 key에 대해서만 나중에 로드된 config가 앞선 값을 override합니다. 충돌하지 않는 설정은 모두 유지됩니다. -예를 들어, 전역 config에 `theme: "opencode"`와 `autoupdate: true`가 있고 프로젝트 config에 `model: "anthropic/claude-sonnet-4-5"`가 있으면 최종 config에는 이 세 설정이 모두 포함됩니다. +예를 들어, 전역 config에 `autoupdate: true`가 있고 프로젝트 config에 `model: "anthropic/claude-sonnet-4-5"`가 있으면 최종 config에는 이 설정이 모두 포함됩니다. --- @@ -94,7 +95,9 @@ Remote config는 가장 먼저 로드되어 기본 레이어 역할을 합니다 ### Global -전역 OpenCode config는 `~/.config/opencode/opencode.json`에 두세요. theme, provider, keybind 같은 사용자 전체 기본 설정은 전역 config로 관리하세요. +전역 OpenCode config는 `~/.config/opencode/opencode.json`에 두세요. provider, model, permissions 같은 사용자 전체 기본 설정은 전역 config로 관리하세요. + +TUI 관련 설정은 `~/.config/opencode/tui.json`을 사용하세요. 전역 config는 조직의 Remote 기본값을 override합니다. @@ -104,6 +107,8 @@ Remote config는 가장 먼저 로드되어 기본 레이어 역할을 합니다 프로젝트 루트에 `opencode.json`을 추가하세요. 프로젝트 config는 표준 config 파일 중 우선순위가 가장 높아 전역 및 Remote config를 모두 override합니다. +프로젝트별 TUI 설정은 `tui.json`을 함께 추가하세요. + :::tip 프로젝트별 config는 프로젝트 루트에 두세요. ::: @@ -142,7 +147,9 @@ custom 디렉토리는 전역 config와 `.opencode` 디렉토리 뒤에 로드 ## Schema -config 파일의 schema는 [**`opencode.ai/config.json`**](https://opencode.ai/config.json)에 정의되어 있습니다. +server/runtime config schema는 [**`opencode.ai/config.json`**](https://opencode.ai/config.json)에 정의되어 있습니다. + +TUI config는 [**`opencode.ai/tui.json`**](https://opencode.ai/tui.json)을 사용합니다. 편집기에서 이 schema를 기반으로 validation과 autocomplete를 사용할 수 있습니다. @@ -150,28 +157,24 @@ config 파일의 schema는 [**`opencode.ai/config.json`**](https://opencode.ai/c ### TUI -`tui` 옵션으로 TUI 관련 설정을 구성할 수 있습니다. +TUI 관련 설정에는 전용 `tui.json` (또는 `tui.jsonc`) 파일을 사용하세요. -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", - "tui": { - "scroll_speed": 3, - "scroll_acceleration": { - "enabled": true - }, - "diff_style": "auto" - } + "$schema": "https://opencode.ai/tui.json", + "scroll_speed": 3, + "scroll_acceleration": { + "enabled": true + }, + "diff_style": "auto" } ``` -사용 가능한 옵션: +`OPENCODE_TUI_CONFIG`를 사용하여 사용자 지정 TUI 설정 파일을 가리킬 수 있습니다. -- `scroll_acceleration.enabled` - macOS 스타일 스크롤 가속을 활성화합니다. **`scroll_speed`보다 우선합니다.** -- `scroll_speed` - 사용자 정의 스크롤 속도 배수(기본: `3`, 최소: `1`). `scroll_acceleration.enabled`가 `true`이면 무시됩니다. -- `diff_style` - diff 렌더링 방식을 제어합니다. `"auto"`는 터미널 너비에 맞춰 조정되고, `"stacked"`는 항상 단일 컬럼으로 표시합니다. +`opencode.json`의 기존 `theme`, `keybinds`, `tui` 키는 더 이상 사용되지 않으며(deprecated) 가능한 경우 자동으로 마이그레이션됩니다. -[TUI에 대해 더 알아보기](/docs/tui). +[TUI 구성에 대해 더 알아보기](/docs/tui#configure). --- @@ -297,12 +300,12 @@ Bearer token(`AWS_BEARER_TOKEN_BEDROCK` 또는 `/connect`)은 profile 기반 인 ### Themes -`theme` 옵션으로 OpenCode config에서 사용할 theme를 설정할 수 있습니다. +`tui.json`에서 UI 테마를 설정하세요. -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", - "theme": "" + "$schema": "https://opencode.ai/tui.json", + "theme": "tokyonight" } ``` @@ -402,11 +405,11 @@ Bearer token(`AWS_BEARER_TOKEN_BEDROCK` 또는 `/connect`)은 profile 기반 인 ### Keybinds -`keybinds` 옵션으로 keybind를 커스터마이즈할 수 있습니다. +`tui.json`에서 단축키를 사용자 지정하세요. -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "keybinds": {} } ``` diff --git a/packages/web/src/content/docs/ko/custom-tools.mdx b/packages/web/src/content/docs/ko/custom-tools.mdx index 77310557fa..c90db16f1d 100644 --- a/packages/web/src/content/docs/ko/custom-tools.mdx +++ b/packages/web/src/content/docs/ko/custom-tools.mdx @@ -79,6 +79,32 @@ export const multiply = tool({ --- +#### 기본 도구와 이름 충돌 + +커스텀 도구는 도구 이름으로 식별됩니다. 커스텀 도구가 기본 도구와 같은 이름을 사용하면 커스텀 도구가 우선순위를 갖습니다. + +예를 들어, 이 파일은 기본 `bash` 도구를 대체합니다: + +```ts title=".opencode/tools/bash.ts" +import { tool } from "@opencode-ai/plugin" + +export default tool({ + description: "Restricted bash wrapper", + args: { + command: tool.schema.string(), + }, + async execute(args) { + return `blocked: ${args.command}` + }, +}) +``` + +:::note +의도적으로 기본 도구를 대체하려는 경우가 아니라면 고유한 이름을 사용하는 것이 좋습니다. 도구를 오버라이드하지 않고 비활성화만 하려면 [permissions](/docs/permissions)를 사용하세요. +::: + +--- + ### 인자 인자 타입은 `tool.schema`로 정의할 수 있습니다. `tool.schema`는 [Zod](https://zod.dev) 기반입니다. diff --git a/packages/web/src/content/docs/ko/ecosystem.mdx b/packages/web/src/content/docs/ko/ecosystem.mdx index 9f6a8f9bca..455459b7ca 100644 --- a/packages/web/src/content/docs/ko/ecosystem.mdx +++ b/packages/web/src/content/docs/ko/ecosystem.mdx @@ -15,38 +15,40 @@ OpenCode를 기반으로 만들어진 커뮤니티 프로젝트 모음입니다. ## 플러그인 -| 이름 | 설명 | -| --------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- | -| [opencode-daytona](https://github.com/jamesmurdza/daytona/blob/main/guides/typescript/opencode/README.md) | git sync와 live preview를 지원하는 격리된 Daytona sandbox에서 OpenCode 세션을 자동 실행합니다. | -| [opencode-helicone-session](https://github.com/H2Shami/opencode-helicone-session) | 요청을 그룹화할 수 있도록 Helicone session header를 자동으로 주입합니다. | -| [opencode-type-inject](https://github.com/nick-vi/opencode-type-inject) | 조회 tool과 함께 TypeScript/Svelte 타입 정보를 파일 읽기에 자동 주입합니다. | -| [opencode-openai-codex-auth](https://github.com/numman-ali/opencode-openai-codex-auth) | API 크레딧 대신 ChatGPT Plus/Pro 구독을 사용할 수 있습니다. | -| [opencode-gemini-auth](https://github.com/jenslys/opencode-gemini-auth) | API 과금 대신 기존 Gemini 플랜을 사용할 수 있습니다. | -| [opencode-antigravity-auth](https://github.com/NoeFabris/opencode-antigravity-auth) | API 과금 대신 Antigravity의 무료 model을 사용할 수 있습니다. | -| [opencode-devcontainers](https://github.com/athal7/opencode-devcontainers) | shallow clone과 자동 포트 할당을 기반으로 multi-branch devcontainer 격리를 제공합니다. | -| [opencode-google-antigravity-auth](https://github.com/shekohex/opencode-google-antigravity-auth) | Google Search 지원과 견고한 API 처리를 제공하는 Google Antigravity OAuth Plugin입니다. | -| [opencode-dynamic-context-pruning](https://github.com/Tarquinen/opencode-dynamic-context-pruning) | 오래된 tool output을 정리해 token 사용량을 최적화합니다. | -| [opencode-websearch-cited](https://github.com/ghoulr/opencode-websearch-cited.git) | 지원 provider에서 Google grounded 스타일의 네이티브 websearch를 추가합니다. | -| [opencode-pty](https://github.com/shekohex/opencode-pty.git) | AI agent가 PTY에서 백그라운드 프로세스를 실행하고 대화형 입력을 보낼 수 있게 합니다. | -| [opencode-shell-strategy](https://github.com/JRedeker/opencode-shell-strategy) | 비대화형 shell 명령 실행 지침을 제공해 TTY 의존 작업으로 인한 멈춤을 방지합니다. | -| [opencode-wakatime](https://github.com/angristan/opencode-wakatime) | Wakatime으로 OpenCode 사용량을 추적합니다. | -| [opencode-md-table-formatter](https://github.com/franlol/opencode-md-table-formatter/tree/main) | LLM이 생성한 markdown 표를 정리합니다. | -| [opencode-morph-fast-apply](https://github.com/JRedeker/opencode-morph-fast-apply) | Morph Fast Apply API와 lazy edit marker를 활용해 코드 편집 속도를 크게 높입니다. | -| [oh-my-opencode](https://github.com/code-yeongyu/oh-my-opencode) | background agent, 사전 구성된 LSP/AST/MCP tool, curated agent, Claude Code 호환성을 제공합니다. | -| [opencode-notificator](https://github.com/panta82/opencode-notificator) | OpenCode 세션에 데스크톱 알림과 사운드 알림을 제공합니다. | -| [opencode-notifier](https://github.com/mohak34/opencode-notifier) | permission, 완료, 오류 이벤트에 대한 데스크톱 알림과 사운드 알림을 제공합니다. | -| [opencode-zellij-namer](https://github.com/24601/opencode-zellij-namer) | OpenCode 맥락을 기반으로 Zellij session 이름을 AI로 자동 지정합니다. | -| [opencode-skillful](https://github.com/zenobi-us/opencode-skillful) | skill 탐색과 주입을 통해 OpenCode agent가 필요 시 prompt를 lazy load하도록 합니다. | -| [opencode-supermemory](https://github.com/supermemoryai/opencode-supermemory) | Supermemory를 사용해 세션 간 persistent memory를 제공합니다. | -| [@plannotator/opencode](https://github.com/backnotprop/plannotator/tree/main/apps/opencode-plugin) | 시각 주석과 private/offline 공유를 포함한 인터랙티브 계획 리뷰를 제공합니다. | -| [@openspoon/subtask2](https://github.com/spoons-and-mirrors/subtask2) | 세밀한 flow control로 opencode /commands를 강력한 orchestration 시스템으로 확장합니다. | -| [opencode-scheduler](https://github.com/different-ai/opencode-scheduler) | cron 문법을 사용해 launchd(Mac) 또는 systemd(Linux) 기반 반복 작업을 예약합니다. | -| [micode](https://github.com/vtemian/micode) | Structured Brainstorm → Plan → Implement 워크플로를 session continuity와 함께 제공합니다. | -| [octto](https://github.com/vtemian/octto) | 다중 질문 폼 기반의 AI 브레인스토밍용 인터랙티브 브라우저 UI를 제공합니다. | -| [opencode-background-agents](https://github.com/kdcokenny/opencode-background-agents) | Claude Code 스타일의 background agent를 async delegation과 context persistence로 제공합니다. | -| [opencode-notify](https://github.com/kdcokenny/opencode-notify) | OpenCode 작업 완료 시점을 native OS 알림으로 알려줍니다. | -| [opencode-workspace](https://github.com/kdcokenny/opencode-workspace) | 16개 구성요소를 한 번에 설치하는 bundled multi-agent orchestration harness를 제공합니다. | -| [opencode-worktree](https://github.com/kdcokenny/opencode-worktree) | OpenCode용 git worktree를 손쉽게 사용할 수 있도록 돕습니다. | +| 이름 | 설명 | +| -------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- | +| [opencode-daytona](https://github.com/daytonaio/daytona/tree/main/libs/opencode-plugin) | git sync와 live preview를 지원하는 격리된 Daytona sandbox에서 OpenCode 세션을 자동 실행합니다. | +| [opencode-helicone-session](https://github.com/H2Shami/opencode-helicone-session) | 요청을 그룹화할 수 있도록 Helicone session header를 자동으로 주입합니다. | +| [opencode-type-inject](https://github.com/nick-vi/opencode-type-inject) | 조회 tool과 함께 TypeScript/Svelte 타입 정보를 파일 읽기에 자동 주입합니다. | +| [opencode-openai-codex-auth](https://github.com/numman-ali/opencode-openai-codex-auth) | API 크레딧 대신 ChatGPT Plus/Pro 구독을 사용할 수 있습니다. | +| [opencode-gemini-auth](https://github.com/jenslys/opencode-gemini-auth) | API 과금 대신 기존 Gemini 플랜을 사용할 수 있습니다. | +| [opencode-antigravity-auth](https://github.com/NoeFabris/opencode-antigravity-auth) | API 과금 대신 Antigravity의 무료 model을 사용할 수 있습니다. | +| [opencode-devcontainers](https://github.com/athal7/opencode-devcontainers) | shallow clone과 자동 포트 할당을 기반으로 multi-branch devcontainer 격리를 제공합니다. | +| [opencode-google-antigravity-auth](https://github.com/shekohex/opencode-google-antigravity-auth) | Google Search 지원과 견고한 API 처리를 제공하는 Google Antigravity OAuth Plugin입니다. | +| [opencode-dynamic-context-pruning](https://github.com/Tarquinen/opencode-dynamic-context-pruning) | 오래된 tool output을 정리해 token 사용량을 최적화합니다. | +| [opencode-vibeguard](https://github.com/inkdust2021/opencode-vibeguard) | LLM 호출 전에 secrets/PII를 VibeGuard 스타일 placeholder로 가리고, 로컬에서 복원합니다. | +| [opencode-websearch-cited](https://github.com/ghoulr/opencode-websearch-cited.git) | 지원 provider에서 Google grounded 스타일의 네이티브 websearch를 추가합니다. | +| [opencode-pty](https://github.com/shekohex/opencode-pty.git) | AI agent가 PTY에서 백그라운드 프로세스를 실행하고 대화형 입력을 보낼 수 있게 합니다. | +| [opencode-shell-strategy](https://github.com/JRedeker/opencode-shell-strategy) | 비대화형 shell 명령 실행 지침을 제공해 TTY 의존 작업으로 인한 멈춤을 방지합니다. | +| [opencode-wakatime](https://github.com/angristan/opencode-wakatime) | Wakatime으로 OpenCode 사용량을 추적합니다. | +| [opencode-md-table-formatter](https://github.com/franlol/opencode-md-table-formatter/tree/main) | LLM이 생성한 markdown 표를 정리합니다. | +| [opencode-morph-fast-apply](https://github.com/JRedeker/opencode-morph-fast-apply) | Morph Fast Apply API와 lazy edit marker를 활용해 코드 편집 속도를 크게 높입니다. | +| [oh-my-opencode](https://github.com/code-yeongyu/oh-my-opencode) | background agent, 사전 구성된 LSP/AST/MCP tool, curated agent, Claude Code 호환성을 제공합니다. | +| [opencode-notificator](https://github.com/panta82/opencode-notificator) | OpenCode 세션에 데스크톱 알림과 사운드 알림을 제공합니다. | +| [opencode-notifier](https://github.com/mohak34/opencode-notifier) | permission, 완료, 오류 이벤트에 대한 데스크톱 알림과 사운드 알림을 제공합니다. | +| [opencode-zellij-namer](https://github.com/24601/opencode-zellij-namer) | OpenCode 맥락을 기반으로 Zellij session 이름을 AI로 자동 지정합니다. | +| [opencode-skillful](https://github.com/zenobi-us/opencode-skillful) | skill 탐색과 주입을 통해 OpenCode agent가 필요 시 prompt를 lazy load하도록 합니다. | +| [opencode-supermemory](https://github.com/supermemoryai/opencode-supermemory) | Supermemory를 사용해 세션 간 persistent memory를 제공합니다. | +| [@plannotator/opencode](https://github.com/backnotprop/plannotator/tree/main/apps/opencode-plugin) | 시각 주석과 private/offline 공유를 포함한 인터랙티브 계획 리뷰를 제공합니다. | +| [@openspoon/subtask2](https://github.com/spoons-and-mirrors/subtask2) | 세밀한 flow control로 opencode /commands를 강력한 orchestration 시스템으로 확장합니다. | +| [opencode-scheduler](https://github.com/different-ai/opencode-scheduler) | cron 문법을 사용해 launchd(Mac) 또는 systemd(Linux) 기반 반복 작업을 예약합니다. | +| [micode](https://github.com/vtemian/micode) | Structured Brainstorm → Plan → Implement 워크플로를 session continuity와 함께 제공합니다. | +| [octto](https://github.com/vtemian/octto) | 다중 질문 폼 기반의 AI 브레인스토밍용 인터랙티브 브라우저 UI를 제공합니다. | +| [opencode-background-agents](https://github.com/kdcokenny/opencode-background-agents) | Claude Code 스타일의 background agent를 async delegation과 context persistence로 제공합니다. | +| [opencode-notify](https://github.com/kdcokenny/opencode-notify) | OpenCode 작업 완료 시점을 native OS 알림으로 알려줍니다. | +| [opencode-workspace](https://github.com/kdcokenny/opencode-workspace) | 16개 구성요소를 한 번에 설치하는 bundled multi-agent orchestration harness를 제공합니다. | +| [opencode-worktree](https://github.com/kdcokenny/opencode-worktree) | OpenCode용 git worktree를 손쉽게 사용할 수 있도록 돕습니다. | +| [opencode-sentry-monitor](https://github.com/stolinski/opencode-sentry-monitor) | Sentry AI 모니터링으로 AI 에이전트를 추적하고 디버그합니다. | --- diff --git a/packages/web/src/content/docs/ko/gitlab.mdx b/packages/web/src/content/docs/ko/gitlab.mdx index 7b6468c740..850cd62258 100644 --- a/packages/web/src/content/docs/ko/gitlab.mdx +++ b/packages/web/src/content/docs/ko/gitlab.mdx @@ -1,34 +1,34 @@ --- title: GitLab -description: GitLab 이슈 및 머지 리퀘스트에서 opencode를 사용하세요. +description: GitLab 이슈와 merge request에서 OpenCode를 사용하세요. --- -opencode는 GitLab CI/CD 파이프라인 또는 GitLab Duo를 통해 GitLab 워크플로우와 통합됩니다. +OpenCode는 GitLab CI/CD 파이프라인 또는 GitLab Duo를 통해 GitLab 워크플로에 통합됩니다. -두 경우, opencode는 GitLab runners에서 실행됩니다. +두 경우 모두 OpenCode는 GitLab runner에서 실행됩니다. --- -# GitLab CI 소개 +## GitLab CI -opencode는 일반 GitLab 파이프라인에서 작동합니다. [CI 컴포넌트](https://docs.gitlab.com/ee/ci/components/)로 파이프라인에 구축할 수 있습니다. +OpenCode는 일반 GitLab 파이프라인에서 작동합니다. [CI component](https://docs.gitlab.com/ee/ci/components/)로 파이프라인에 통합할 수 있습니다. -여기에서 우리는 opencode에 대한 커뮤니티 생성 CI / CD 구성품을 사용하고 있습니다. [nagyv/gitlab-opencode](https://gitlab.com/nagyv/gitlab-opencode). +여기서는 OpenCode용 커뮤니티 제작 CI/CD component인 [nagyv/gitlab-opencode](https://gitlab.com/nagyv/gitlab-opencode)를 사용합니다. --- ### 기능 -- **실행별 사용자 지정 구성 사용**: 사용자 정의 구성 디렉토리와 opencode 구성, 예를 들어 `./config/#custom-directory`는 opencode 실행마다 활성화하거나 비활성화 할 수 있습니다. -- ** 최소 설정**: CI 구성 요소는 opencode를 배경으로 설정하면 opencode 구성과 초기 프롬프트를 만들 필요가 있습니다. -- **Flexible**: CI 구성 요소는 여러 입력을 지원합니다. +- **job별 custom config 사용**: custom config 디렉터리(예: `./config/#custom-directory`)를 사용해 OpenCode를 각 실행 단위로 설정하고 기능을 켜거나 끌 수 있습니다. +- **최소 설정**: CI component가 백그라운드에서 OpenCode를 설정하므로 OpenCode config와 초기 prompt만 만들면 됩니다. +- **유연함**: CI component는 동작을 사용자화할 수 있도록 여러 입력값을 지원합니다. --- -## 설정 +### Setup -1. opencode 인증 JSON을 **Settings** > **CI/CD** > **Variables**에서 파일 유형 CI 환경 변수로 저장하십시오. "Masked and hidden"로 표시하십시오. -2. `.gitlab-ci.yml` 파일에 뒤에 추가하십시오. +1. OpenCode 인증 JSON을 **Settings** > **CI/CD** > **Variables** 아래의 File 타입 CI 환경 변수로 저장하세요. 반드시 "Masked and hidden"으로 표시하세요. +2. 아래 내용을 `.gitlab-ci.yml` 파일에 추가하세요. ```yaml title=".gitlab-ci.yml" include: @@ -40,40 +40,40 @@ opencode는 일반 GitLab 파이프라인에서 작동합니다. [CI 컴포넌 message: "Your prompt here" ``` -더 많은 입력 및 사용 사례 [docs를 체크 아웃](https://gitlab.com/explore/catalog/nagyv/gitlab-opencode) 이 구성 요소에 대한. +더 많은 입력값과 사용 사례는 이 component의 [docs](https://gitlab.com/explore/catalog/nagyv/gitlab-opencode)에서 확인하세요. --- ## GitLab Duo -opencode는 GitLab 워크플로우와 통합됩니다. -코멘트에 Mention `@opencode`, opencode는 GitLab CI 파이프라인 내에서 작업을 실행합니다. +OpenCode는 GitLab 워크플로에 통합됩니다. +댓글에서 `@opencode`를 멘션하면 OpenCode가 GitLab CI 파이프라인 안에서 작업을 실행합니다. --- ### 기능 -- **이슈**: opencode가 문제점을 보고 당신을 설명합니다. -- **수정 및 구현**: 이슈를 수정하거나 기능을 구현하려면 opencode에 문의하십시오. - 새로운 지점을 만들고 변화를 병합 요청을 제기합니다. -- **보안**: opencode는 GitLab runners에서 실행됩니다. +- **이슈 분류**: OpenCode에 이슈를 살펴보고 설명해 달라고 요청할 수 있습니다. +- **수정 및 구현**: OpenCode에 이슈를 수정하거나 기능을 구현해 달라고 요청할 수 있습니다. + OpenCode는 새 브랜치를 만들고 변경 사항이 담긴 merge request를 생성합니다. +- **보안**: OpenCode는 GitLab runner에서 실행됩니다. --- -## 설정 +### Setup -opencode는 GitLab CI/CD 파이프라인에서 실행되며, 여기서 설정해야 할 일은 다음과 같습니다. +OpenCode는 GitLab CI/CD 파이프라인에서 실행되며, 설정에 필요한 항목은 다음과 같습니다. :::tip -[**GitLab docs**](https://docs.gitlab.com/user/duo agent platform/agent assistant/) 를 체크 아웃하십시오. +[최신 안내는 **GitLab docs**](https://docs.gitlab.com/user/duo_agent_platform/agent_assistant/)를 확인하세요. ::: -1. GitLab 환경 설정 -2. CI/CD 설치 -3. AI 모형 공급자 API 열쇠를 얻으십시오 -4. 서비스 계정 만들기 -5. CI/CD 변수 구성 -6. Flow config 파일을 만들려면 다음과 같습니다. +1. GitLab 환경을 설정합니다. +2. CI/CD를 설정합니다. +3. AI model provider API 키를 준비합니다. +4. 서비스 계정을 생성합니다. +5. CI/CD 변수를 설정합니다. +6. flow config 파일을 생성합니다. 예시는 다음과 같습니다. <details> @@ -152,44 +152,44 @@ opencode는 GitLab CI/CD 파이프라인에서 실행되며, 여기서 설정해 </details> -자세한 지침에 대한 [GitLab CLI Agent docs](https://docs.gitlab.com/user/duo agent platform/agent assistant/)를 참조할 수 있습니다. +[GitLab CLI agents docs](https://docs.gitlab.com/user/duo_agent_platform/agent_assistant/)에서 자세한 안내를 확인할 수 있습니다. --- ### 예제 -다음은 GitLab에서 opencode를 사용할 수있는 몇 가지 예입니다. +다음은 GitLab에서 OpenCode를 사용하는 몇 가지 예시입니다. :::tip -`@opencode`보다 다른 트리거 구문을 사용할 수 있습니다. +`@opencode` 대신 다른 trigger phrase를 사용하도록 설정할 수 있습니다. ::: - **이슈 설명** -GitLab 문제에서이 코멘트를 추가하십시오. +GitLab 이슈에 아래 댓글을 남기세요. ``` @opencode explain this issue ``` -opencode는 문제와 대답을 명확하게 설명합니다. +OpenCode가 이슈를 읽고 명확한 설명으로 답변합니다. - **이슈 해결** -GitLab 문제에서, 말한다: +GitLab 이슈에서 다음과 같이 요청하세요. ``` @opencode fix this ``` -opencode는 새로운 지점을 만들 것이며 변경 사항을 구현하고 변경 사항을 병합 요청을 엽니다. +OpenCode가 새 브랜치를 만들고 변경 사항을 구현한 뒤, 해당 변경 사항으로 merge request를 엽니다. - **머지 리퀘스트 검토** -GitLab 병합 요청에 대한 다음 의견을 남겨주세요. +GitLab merge request에 아래 댓글을 남기세요. ``` @opencode review this merge request ``` -opencode는 병합 요청을 검토하고 피드백을 제공합니다. +OpenCode가 merge request를 검토하고 피드백을 제공합니다. diff --git a/packages/web/src/content/docs/ko/go.mdx b/packages/web/src/content/docs/ko/go.mdx new file mode 100644 index 0000000000..5909a01c9f --- /dev/null +++ b/packages/web/src/content/docs/ko/go.mdx @@ -0,0 +1,145 @@ +--- +title: Go +description: 오픈 코딩 모델을 위한 저렴한 구독 서비스입니다. +--- + +import config from "../../../../config.mjs" +export const console = config.console +export const email = `mailto:${config.email}` + +OpenCode Go는 인기 있는 오픈 코딩 모델에 안정적으로 액세스할 수 있는 저렴한 **월 $10** 구독 서비스입니다. + +:::note +OpenCode Go는 현재 베타 버전입니다. +::: + +Go는 OpenCode의 다른 제공자처럼 작동합니다. OpenCode Go를 구독하고 API 키를 받으세요. 이는 **완전히 선택 사항**이며 OpenCode를 사용하기 위해 반드시 사용할 필요는 없습니다. + +주로 해외 사용자를 위해 설계되었으며, 안정적인 글로벌 액세스를 위해 미국, EU, 싱가포르에서 모델이 호스팅됩니다. + +--- + +## 배경 + +오픈 모델은 정말 좋아졌습니다. 이제 코딩 작업에서 독점 모델에 가까운 성능을 발휘합니다. 그리고 많은 제공자가 경쟁적으로 서비스할 수 있기 때문에 일반적으로 훨씬 저렴합니다. + +하지만 안정적이고 지연 시간이 짧은 액세스를 얻기는 어려울 수 있습니다. 제공자마다 품질과 가용성이 다릅니다. + +:::tip +OpenCode와 잘 작동하는 엄선된 모델 및 제공자 그룹을 테스트했습니다. +::: + +이를 해결하기 위해 몇 가지 작업을 수행했습니다. + +1. 엄선된 오픈 모델 그룹을 테스트하고 해당 팀과 최적의 실행 방법에 대해 논의했습니다. +2. 그런 다음 몇몇 제공자와 협력하여 이것들이 올바르게 서비스되고 있는지 확인했습니다. +3. 마지막으로 모델/제공자 조합을 벤치마킹하여 추천할 만한 목록을 만들었습니다. + +OpenCode Go를 사용하면 **월 $10**에 이러한 모델에 액세스할 수 있습니다. + +--- + +## 작동 방식 + +OpenCode Go는 OpenCode의 다른 제공자처럼 작동합니다. + +1. **<a href={console}>OpenCode Zen</a>**에 로그인하고 Go를 구독한 다음 API 키를 복사합니다. +2. TUI에서 `/connect` 명령을 실행하고 `OpenCode Go`를 선택한 다음 API 키를 붙여넣습니다. +3. TUI에서 `/models`를 실행하여 Go를 통해 사용할 수 있는 모델 목록을 확인합니다. + +:::note +워크스페이스당 한 명의 멤버만 OpenCode Go를 구독할 수 있습니다. +::: + +현재 모델 목록은 다음과 같습니다. + +- **GLM-5** +- **Kimi K2.5** +- **MiniMax M2.5** + +모델 목록은 테스트하고 새로운 모델을 추가함에 따라 변경될 수 있습니다. + +--- + +## 사용 한도 + +OpenCode Go에는 다음과 같은 한도가 포함됩니다. + +- **5시간 한도** — $12 사용량 +- **주간 한도** — $30 사용량 +- **월간 한도** — $60 사용량 + +한도는 달러 가치로 정의됩니다. 즉, 실제 요청 수는 사용하는 모델에 따라 다릅니다. MiniMax M2.5와 같은 저렴한 모델은 더 많은 요청을 허용하는 반면, GLM-5와 같은 고비용 모델은 더 적은 요청을 허용합니다. + +아래 표는 일반적인 Go 사용 패턴을 기반으로 한 예상 요청 수를 제공합니다. + +| | GLM-5 | Kimi K2.5 | MiniMax M2.5 | +| --------------- | ----- | --------- | ------------ | +| 5시간당 요청 수 | 1,150 | 1,850 | 30,000 | +| 주당 요청 수 | 2,880 | 4,630 | 75,000 | +| 월당 요청 수 | 5,750 | 9,250 | 150,000 | + +추정치는 관찰된 평균 요청 패턴을 기반으로 합니다. + +- GLM-5 — 요청당 입력 700, 캐시 52,000, 출력 150 토큰 +- Kimi K2.5 — 요청당 입력 870, 캐시 55,000, 출력 200 토큰 +- MiniMax M2.5 — 요청당 입력 300, 캐시 55,000, 출력 125 토큰 + +**<a href={console}>콘솔</a>**에서 현재 사용량을 추적할 수 있습니다. + +:::tip +사용 한도에 도달하면 무료 모델을 계속 사용할 수 있습니다. +::: + +사용 한도는 초기 사용 및 피드백을 통해 학습함에 따라 변경될 수 있습니다. + +--- + +### 가격 + +OpenCode Go는 **월 $10** 구독 요금제입니다. 아래는 **100만 토큰당** 가격입니다. + +| Model | Input | Output | Cached Read | +| ------------ | ----- | ------ | ----------- | +| GLM-5 | $1.00 | $3.20 | $0.20 | +| Kimi K2.5 | $0.60 | $3.00 | $0.10 | +| MiniMax M2.5 | $0.30 | $1.20 | $0.03 | + +--- + +### 한도 초과 사용 + +Zen 잔액에 크레딧이 있는 경우 콘솔에서 **잔액 사용(Use balance)** 옵션을 활성화할 수 있습니다. 활성화하면 사용 한도에 도달했을 때 요청을 차단하는 대신 Zen 잔액을 사용하게 됩니다. + +--- + +## 엔드포인트 + +다음 API 엔드포인트를 통해 Go 모델에 액세스할 수도 있습니다. + +| Model | Model ID | Endpoint | AI SDK Package | +| ------------ | ------------ | ------------------------------------------------ | --------------------------- | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | + +OpenCode 설정의 [모델 ID](/docs/config/#models)는 `opencode-go/<model-id>` 형식을 사용합니다. 예를 들어 Kimi K2.5의 경우 설정에서 `opencode-go/kimi-k2.5`를 사용합니다. + +--- + +## 개인정보 보호 + +이 플랜은 주로 해외 사용자를 위해 설계되었으며, 안정적인 글로벌 액세스를 위해 미국, EU, 싱가포르에서 모델이 호스팅됩니다. + +질문이 있으시면 <a href={email}>문의해 주세요</a>. + +--- + +## 목표 + +우리는 다음을 위해 OpenCode Go를 만들었습니다. + +1. 저렴한 구독으로 더 많은 사람들이 AI 코딩에 **접근할 수 있도록** 합니다. +2. 최고의 오픈 코딩 모델에 **안정적으로** 액세스할 수 있도록 합니다. +3. 코딩 에이전트 사용을 위해 **테스트 및 벤치마킹된** 모델을 큐레이팅합니다. +4. OpenCode와 함께 다른 제공자도 사용할 수 있도록 하여 **락인(lock-in)이 없도록** 합니다. diff --git a/packages/web/src/content/docs/ko/ide.mdx b/packages/web/src/content/docs/ko/ide.mdx index 2df782a9e7..ddc7300191 100644 --- a/packages/web/src/content/docs/ko/ide.mdx +++ b/packages/web/src/content/docs/ko/ide.mdx @@ -1,35 +1,36 @@ --- title: IDE -description: VS Code, Cursor 및 기타 IDE용 opencode 확장 프로그램. +description: VS Code, Cursor 및 기타 IDE용 OpenCode 확장 프로그램 --- -opencode는 VS Code, Cursor, 또는 터미널을 지원하는 IDE와 통합됩니다. 시작하려면 terminal에서 `opencode`를 실행하십시오. +OpenCode는 VS Code, Cursor, 또는 터미널을 지원하는 모든 IDE와 통합됩니다. 시작하려면 터미널에서 `opencode`를 실행하세요. --- ## 사용법 --**Quick Launch**: `Cmd+Esc` (Mac) 또는 `Ctrl+Esc` (Windows/Linux)를 사용하여 통합 터미널 뷰에 opencode를 열거나 기존 terminal 세션을 이미 실행하면 됩니다. -**New Session**: `Cmd+Shift+Esc` (Mac) 또는 `Ctrl+Shift+Esc` (Windows/Linux)를 사용하여 새로운 opencode terminal 세션을 시작하려면 이미 열리면 됩니다. UI에서 opencode 버튼을 클릭합니다. -**Context Awareness**: opencode로 현재 선택 또는 탭을 자동으로 공유합니다. - -- **파일 참조 단축키** : 파일 참조를 삽입하려면 `Cmd+Option+K` (Mac) 또는 `Alt+Ctrl+K` (Linux / Windows)를 사용하십시오. 예를 들어, `@File#L37-42`. +- **Quick Launch**: `Cmd+Esc` (Mac) 또는 `Ctrl+Esc` (Windows/Linux)를 사용해 분할 터미널 뷰에서 OpenCode를 열거나, 이미 실행 중인 터미널 세션으로 포커스하세요. +- **New Session**: `Cmd+Shift+Esc` (Mac) 또는 `Ctrl+Shift+Esc` (Windows/Linux)를 사용해 기존 세션이 열려 있어도 새 OpenCode 터미널 세션을 시작하세요. UI의 OpenCode 버튼을 클릭해도 됩니다. +- **Context Awareness**: 현재 선택 영역이나 탭을 OpenCode와 자동으로 공유합니다. +- **File Reference Shortcuts**: `Cmd+Option+K` (Mac) 또는 `Alt+Ctrl+K` (Linux/Windows)를 사용해 파일 참조를 삽입하세요. 예: `@File#L37-42`. --- ## 설치 -VS Code에 opencode를 설치하고 Cursor, Windsurf, VSCodium과 같은 인기있는 포크 : +VS Code와 Cursor, Windsurf, VSCodium 같은 인기 포크에 OpenCode를 설치하려면: -1. VS Code 열기 -2. 통합 terminal을 여십시오 -3. 실행 `opencode` - 확장 자동으로 설치 +1. VS Code를 여세요.4 +2. 통합 터미널을 여세요. +3. `opencode`를 실행하세요. 확장 프로그램이 자동으로 설치됩니다. -반면에 TUI에서 `/editor` 또는 `/export`를 실행할 때, 당신은 `export EDITOR="code --wait"`를 설정할 필요가 있을 것입니다. [Learn more](/docs/tui/#editor-setup). +반면 TUI에서 `/editor` 또는 `/export`를 실행할 때 자체 IDE를 사용하려면 `export EDITOR="code --wait"`를 설정해야 합니다. [자세히 알아보기](/docs/tui/#editor-setup). --- -## 수동 설치 +### 수동 설치 -확장 마켓 플레이스에서 **opencode**를 검색하고 **Install**를 클릭합니다. +Extension Marketplace에서 **OpenCode**를 검색한 다음 **Install**을 클릭하세요. --- @@ -37,11 +38,11 @@ VS Code에 opencode를 설치하고 Cursor, Windsurf, VSCodium과 같은 인기 확장이 자동으로 설치되지 않는 경우: -- 통합 terminal에서 `opencode`를 실행하는 것을 보장합니다. -- IDE용 CLI가 설치됩니다. -- VS Code : `code` 명령 -- 커서: `cursor` 명령 -- 윈드 서핑을 위해: `windsurf` 명령 -- VSCodium의 경우: `codium` 명령 -- 만약 `Cmd+Shift+P` (Mac) 또는 `Ctrl+Shift+P` (Windows/Linux)를 실행하고 "Shell Command: PATH"에서 'code' 명령을 설치하십시오 (또는 IDE에 해당) -- Ensure VS Code는 확장을 설치하는 권한이 있습니다. +- 통합 터미널에서 `opencode`를 실행하고 있는지 확인하세요. +- IDE용 CLI가 설치되어 있는지 확인하세요. + - VS Code: `code` command + - Cursor: `cursor` command + - Windsurf: `windsurf` command + - VSCodium: `codium` command + - 설치되어 있지 않다면 `Cmd+Shift+P` (Mac) 또는 `Ctrl+Shift+P` (Windows/Linux)를 실행하고 "Shell Command: Install 'code' command in PATH"(또는 IDE에 맞는 동등한 명령)를 검색하세요. +- VS Code에 확장 프로그램 설치 권한이 있는지 확인하세요. diff --git a/packages/web/src/content/docs/ko/index.mdx b/packages/web/src/content/docs/ko/index.mdx index b94d0750f6..0dfa0bbc83 100644 --- a/packages/web/src/content/docs/ko/index.mdx +++ b/packages/web/src/content/docs/ko/index.mdx @@ -7,19 +7,19 @@ import { Tabs, TabItem } from "@astrojs/starlight/components" import config from "../../../../config.mjs" export const console = config.console -[**OpenCode**](/)는 터미널 기반 인터페이스, 데스크톱 앱, IDE 확장 형태로 사용할 수 있는 오픈 소스 AI 코딩 에이전트입니다. +[**OpenCode**](/)는 오픈 소스 AI coding agent입니다. 터미널 기반 인터페이스, 데스크톱 앱, IDE 확장으로 사용할 수 있습니다. ![opencode TUI with the opencode theme](../../../assets/lander/screenshot.png) -바로 시작해 봅시다. +바로 시작해 보겠습니다. --- -## 사전 준비 +#### 사전 준비 터미널에서 OpenCode를 사용하려면 다음이 필요합니다. -1. 최신 터미널 에뮬레이터 (예:) +1. 다음과 같은 최신 터미널 에뮬레이터 - [WezTerm](https://wezterm.org), 크로스 플랫폼 - [Alacritty](https://alacritty.org), 크로스 플랫폼 - [Ghostty](https://ghostty.org), Linux 및 macOS @@ -31,13 +31,13 @@ export const console = config.console ## 설치 -가장 쉬운 설치 방법은 설치 스크립트를 사용하는 것입니다. +OpenCode를 설치하는 가장 쉬운 방법은 설치 스크립트를 사용하는 것입니다. ```bash curl -fsSL https://opencode.ai/install | bash ``` -아래 명령으로도 설치할 수 있습니다. +다음 명령으로도 설치할 수 있습니다. - **Node.js 사용** @@ -79,9 +79,9 @@ curl -fsSL https://opencode.ai/install | bash brew install anomalyco/tap/opencode ``` - > 최신 릴리스는 OpenCode tap 사용을 권장합니다. 공식 `brew install opencode` 포뮬러는 Homebrew 팀이 관리하므로 업데이트 주기가 더 긴 편입니다. + > 최신 릴리스를 사용하려면 OpenCode tap 사용을 권장합니다. 공식 `brew install opencode` formula는 Homebrew 팀이 관리하며 업데이트 주기가 더 깁니다. -- **Arch Linux에서 Paru 사용** +- **Arch Linux에 설치** ```bash sudo pacman -S opencode # Arch Linux (Stable) @@ -91,7 +91,7 @@ curl -fsSL https://opencode.ai/install | bash #### Windows :::tip[권장: WSL 사용] -Windows에서는 [Windows Subsystem for Linux (WSL)](/docs/windows-wsl)을 사용하는 것이 가장 좋습니다. OpenCode 기능과의 호환성이 높고 성능도 더 좋습니다. +Windows에서는 [Windows Subsystem for Linux (WSL)](/docs/windows-wsl) 사용을 권장합니다. 성능이 더 좋고 OpenCode 기능과의 완전한 호환성을 제공합니다. ::: - **Chocolatey 사용** @@ -124,7 +124,7 @@ Windows에서는 [Windows Subsystem for Linux (WSL)](/docs/windows-wsl)을 사 docker run -it --rm ghcr.io/anomalyco/opencode ``` -Windows에서 Bun을 통한 OpenCode 설치는 아직 지원되지 않으며, 현재 지원을 준비 중입니다. +현재 Windows에서 Bun을 사용한 OpenCode 설치 지원은 준비 중입니다. [Releases](https://github.com/anomalyco/opencode/releases)에서 바이너리를 직접 받아 설치할 수도 있습니다. @@ -134,16 +134,16 @@ Windows에서 Bun을 통한 OpenCode 설치는 아직 지원되지 않으며, OpenCode는 API 키를 설정하면 원하는 LLM 제공자를 사용할 수 있습니다. -LLM 제공자(LLM Provider)를 처음 사용한다면 [OpenCode Zen](/docs/zen)을 추천합니다. +LLM 제공자를 처음 사용한다면 [OpenCode Zen](/docs/zen) 사용을 권장합니다. OpenCode 팀이 테스트하고 검증한 모델 목록입니다. -1. TUI에서 `/connect` 명령을 실행한 뒤 `opencode`를 선택하고 [opencode.ai/auth](https://opencode.ai/auth)로 이동합니다. +1. TUI에서 `/connect` 명령을 실행하고 `opencode`를 선택한 다음 [opencode.ai/auth](https://opencode.ai/auth)로 이동합니다. ```txt /connect ``` -2. 로그인 후 결제 정보를 입력하고 API 키를 복사합니다. +2. 로그인하고 결제 정보를 추가한 뒤 API 키를 복사합니다. 3. API 키를 붙여 넣습니다. @@ -154,13 +154,13 @@ OpenCode 팀이 테스트하고 검증한 모델 목록입니다. └ enter ``` -다른 제공자를 선택해도 됩니다. [더 알아보기](/docs/providers#directory). +또는 다른 제공자 중 하나를 선택할 수도 있습니다. [더 알아보기](/docs/providers#directory). --- ## 초기화 -이제 제공자 구성이 끝났으니, 작업할 프로젝트 디렉터리로 이동합니다. +이제 제공자 구성을 마쳤으니 작업하려는 프로젝트로 이동합니다. ```bash cd /path/to/project @@ -172,19 +172,19 @@ cd /path/to/project opencode ``` -다음 명령으로 프로젝트용 OpenCode 초기화를 진행합니다. +다음 명령을 실행해 프로젝트에서 OpenCode를 초기화합니다. ```bash frame="none" /init ``` -이 명령은 프로젝트를 분석하고 루트에 `AGENTS.md` 파일을 생성합니다. +이 명령을 실행하면 OpenCode가 프로젝트를 분석하고 프로젝트 루트에 `AGENTS.md` 파일을 생성합니다. :::tip -프로젝트의 `AGENTS.md`는 Git에 커밋해 두는 것을 권장합니다. +프로젝트의 `AGENTS.md` 파일은 Git에 커밋하는 것을 권장합니다. ::: -그러면 OpenCode가 프로젝트 구조와 코딩 패턴을 더 잘 이해할 수 있습니다. +이렇게 하면 OpenCode가 프로젝트 구조와 사용 중인 코딩 패턴을 더 잘 이해할 수 있습니다. --- @@ -192,7 +192,7 @@ opencode 이제 OpenCode로 프로젝트 작업을 시작할 준비가 되었습니다. 무엇이든 물어보세요. -AI 코딩 에이전트를 처음 쓰는 경우 도움이 되는 예시를 소개합니다. +AI coding agent를 처음 사용한다면 도움이 될 수 있는 예시를 소개합니다. --- @@ -208,25 +208,25 @@ OpenCode에 코드베이스 설명을 요청할 수 있습니다. How is authentication handled in @packages/functions/src/api/index.ts ``` -직접 작업하지 않은 코드 영역을 이해할 때 특히 유용합니다. +이 방법은 직접 작업하지 않은 코드 영역을 이해할 때 유용합니다. --- ### 기능 추가 -프로젝트에 새 기능을 추가해 달라고 요청할 수 있습니다. 다만 먼저 계획을 만들게 하는 것을 권장합니다. +OpenCode에 프로젝트의 새 기능 추가를 요청할 수 있습니다. 다만 먼저 계획을 만들도록 요청하는 것을 권장합니다. 1. **계획 만들기** - OpenCode에는 변경 작업을 비활성화하고 구현 방법을 제안만 하는 *Plan mode*가 있습니다. + OpenCode에는 변경 작업 기능을 비활성화하고 기능을 구현할 방법만 제안하는 *Plan mode*가 있습니다. - **Tab** 키로 전환하면 오른쪽 아래에 모드 표시가 나타납니다. + **Tab** 키를 눌러 전환하세요. 화면 오른쪽 아래에서 모드 표시를 확인할 수 있습니다. ```bash frame="none" title="Switch to Plan mode" <TAB> ``` - 이제 원하는 작업을 구체적으로 설명합니다. + 이제 수행하길 원하는 작업을 설명해 보겠습니다. ```txt frame="none" When a user deletes a note, we'd like to flag it as deleted in the database. @@ -234,15 +234,15 @@ How is authentication handled in @packages/functions/src/api/index.ts From this screen, the user can undelete a note or permanently delete it. ``` - OpenCode가 정확히 이해할 만큼 충분한 맥락을 주는 것이 중요합니다. 팀의 주니어 개발자에게 설명하듯 요청하면 도움이 됩니다. + OpenCode가 원하는 작업을 이해할 수 있도록 충분한 세부 정보를 제공해야 합니다. 팀의 주니어 개발자에게 말하듯이 설명하면 도움이 됩니다. :::tip - 맥락과 예시를 충분히 제공하면 원하는 결과를 얻기 쉽습니다. + OpenCode가 원하는 작업을 이해하도록 충분한 맥락과 예시를 제공하세요. ::: 2. **계획 다듬기** - 계획이 나오면 피드백을 주거나 추가 요구사항을 붙일 수 있습니다. + 계획이 나오면 피드백을 주거나 세부 사항을 더 추가할 수 있습니다. ```txt frame="none" We'd like to design this new screen using a design I've used before. @@ -250,20 +250,20 @@ How is authentication handled in @packages/functions/src/api/index.ts ``` :::tip - 이미지를 터미널에 드래그 앤 드롭하면 프롬프트에 첨부할 수 있습니다. + 이미지를 터미널에 드래그 앤 드롭해 prompt에 추가하세요. ::: - OpenCode는 첨부한 이미지를 분석해 프롬프트에 포함합니다. + OpenCode는 제공한 이미지를 스캔해 prompt에 추가할 수 있습니다. 이미지를 터미널에 드래그 앤 드롭하면 됩니다. 3. **기능 구현** - 계획이 충분히 만족스러우면 **Tab** 키를 다시 눌러 *Build mode*로 돌아갑니다. + 계획이 충분히 마음에 들면 **Tab** 키를 다시 눌러 *Build mode*로 전환하세요. ```bash frame="none" <TAB> ``` - 그리고 실제 변경을 요청합니다. + 그리고 변경을 적용해 달라고 요청하세요. ```bash frame="none" Sounds good! Go ahead and make the changes. @@ -273,7 +273,7 @@ How is authentication handled in @packages/functions/src/api/index.ts ### 바로 변경하기 -비교적 단순한 변경은 계획 검토 없이 바로 구현하도록 요청해도 됩니다. +비교적 간단한 변경은 계획을 먼저 검토하지 않고 바로 구현하도록 요청할 수 있습니다. ```txt frame="none" "@packages/functions/src/settings.ts" "@packages/functions/src/notes.ts" We need to add authentication to the /settings route. Take a look at how this is @@ -281,37 +281,37 @@ handled in the /notes route in @packages/functions/src/notes.ts and implement the same logic in @packages/functions/src/settings.ts ``` -원하는 변경이 정확히 반영되도록, 필요한 맥락을 충분히 제공하세요. +OpenCode가 올바른 변경을 하도록 충분한 세부 정보를 제공해야 합니다. --- ### 변경 되돌리기 -예를 들어 OpenCode에 변경을 요청했다고 가정해 보겠습니다. +예를 들어 OpenCode에 변경을 요청했다고 해보겠습니다. ```txt frame="none" "@packages/functions/src/api/index.ts" Can you refactor the function in @packages/functions/src/api/index.ts? ``` -결과가 기대와 다르면 `/undo` 명령으로 **되돌릴 수** 있습니다. +그런데 원하는 결과가 아니었다면 `/undo` 명령으로 변경을 **되돌릴 수** 있습니다. ```bash frame="none" /undo ``` -OpenCode는 방금 적용한 변경을 되돌리고 원래 메시지를 다시 보여줍니다. +OpenCode가 방금 적용한 변경을 되돌리고 원래 메시지를 다시 보여줍니다. ```txt frame="none" "@packages/functions/src/api/index.ts" Can you refactor the function in @packages/functions/src/api/index.ts? ``` -이 상태에서 프롬프트를 다듬어 다시 시도하면 됩니다. +여기에서 prompt를 수정해 다시 요청할 수 있습니다. :::tip `/undo`는 여러 번 연속으로 실행할 수 있습니다. ::: -반대로 `/redo` 명령으로 **다시 적용**할 수도 있습니다. +또는 `/redo` 명령으로 변경을 **다시 적용**할 수 있습니다. ```bash frame="none" /redo @@ -327,18 +327,18 @@ OpenCode와의 대화는 [팀과 공유](/docs/share)할 수 있습니다. /share ``` -현재 대화 링크를 생성하고 클립보드에 복사합니다. +이 명령을 실행하면 현재 대화 링크를 생성하고 클립보드에 복사합니다. :::note 대화는 기본값으로 공유되지 않습니다. ::: -아래는 OpenCode [대화 예시](https://opencode.ai/s/4XP1fce5)입니다. +다음은 OpenCode [대화 예시](https://opencode.ai/s/4XP1fce5)입니다. --- ## 사용자 지정 -이제 OpenCode 사용의 기본은 끝났습니다. +이제 OpenCode 사용법을 익혔습니다. -자신의 워크플로우에 맞추려면 [테마 선택](/docs/themes), [키바인드 사용자 지정](/docs/keybinds), [코드 포매터 설정](/docs/formatters), [커스텀 명령 작성](/docs/commands), [OpenCode 구성 조정](/docs/config)을 추천합니다. +원하는 방식에 맞추려면 [테마 선택](/docs/themes), [키바인드 사용자 지정](/docs/keybinds), [코드 formatter 설정](/docs/formatters), [custom command 만들기](/docs/commands), [OpenCode config 설정](/docs/config)을 권장합니다. diff --git a/packages/web/src/content/docs/ko/keybinds.mdx b/packages/web/src/content/docs/ko/keybinds.mdx index d41fb8cef5..fa8b4e9bdd 100644 --- a/packages/web/src/content/docs/ko/keybinds.mdx +++ b/packages/web/src/content/docs/ko/keybinds.mdx @@ -1,13 +1,13 @@ --- title: 키바인드 -description: 키바인드를 사용자 지정하세요. +description: 키바인드를 커스터마이즈하세요. --- -opencode는 opencode config를 통해 사용자 정의 할 수있는 keybinds 목록을 가지고 있습니다. +OpenCode에는 `tui.json`을 통해 커스터마이즈할 수 있는 키바인드 목록이 있습니다. -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "keybinds": { "leader": "ctrl+x", "app_exit": "ctrl+c,ctrl+d,<leader>q", @@ -28,6 +28,7 @@ opencode는 opencode config를 통해 사용자 정의 할 수있는 keybinds "session_unshare": "none", "session_interrupt": "escape", "session_compact": "<leader>c", + "session_child_first": "<leader>down", "session_child_cycle": "<leader>right", "session_child_cycle_reverse": "<leader>left", "session_parent": "<leader>up", @@ -107,21 +108,21 @@ opencode는 opencode config를 통해 사용자 정의 할 수있는 keybinds ## 리더 키 -opencode는 대부분의 keybinds에 대한 `leader` 키를 사용합니다. 이것은 당신의 terminal에 있는 충돌을 피합니다. +OpenCode는 대부분의 keybinds에 `leader` 키를 사용합니다. 이렇게 하면 terminal에서 충돌을 피할 수 있습니다. -기본적으로 `ctrl+x`는 리더 키이며 대부분의 작업은 리더 키를 먼저 누르고 단축키를 누릅니다. 예를 들어, 새 세션을 시작하려면 먼저 `ctrl+x`를 누르고 `n`를 누릅니다. +기본값으로 `ctrl+x`가 리더 키이며, 대부분의 작업은 먼저 리더 키를 누른 뒤 단축키를 누릅니다. 예를 들어 새 세션을 시작하려면 먼저 `ctrl+x`를 누르고 `n`을 누릅니다. -키바인드에 리더 키를 사용할 필요는 없지만, 사용하는 것을 권장합니다. +keybinds에 리더 키를 꼭 사용할 필요는 없지만, 사용하는 것을 권장합니다. --- ## 키바인드 비활성화 -"none"의 값으로 구성에 키를 추가하여 keybind를 비활성화 할 수 있습니다. +`tui.json`에 해당 키를 값 `"none"`으로 추가하면 키바인드를 비활성화할 수 있습니다. -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "keybinds": { "session_compact": "none" } @@ -132,39 +133,39 @@ opencode는 대부분의 keybinds에 대한 `leader` 키를 사용합니다. 이 ## 데스크탑 프롬프트 단축키 -opencode 데스크톱 앱 프롬프트 입력은 텍스트 편집을 위한 일반적인 Readline/Emacs-style 단축키를 지원합니다. 이들은 내장되어 있으며 현재 `opencode.json`를 통해 구성할 수 없습니다. +OpenCode 데스크톱 앱의 프롬프트 입력은 텍스트 편집을 위한 일반적인 Readline/Emacs-style 단축키를 지원합니다. 이 단축키는 내장되어 있으며 현재 `opencode.json`으로는 설정할 수 없습니다. -| 단축키 | 동작 | -| -------- | -------------------------- | -| `ctrl+a` | 현재 행 시작으로 이동 | -| `ctrl+e` | 현재선 끝으로 이동 | -| `ctrl+b` | 커서를 다시 한 문자로 이동 | -| `ctrl+f` | 한자 앞의 커서 | -| `alt+b` | 한 단어로 커서 이동 | -| `alt+f` | 한 단어를 넘겨 주세요 | -| `ctrl+d` | 커서의 캐릭터 삭제 | -| `ctrl+k` | 노선의 종료 | -| `ctrl+u` | 노선 시작 | -| `ctrl+w` | 이전 단어 | -| `alt+d` | 다음 단어를 죽이기 | -| `ctrl+t` | 자가용 캐릭터 | -| `ctrl+g` | 팝오버를 취소 / 응답 취소 | +| 단축키 | 동작 | +| -------- | --------------------------------- | +| `ctrl+a` | 현재 줄 시작으로 이동 | +| `ctrl+e` | 현재 줄 끝으로 이동 | +| `ctrl+b` | 커서를 문자 하나 뒤로 이동 | +| `ctrl+f` | 커서를 문자 하나 앞으로 이동 | +| `alt+b` | 커서를 단어 하나 뒤로 이동 | +| `alt+f` | 커서를 단어 하나 앞으로 이동 | +| `ctrl+d` | 커서 아래 문자 삭제 | +| `ctrl+k` | 줄 끝까지 삭제 | +| `ctrl+u` | 줄 시작까지 삭제 | +| `ctrl+w` | 이전 단어 삭제 | +| `alt+d` | 다음 단어 삭제 | +| `ctrl+t` | 문자 순서 바꾸기 | +| `ctrl+g` | 팝오버 취소 / 실행 중인 응답 중단 | --- ## Shift+Enter -몇몇 terminal은 기본적으로 입력한 보조 키를 보내지 않습니다. `Shift+Enter`를 이스케이프 시퀀스로 보낼 terminal을 구성해야 할 수 있습니다. +일부 terminal은 기본적으로 Enter와 modifier 키 조합을 전송하지 않습니다. `Shift+Enter`를 이스케이프 시퀀스로 전송하도록 terminal을 설정해야 할 수도 있습니다. ### Windows Terminal -`settings.json`를 엽니다: +다음 경로의 `settings.json`을 여세요: ``` %LOCALAPPDATA%\Packages\Microsoft.WindowsTerminal_8wekyb3d8bbwe\LocalState\settings.json ``` -루트 레벨 `actions` 배열에 이것을 추가하십시오: +루트 레벨 `actions` 배열에 다음을 추가하세요: ```json "actions": [ @@ -178,7 +179,7 @@ opencode 데스크톱 앱 프롬프트 입력은 텍스트 편집을 위한 일 ] ``` -루트 레벨 `keybindings` 배열에 이것을 추가하십시오: +루트 레벨 `keybindings` 배열에 다음을 추가하세요: ```json "keybindings": [ @@ -189,4 +190,4 @@ opencode 데스크톱 앱 프롬프트 입력은 텍스트 편집을 위한 일 ] ``` -파일을 저장하고 Windows Terminal을 다시 시작하거나 새 탭을 엽니 다. +파일을 저장한 뒤 Windows Terminal을 다시 시작하거나 새 탭을 여세요. diff --git a/packages/web/src/content/docs/ko/lsp.mdx b/packages/web/src/content/docs/ko/lsp.mdx index 31d3dda26d..c1786f6aef 100644 --- a/packages/web/src/content/docs/ko/lsp.mdx +++ b/packages/web/src/content/docs/ko/lsp.mdx @@ -1,62 +1,63 @@ --- title: LSP 서버 -description: OpenCode는 LSP 서버와 통합되어 작동합니다. +description: OpenCode는 LSP 서버와 통합됩니다. --- -OpenCode는 언어 서버 프로토콜(LSP)과 통합되어 LLM이 코드베이스와 상호 작용할 수 있게 돕습니다. 이를 통해 진단 정보를 사용하여 LLM에 피드백을 제공합니다. +OpenCode는 Language Server Protocol(LSP)과 통합되어 LLM이 코드베이스와 상호작용하도록 돕습니다. 진단 정보를 활용해 LLM에 피드백을 제공합니다. --- ## 기본 제공 (Built-in) -OpenCode는 인기 있는 언어들에 대해 여러 내장 LSP 서버를 제공합니다. +OpenCode는 널리 사용되는 언어를 위해 여러 built-in LSP 서버를 제공합니다. -| LSP 서버 | 확장자 | 요구사항 | -| ------------------ | ------------------------------------------------------------------ | ----------------------------------------------------- | -| astro | .astro | Astro 프로젝트 자동 설치 | -| bash | .sh, .bash, .zsh, .ksh | bash-language-server 자동 설치 | -| clangd | .c, .cpp, .cc, .cxx, .c++, .h, .hpp, .hh, .hxx, .h++ | C/C++ 프로젝트용 자동 설치 | -| csharp | .cs | `.NET SDK` 설치 | -| clojure-lsp | .clj, .cljs, .cljc, .edn | `clojure-lsp` 명령 사용 가능 | -| dart | .dart | `dart` 명령 사용 가능 | -| deno | .ts, .tsx, .js, .jsx, .mjs | `deno` 명령 사용 가능(deno.json/deno.jsonc 자동 감지) | -| elixir-ls | .ex, .exs | `elixir` 명령 사용 가능 | -| eslint | .ts, .tsx, .js, .jsx, .mjs, .cjs, .mts, .cts, .vue | 프로젝트의 `eslint` 의존성 | -| fsharp | .fs, .fsi, .fsx, .fsscript | `.NET SDK` 설치 | -| gleam | .gleam | `gleam` 명령 사용 가능 | -| gopls | .go | `go` 명령 사용 가능 | -| hls | .hs, .lhs | `haskell-language-server-wrapper` 명령 사용 가능 | -| jdtls | .java | `Java SDK (version 21+)` 설치 | -| kotlin-ls | .kt, .kts | Kotlin 프로젝트용 자동 설치 | -| lua-ls | .lua | Lua 프로젝트용 자동 설치 | -| nixd | .nix | `nixd` 명령 사용 가능 | -| ocaml-lsp | .ml, .mli | `ocamllsp` 명령 사용 가능 | -| oxlint | .ts, .tsx, .js, .jsx, .mjs, .cjs, .mts, .ct, .vue, .astro, .svelte | 프로젝트의 `oxlint` 의존성 | -| PHP intelephense | .php | PHP 프로젝트 자동 설치 | -| prisma | .prisma | `prisma` 명령 사용 가능 | -| pyright | .py, .pyi | `pyright` 의존성 설치 | -| ruby-lsp (rubocop) | .rb, .rake, .gemspec, .ru | `ruby` 및 `gem` 명령 사용 가능 | -| rust | .rs | `rust-analyzer` 명령 사용 가능 | -| sourcekit-lsp | .swift, .objc, .objcpp | `swift` 설치 (macOS의 `xcode`) | -| svelte | .svelte | Svelte 프로젝트 자동 설치 | -| terraform | .tf, .tfvars | GitHub 릴리스에서 자동 설치 | -| typst | .typ, .typc | GitHub 릴리스에서 자동 설치 | -| typescript | .ts, .tsx, .js, .jsx, .mjs, .cjs, .mts, .cts | 프로젝트의 `typescript` 의존성 | -| vue | .vue | Vue 프로젝트 자동 설치 | -| yaml-ls | .yaml, .yml | Red Hat yaml-language-server 자동 설치 | -| zls | .zig, .zon | `zig` 명령 사용 가능 | +| LSP 서버 | 확장자 | 요구 사항 | +| ------------------ | ------------------------------------------------------------------- | ---------------------------------------------------------- | +| astro | .astro | Astro 프로젝트에서 자동 설치 | +| bash | .sh, .bash, .zsh, .ksh | `bash-language-server` 자동 설치 | +| clangd | .c, .cpp, .cc, .cxx, .c++, .h, .hpp, .hh, .hxx, .h++ | C/C++ 프로젝트에서 자동 설치 | +| csharp | .cs | `.NET SDK` 설치됨 | +| clojure-lsp | .clj, .cljs, .cljc, .edn | `clojure-lsp` 명령 사용 가능 | +| dart | .dart | `dart` 명령 사용 가능 | +| deno | .ts, .tsx, .js, .jsx, .mjs | `deno` 명령 사용 가능 (`deno.json`/`deno.jsonc` 자동 감지) | +| elixir-ls | .ex, .exs | `elixir` 명령 사용 가능 | +| eslint | .ts, .tsx, .js, .jsx, .mjs, .cjs, .mts, .cts, .vue | 프로젝트에 `eslint` dependency 존재 | +| fsharp | .fs, .fsi, .fsx, .fsscript | `.NET SDK` 설치됨 | +| gleam | .gleam | `gleam` 명령 사용 가능 | +| gopls | .go | `go` 명령 사용 가능 | +| hls | .hs, .lhs | `haskell-language-server-wrapper` 명령 사용 가능 | +| jdtls | .java | `Java SDK (version 21+)` 설치됨 | +| julials | .jl | `julia` 및 `LanguageServer.jl` 설치됨 | +| kotlin-ls | .kt, .kts | Kotlin 프로젝트에서 자동 설치 | +| lua-ls | .lua | Lua 프로젝트에서 자동 설치 | +| nixd | .nix | `nixd` 명령 사용 가능 | +| ocaml-lsp | .ml, .mli | `ocamllsp` 명령 사용 가능 | +| oxlint | .ts, .tsx, .js, .jsx, .mjs, .cjs, .mts, .cts, .vue, .astro, .svelte | 프로젝트에 `oxlint` dependency 존재 | +| php intelephense | .php | PHP 프로젝트에서 자동 설치 | +| prisma | .prisma | `prisma` 명령 사용 가능 | +| pyright | .py, .pyi | `pyright` dependency 설치됨 | +| ruby-lsp (rubocop) | .rb, .rake, .gemspec, .ru | `ruby` 및 `gem` 명령 사용 가능 | +| rust | .rs | `rust-analyzer` 명령 사용 가능 | +| sourcekit-lsp | .swift, .objc, .objcpp | `swift` 설치됨 (macOS에서는 `xcode`) | +| svelte | .svelte | Svelte 프로젝트에서 자동 설치 | +| terraform | .tf, .tfvars | GitHub releases에서 자동 설치 | +| tinymist | .typ, .typc | GitHub releases에서 자동 설치 | +| typescript | .ts, .tsx, .js, .jsx, .mjs, .cjs, .mts, .cts | 프로젝트에 `typescript` dependency 존재 | +| vue | .vue | Vue 프로젝트에서 자동 설치 | +| yaml-ls | .yaml, .yml | Red Hat `yaml-language-server` 자동 설치 | +| zls | .zig, .zon | `zig` 명령 사용 가능 | -LSP 서버는 위 파일 확장자 중 하나가 감지되고 요구 사항이 충족되면 자동으로 활성화됩니다. +위 확장자 중 하나가 감지되고 요구 사항이 충족되면 LSP 서버가 자동으로 활성화됩니다. :::note -`OPENCODE_DISABLE_LSP_DOWNLOAD` 환경 변수를 `true`로 설정하여 자동 LSP 서버 다운로드를 비활성화 할 수 있습니다. +`OPENCODE_DISABLE_LSP_DOWNLOAD` 환경 변수를 `true`로 설정하면 LSP 서버 자동 다운로드를 비활성화할 수 있습니다. ::: --- ## 작동 방식 -OpenCode가 파일을 열 때, 다음과 같이 작동합니다: +OpenCode가 파일을 열면 다음과 같이 동작합니다. 1. 활성화된 모든 LSP 서버에 대해 파일 확장자를 확인합니다. 2. 적절한 LSP 서버가 아직 실행 중이지 않다면 시작합니다. @@ -65,7 +66,7 @@ OpenCode가 파일을 열 때, 다음과 같이 작동합니다: ## 구성 -OpenCode 설정의 `lsp` 섹션을 통해 LSP 서버를 사용자 정의할 수 있습니다. +OpenCode config의 `lsp` 섹션에서 LSP 서버를 사용자 정의할 수 있습니다. ```json title="opencode.json" { @@ -74,23 +75,23 @@ OpenCode 설정의 `lsp` 섹션을 통해 LSP 서버를 사용자 정의할 수 } ``` -각 LSP 서버는 다음을 지원합니다: +각 LSP 서버는 다음 속성을 지원합니다. -| 속성 | 유형 | 설명 | -| ---------------- | -------- | --------------------------------------- | -| `disabled` | boolean | LSP 서버를 비활성화하려면 `true`로 설정 | -| `command` | string[] | LSP 서버를 시작하는 명령 | -| `extensions` | string[] | 이 LSP 서버의 확장자 | -| `env` | object | 서버 시작 시 설정할 환경 변수 | -| `initialization` | object | LSP 서버에 보내는 초기화 옵션 | +| 속성 | 타입 | 설명 | +| ---------------- | -------- | --------------------------------------------- | +| `disabled` | boolean | LSP 서버를 비활성화하려면 `true`로 설정하세요 | +| `command` | string[] | LSP 서버를 시작하는 명령입니다 | +| `extensions` | string[] | 이 LSP 서버가 처리할 파일 확장자입니다 | +| `env` | object | 서버 시작 시 설정할 환경 변수입니다 | +| `initialization` | object | LSP 서버로 전송할 초기화 옵션입니다 | -몇 가지 예제를 살펴봅시다. +예시를 살펴보겠습니다. --- -## 환경 변수 +### 환경 변수 -`env` 속성을 사용하여 LSP 서버를 시작할 때 환경 변수를 설정합니다. +`env` 속성을 사용하면 LSP 서버 시작 시 환경 변수를 설정할 수 있습니다. ```json title="opencode.json" {5-7} { @@ -109,7 +110,7 @@ OpenCode 설정의 `lsp` 섹션을 통해 LSP 서버를 사용자 정의할 수 ### 초기화 옵션 -`initialization` 속성을 사용하여 초기화 옵션을 LSP 서버에 전달합니다. 이들은 LSP `initialize` 요청에 보내진 서버 별 설정입니다. +`initialization` 속성을 사용해 LSP 서버에 초기화 옵션을 전달하세요. 이 값은 LSP `initialize` 요청 중에 전송되는 서버별 설정입니다. ```json title="opencode.json" {5-9} { @@ -127,14 +128,14 @@ OpenCode 설정의 `lsp` 섹션을 통해 LSP 서버를 사용자 정의할 수 ``` :::note -초기화 옵션은 LSP 서버가 다릅니다. LSP 서버의 사용 가능한 옵션을 확인하세요. +초기화 옵션은 LSP 서버마다 다릅니다. 사용 가능한 옵션은 해당 LSP 서버 문서를 확인하세요. ::: --- ### LSP 서버 비활성화 -전역적으로 **모든** LSP 서버를 비활성화하려면 `lsp`를 `false`로 설정하십시오. +전역에서 **모든** LSP 서버를 비활성화하려면 `lsp`를 `false`로 설정하세요. ```json title="opencode.json" {3} { @@ -143,7 +144,7 @@ OpenCode 설정의 `lsp` 섹션을 통해 LSP 서버를 사용자 정의할 수 } ``` -**특정** LSP 서버를 비활성화하려면 `disabled`를 `true`로 설정하십시오. +**특정** LSP 서버를 비활성화하려면 `disabled`를 `true`로 설정하세요. ```json title="opencode.json" {5} { @@ -160,7 +161,7 @@ OpenCode 설정의 `lsp` 섹션을 통해 LSP 서버를 사용자 정의할 수 ## 사용자 정의 LSP 서버 -명령어와 파일 확장자를 지정하여 사용자 정의 LSP 서버를 추가할 수 있습니다. +명령과 파일 확장자를 지정해 사용자 정의 LSP 서버를 추가할 수 있습니다. ```json title="opencode.json" {4-7} { @@ -180,9 +181,9 @@ OpenCode 설정의 `lsp` 섹션을 통해 LSP 서버를 사용자 정의할 수 ### PHP Intelephense -PHP Intelephense는 라이선스 키를 통해 프리미엄 기능을 제공합니다. 텍스트 파일에 키(만)를 저장하여 라이선스 키를 제공할 수 있습니다. +PHP Intelephense는 라이선스 키를 통해 프리미엄 기능을 제공합니다. 텍스트 파일에 키만 저장해 라이선스 키를 제공할 수 있습니다. - macOS/Linux: `$HOME/intelephense/license.txt` - Windows: `%USERPROFILE%/intelephense/license.txt` -파일에는 다른 내용이 없어야 합니다. +파일에는 추가 내용 없이 라이선스 키만 포함하는 것이 좋습니다. diff --git a/packages/web/src/content/docs/ko/plugins.mdx b/packages/web/src/content/docs/ko/plugins.mdx index 7214f32658..f20eb90c46 100644 --- a/packages/web/src/content/docs/ko/plugins.mdx +++ b/packages/web/src/content/docs/ko/plugins.mdx @@ -3,7 +3,7 @@ title: 플러그인 description: OpenCode를 확장하기 위해 자신만의 플러그인을 작성하세요. --- -플러그인은 다양한 이벤트와 사용자 정의 행동으로 후킹하여 opencode를 확장 할 수 있습니다. 플러그인을 만들 수 있습니다 새로운 기능을 추가, 외부 서비스와 통합, 또는 opencode의 기본 동작을 수정. +플러그인은 다양한 이벤트와 사용자 정의 행동으로 후킹하여 opencode를 확장 할 수 있습니다. 플러그인을 사용하여 새로운 기능을 추가하거나, 외부 서비스와 통합하거나, opencode의 기본 동작을 수정할 수 있습니다. 예를 들어, 커뮤니티에 의해 생성 된 [plugins](/docs/ecosystem#plugins)를 확인하십시오. @@ -11,18 +11,18 @@ description: OpenCode를 확장하기 위해 자신만의 플러그인을 작성 ## 플러그인 사용 -플러그인을로드하는 두 가지 방법이 있습니다. +플러그인을 로드하는 두 가지 방법이 있습니다. --- -## 로컬 파일에서 +### 로컬 파일에서 플러그인 디렉토리에 JavaScript 또는 TypeScript 파일을 배치합니다. - `.opencode/plugins/` - 프로젝트 레벨 플러그인 - `~/.config/opencode/plugins/` - 글로벌 플러그인 -이 디렉토리의 파일은 자동으로 시작에로드됩니다. +이 디렉토리의 파일은 시작 시 자동으로 로드됩니다. --- @@ -37,43 +37,42 @@ config 파일에 npm 패키지를 지정합니다. } ``` -일반 및 범위의 npm 패키지 모두 지원됩니다. +일반 패키지 및 스코프 npm 패키지 모두 지원됩니다. [ecosystem](/docs/ecosystem#plugins)에서 사용할 수 있는 플러그인을 찾아보세요. --- -## 플러그인이 설치되는 방법 +### 플러그인이 설치되는 방법 -**npm 플러그인**은 시작시 Bun을 사용하여 자동으로 설치됩니다. 패키지와 그들의 의존성은 `~/.cache/opencode/node_modules/`에서 캐시됩니다. +**npm 플러그인**은 시작시 Bun을 사용하여 자동으로 설치됩니다. 패키지와 그 의존성은 `~/.cache/opencode/node_modules/`에 캐시됩니다. -**로컬 플러그인**은 플러그인 디렉토리에서 직접로드됩니다. 외부 패키지를 사용하려면 구성 디렉토리 내 `package.json`를 작성해야 합니다 ([Dependencies](#dependencies)), 또는 플러그인을 npm에 게시하고 [config에 추가](/docs/config#plugins). +**로컬 플러그인**은 플러그인 디렉토리에서 직접 로드됩니다. 외부 패키지를 사용하려면 구성 디렉토리 내에 `package.json`을 작성해야 하거나([의존성](#의존성) 참조), 플러그인을 npm에 게시하고 [config에 추가](/docs/config#plugins)해야 합니다. --- -## 로드 순서 +### 로드 순서 -플러그인은 모든 소스에서로드되며 모든 후크는 순서대로 실행됩니다. 로드 순서는 다음과 같습니다: +플러그인은 모든 소스에서 로드되며 모든 후크는 순서대로 실행됩니다. 로드 순서는 다음과 같습니다: 1. 글로벌 구성 (`~/.config/opencode/opencode.json`) 2. 프로젝트 구성 (`opencode.json`) 3. 글로벌 플러그인 디렉토리 (`~/.config/opencode/plugins/`) 4. 프로젝트 플러그인 디렉토리 (`.opencode/plugins/`) -중복 npm 패키지는 한 번만 로드됩니다. 하지만, 로컬 플러그인과 같은 이름과 npm 플러그인은 모두 별도로로드됩니다. +중복된 이름과 버전의 npm 패키지는 한 번만 로드됩니다. 하지만 로컬 플러그인과 npm 플러그인의 이름이 비슷하더라도 둘 다 별도로 로드됩니다. --- ## 플러그인 만들기 -플러그인은 **JavaScript/TypeScript 모듈**입니다. -기능. 각 함수는 context 객체를 수신하고 Hooks 객체를 반환합니다. +플러그인은 하나 이상의 플러그인 함수를 내보내는 **JavaScript/TypeScript 모듈**입니다. 각 함수는 context 객체를 수신하고 hooks 객체를 반환합니다. --- ### 의존성 -로컬 플러그인 및 사용자 정의 도구는 외부 npm 패키지를 사용할 수 있습니다. `package.json`를 config 디렉토리에 추가하면 필요한 의존도가 있습니다. +로컬 플러그인 및 사용자 정의 도구는 외부 npm 패키지를 사용할 수 있습니다. config 디렉토리에 `package.json`을 추가하고 필요한 의존성을 명시하십시오. ```json title=".opencode/package.json" { @@ -83,7 +82,7 @@ config 파일에 npm 패키지를 지정합니다. } ``` -opencode는 `bun install`를 시작합니다. 플러그인 및 도구가 가져올 수 있습니다. +opencode는 시작 시 `bun install`을 실행하여 이를 설치합니다. 이후 플러그인 및 도구에서 가져올 수 있습니다. ```ts title=".opencode/plugins/my-plugin.ts" import { escape } from "shescape" @@ -113,19 +112,19 @@ export const MyPlugin = async ({ project, client, $, directory, worktree }) => { } ``` -플러그인 기능 수신: +플러그인 함수가 받는 인자: - `project`: 현재 프로젝트 정보. - `directory`: 현재 작업 디렉토리. - `worktree`: git worktree 경로. - `client`: AI와 상호 작용을 위한 opencode SDK 클라이언트. -- `$`: Bun's [shell API](https://bun.com/docs/runtime/shell) 명령어를 실행합니다. +- `$`: 명령어를 실행하기 위한 Bun의 [shell API](https://bun.com/docs/runtime/shell). --- ### TypeScript 지원 -TypeScript 플러그인의 경우 플러그인 패키지에서 유형을 가져올 수 있습니다. +TypeScript 플러그인의 경우 플러그인 패키지에서 타입을 가져올 수 있습니다. ```ts title="my-plugin.ts" {1} import type { Plugin } from "@opencode-ai/plugin" @@ -139,29 +138,29 @@ export const MyPlugin: Plugin = async ({ project, client, $, directory, worktree --- -## 이벤트 +### 이벤트 -플러그인은 예제 섹션에서 아래에서 볼 때 이벤트에 가입 할 수 있습니다. 여기에 다른 이벤트의 목록입니다. +플러그인은 아래 예제 섹션에서 볼 수 있듯이 이벤트를 구독할 수 있습니다. 사용 가능한 이벤트 목록은 다음과 같습니다. -### 명령어 이벤트 +#### 명령어 이벤트 - `command.executed` -### 파일 이벤트 +#### 파일 이벤트 - `file.edited` - `file.watcher.updated` -### 설치 이벤트 +#### 설치 이벤트 - `installation.updated` -### LSP 이벤트 +#### LSP 이벤트 - `lsp.client.diagnostics` - `lsp.updated` -### 메시지 이벤트 +#### 메시지 이벤트 - `message.part.removed` - `message.part.updated` @@ -173,11 +172,11 @@ export const MyPlugin: Plugin = async ({ project, client, $, directory, worktree - `permission.asked` - `permission.replied` -### 서버 이벤트 +#### 서버 이벤트 - `server.connected` -### 세션 이벤트 +#### 세션 이벤트 - `session.created` - `session.compacted` @@ -188,7 +187,7 @@ export const MyPlugin: Plugin = async ({ project, client, $, directory, worktree - `session.status` - `session.updated` -### Todo 이벤트 +#### Todo 이벤트 - `todo.updated` @@ -196,7 +195,7 @@ export const MyPlugin: Plugin = async ({ project, client, $, directory, worktree - `shell.env` -##### 도구 이벤트 +#### 도구 이벤트 - `tool.execute.after` - `tool.execute.before` @@ -211,11 +210,11 @@ export const MyPlugin: Plugin = async ({ project, client, $, directory, worktree ## 예제 -opencode를 확장하기 위해 사용할 수있는 플러그인의 몇 가지 예입니다. +opencode를 확장하기 위해 사용할 수 있는 플러그인 예제입니다. --- -## 알림 보내기 +### 알림 보내기 특정 이벤트가 발생할 때 알림을 전송: @@ -232,7 +231,7 @@ export const NotificationPlugin = async ({ project, client, $, directory, worktr } ``` -macOS에서 AppleScript를 실행하려면 `osascript`를 사용하고 있습니다. 여기에 우리는 그것을 사용하여 알림을 보낼 수 있습니다. +macOS에서 AppleScript를 실행하기 위해 `osascript`를 사용하고 있습니다. 여기서는 알림을 보내는 데 사용합니다. :::note opencode 데스크톱 앱을 사용하는 경우 응답이 준비되어 있거나 세션 오류가 있을 때 시스템 알림을 자동으로 보낼 수 있습니다. @@ -242,7 +241,7 @@ opencode 데스크톱 앱을 사용하는 경우 응답이 준비되어 있거 ### .env 보호 -읽기 `.env` 파일에서 opencode를 방지하십시오: +opencode가 `.env` 파일을 읽지 못하도록 방지: ```javascript title=".opencode/plugins/env-protection.js" export const EnvProtection = async ({ project, client, $, directory, worktree }) => { @@ -260,7 +259,7 @@ export const EnvProtection = async ({ project, client, $, directory, worktree }) ### Inject 환경 변수 -환경 변수를 모든 shell 실행 (AI 도구 및 사용자 terminal)로 주사하십시오. +모든 shell 실행(AI 도구 및 사용자 terminal)에 환경 변수 주입: ```javascript title=".opencode/plugins/inject-env.js" export const InjectEnvPlugin = async () => { @@ -277,7 +276,7 @@ export const InjectEnvPlugin = async () => { ### 사용자 정의 도구 -플러그인은 opencode에 사용자 정의 도구를 추가 할 수 있습니다 : +플러그인은 opencode에 사용자 정의 도구를 추가할 수 있습니다: ```ts title=".opencode/plugins/custom-tools.ts" import { type Plugin, tool } from "@opencode-ai/plugin" @@ -300,13 +299,17 @@ export const CustomToolsPlugin: Plugin = async (ctx) => { } ``` -`tool` helper는 opencode가 호출 할 수있는 사용자 정의 도구를 만듭니다. Zod schema 기능을 가지고 도구 정의를 반환: +`tool` helper는 opencode가 호출할 수 있는 사용자 정의 도구를 만듭니다. Zod 스키마 함수를 받고 다음을 포함하는 도구 정의를 반환합니다: -- `description`: 도구는 무엇을 +- `description`: 도구가 하는 일 - `args`: 도구의 인수에 대한 Zod 스키마 -- `execute`: 도구가 호출될 때 실행되는 기능 +- `execute`: 도구가 호출될 때 실행되는 함수 -사용자 정의 도구는 내장 도구와 함께 opencode를 사용할 수 있습니다. +사용자 정의 도구는 내장 도구와 함께 opencode에서 사용할 수 있습니다. + +:::note +플러그인 도구가 내장 도구와 같은 이름을 사용하면 플러그인 도구가 우선순위를 갖습니다. +::: --- @@ -331,9 +334,9 @@ export const MyPlugin = async ({ client }) => { --- -## Compaction 훅 +### Compaction 훅 -세션이 압축 될 때 포함 된 컨텍스트를 사용자 지정: +세션이 압축될 때 포함되는 컨텍스트를 사용자 지정할 수 있습니다: ```ts title=".opencode/plugins/compaction.ts" import type { Plugin } from "@opencode-ai/plugin" @@ -355,9 +358,9 @@ Include any state that should persist across compaction: } ``` -LLM이 압축 요약을 생성하기 전에 `experimental.session.compacting` 훅이 실행됩니다. 기본 압축 프롬프트를 대체할 수 있도록 도메인 별 컨텍스트를 주입합니다. +`experimental.session.compacting` 훅은 LLM이 연속 요약을 생성하기 전에 실행됩니다. 기본 압축 프롬프트가 놓칠 수 있는 도메인별 컨텍스트를 주입하는 데 사용하세요. -당신은 또한 `output.prompt`를 조정해서 조밀함을 전적으로 대체할 수 있습니다: +또한 `output.prompt`를 설정하여 압축 프롬프트를 완전히 대체할 수도 있습니다: ```ts title=".opencode/plugins/custom-compaction.ts" import type { Plugin } from "@opencode-ai/plugin" @@ -382,4 +385,4 @@ Format as a structured prompt that a new agent can use to resume work. } ``` -`output.prompt`가 설정되면 완전히 기본 압축 프롬프트를 대체합니다. `output.context` 배열은 이 경우에 무시됩니다. +`output.prompt`가 설정되면 기본 압축 프롬프트를 완전히 대체합니다. 이 경우 `output.context` 배열은 무시됩니다. diff --git a/packages/web/src/content/docs/ko/providers.mdx b/packages/web/src/content/docs/ko/providers.mdx index ea48dbfb0a..c543c719dd 100644 --- a/packages/web/src/content/docs/ko/providers.mdx +++ b/packages/web/src/content/docs/ko/providers.mdx @@ -22,13 +22,13 @@ OpenCode는 [AI SDK](https://ai-sdk.dev/) 및 [Models.dev](https://models.dev) --- -#### 구성 +### 구성 OpenCode 설정의 `provider` 섹션을 통해 공급자를 사용자 정의할 수 있습니다. --- -### 기본 URL +#### 기본 URL `baseURL` 옵션을 설정하여 모든 공급자를 위한 기본 URL을 사용자 정의할 수 있습니다. 프록시 서비스 또는 사용자 정의 엔드포인트를 사용할 때 유용합니다. @@ -55,7 +55,38 @@ OpenCode Zen은 OpenCode 팀이 OpenCode와 잘 작동하도록 테스트하고 처음이라면 OpenCode Zen으로 시작하는 것이 좋습니다. ::: -1. TUI에서 `/connect` 명령을 실행하고 `opencode`를 선택한 뒤, [opencode.ai/auth](https://opencode.ai/auth)로 이동합니다. +1. TUI에서 `/connect` 명령을 실행하고 `OpenCode Zen`을 선택한 뒤, [opencode.ai/auth](https://opencode.ai/zen)로 이동합니다. + + ```txt + /connect + ``` + +2. 로그인하고 결제 정보를 입력한 후 API 키를 복사하십시오. + +3. API 키를 붙여넣습니다. + + ```txt + ┌ API key + │ + │ + └ enter + ``` + +4. TUI에서 `/models`를 실행하여 추천 모델 목록을 볼 수 있습니다. + + ```txt + /models + ``` + +OpenCode의 다른 공급자처럼 작동하며 사용은 완전히 선택 사항입니다. + +--- + +## OpenCode Go + +OpenCode Go는 OpenCode 팀이 테스트하고 검증하여 OpenCode와 잘 작동하는 인기 있는 오픈 코딩 모델에 안정적으로 액세스할 수 있는 저렴한 구독 요금제입니다. + +1. TUI에서 `/connect` 명령을 실행하고 `OpenCode Go`를 선택한 뒤 [opencode.ai/auth](https://opencode.ai/zen)로 이동하십시오. ```txt /connect @@ -129,15 +160,15 @@ OpenCode로 Amazon Bedrock을 사용하려면: Amazon Bedrock에서 원하는 모델에 대한 액세스 권한이 있어야 합니다. ::: -2. 다음 방법 중 하나를 사용하여 **설정**합니다: +2. 다음 방법 중 하나를 사용하여 **인증을 구성**합니다: ---- + *** -### 환경 변수 (빠른 시작) + #### 환경 변수 (빠른 시작) -OpenCode를 실행하는 동안 다음 환경 변수 중 하나를 설정합니다: + OpenCode를 실행하는 동안 다음 환경 변수 중 하나를 설정합니다: -```bash + ```bash # Option 1: Using AWS access keys AWS_ACCESS_KEY_ID=XXX AWS_SECRET_ACCESS_KEY=YYY opencode @@ -146,87 +177,84 @@ OpenCode를 실행하는 동안 다음 환경 변수 중 하나를 설정합니 # Option 3: Using Bedrock bearer token AWS_BEARER_TOKEN_BEDROCK=XXX opencode -``` + ``` -또는 bash 프로필에 추가합니다: + 또는 bash 프로필에 추가합니다: -```bash title="~/.bash_profile" + ```bash title="~/.bash_profile" export AWS_PROFILE=my-dev-profile export AWS_REGION=us-east-1 -``` + ``` ---- + *** -#### 설정 파일 (권장) + #### 구성 파일 (권장) -프로젝트별 또는 영구 구성을 위해 `opencode.json`을 사용하십시오. + 프로젝트별 또는 영구 구성을 위해 `opencode.json`을 사용하십시오: -```json title="opencode.json" -{ - "$schema": "https://opencode.ai/config.json", - "provider": { - "amazon-bedrock": { - "options": { - "region": "us-east-1", - "profile": "my-aws-profile" - } - } - } -} -``` + ```json title="opencode.json" + { + "$schema": "https://opencode.ai/config.json", + "provider": { + "amazon-bedrock": { + "options": { + "region": "us-east-1", + "profile": "my-aws-profile" + } + } + } + } + ``` -**유효한 옵션:** + **유효한 옵션:** + - `region` - AWS 리전 (예: `us-east-1`, `eu-west-1`) + - `profile` - `~/.aws/credentials`의 AWS 프로필 이름 + - `endpoint` - VPC 엔드포인트 등을 위한 사용자 정의 엔드포인트 URL (일반 `baseURL` 옵션의 별칭) -- `region` - AWS 리전 (예: `us-east-1`, `eu-west-1`) -- `profile` - `~/.aws/credentials`의 AWS 프로필 이름 -- `endpoint` - VPC 엔드포인트 등을 위한 사용자 정의 엔드포인트 URL (일반 `baseURL` 옵션의 별칭) + :::tip + 구성 파일 옵션은 환경 변수보다 우선 순위가 높습니다. + ::: - :::tip - 구성 파일 옵션은 환경 변수보다 우선 순위가 높습니다. - ::: + *** ---- + #### 고급: VPC 엔드포인트 -#### 고급: VPC 엔드포인트 + Bedrock의 VPC 엔드포인트를 사용하는 경우: -Bedrock의 VPC 엔드포인트를 사용하는 경우: + ```json title="opencode.json" + { + "$schema": "https://opencode.ai/config.json", + "provider": { + "amazon-bedrock": { + "options": { + "region": "us-east-1", + "profile": "production", + "endpoint": "https://bedrock-runtime.us-east-1.vpce-xxxxx.amazonaws.com" + } + } + } + } + ``` -```json title="opencode.json" -{ - "$schema": "https://opencode.ai/config.json", - "provider": { - "amazon-bedrock": { - "options": { - "region": "us-east-1", - "profile": "production", - "endpoint": "https://bedrock-runtime.us-east-1.vpce-xxxxx.amazonaws.com" - } - } - } -} -``` + :::note + `endpoint` 옵션은 일반적인 `baseURL` 옵션의 별칭입니다. `endpoint`와 `baseURL` 둘 다 지정된 경우 `endpoint`가 우선합니다. + ::: -:::note -`endpoint` 옵션은 일반적인 `baseURL` 옵션의 별칭입니다. `endpoint`와 `baseURL` 둘 다 지정된 경우 `endpoint`가 우선합니다. -::: + *** ---- + #### 인증 방법 + - **`AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY`**: IAM 사용자 및 AWS 콘솔에서 액세스 키 생성 + - **`AWS_PROFILE`**: `~/.aws/credentials`의 프로필 이름을 사용합니다. `aws configure --profile my-profile` 또는 `aws sso login`으로 먼저 구성하십시오. + - **`AWS_BEARER_TOKEN_BEDROCK`**: Amazon Bedrock 콘솔에서 임시 API 키 생성 + - **`AWS_WEB_IDENTITY_TOKEN_FILE` / `AWS_ROLE_ARN`**: EKS IRSA (서비스 계정용 IAM 역할) 또는 다른 Kubernetes 환경의 OIDC 연동. 이 환경 변수는 서비스 계정을 사용할 때 Kubernetes에 의해 자동으로 주입됩니다. -#### 인증 방법 + *** -- **`AWS_ACCESS_KEY_ID`/`AWS_SECRET_ACCESS_KEY`**: IAM 사용자 및 AWS 콘솔에서 액세스 키 생성 -- **`AWS_PROFILE`**: `~/.aws/credentials`의 프로필 이름을 사용합니다. `aws configure --profile my-profile` 또는 `aws sso login`으로 먼저 구성하십시오. -- **`AWS_BEARER_TOKEN_BEDROCK`**: Amazon Bedrock 콘솔에서 임시 API 키 생성 -- **`AWS_WEB_IDENTITY_TOKEN_FILE` / `AWS_ROLE_ARN`**: EKS IRSA (서비스 계정용 IAM 역할) 또는 다른 Kubernetes 환경의 OIDC 연동. 이 환경 변수는 서비스 계정을 사용할 때 Kubernetes에 의해 자동으로 주입됩니다. + #### 인증 우선 순위 ---- - -#### 인증 우선 순위 - -Amazon Bedrock은 다음과 같은 인증 우선 순위를 사용합니다. - -1. **Bearer Token** - `AWS_BEARER_TOKEN_BEDROCK` 환경 변수 또는 `/connect` 명령의 토큰 -2. **AWS Credential Chain** - 프로필, 액세스 키, 공유 자격 증명, IAM 역할, 웹 ID 토큰 (EKS IRSA), 인스턴스 메타데이터 + Amazon Bedrock은 다음과 같은 인증 우선 순위를 사용합니다. + 1. **Bearer Token** - `AWS_BEARER_TOKEN_BEDROCK` 환경 변수 또는 `/connect` 명령의 토큰 + 2. **AWS Credential Chain** - 프로필, 액세스 키, 공유 자격 증명, IAM 역할, 웹 ID 토큰 (EKS IRSA), 인스턴스 메타데이터 :::note Bearer 토큰을 설정할 때 (`/connect` 또는 `AWS_BEARER_TOKEN_BEDROCK`를 통해), 구성된 프로필을 포함한 모든 AWS 자격 증명 방법보다 우선 순위가 높습니다. @@ -260,7 +288,7 @@ Amazon Bedrock은 다음과 같은 인증 우선 순위를 사용합니다. --- -#### Anthropic +### Anthropic 1. 가입 후 `/connect` 명령을 실행하고 **Anthropic**을 선택합니다. @@ -268,7 +296,7 @@ Amazon Bedrock은 다음과 같은 인증 우선 순위를 사용합니다. /connect ``` -2. **Claude Pro/Max** 옵션을 선택하면 브라우저가 열립니다. +2. **Claude Pro/Max** 옵션을 선택하면 브라우저가 열리고 인증을 요청합니다. ```txt ┌ Select auth method @@ -300,7 +328,7 @@ Pro/Max 구독이 없는 경우 **Create an API Key**를 선택할 수 있습니 ### Azure OpenAI :::note -"I'm sorry, but I can't support that request" 오류가 발생하면, Azure 리소스의 콘텐츠 필터를 **DefaultV2**에서 **Default**로 변경해 보세요. +"I'm sorry, but I cannot assist with that request" 오류가 발생하면, Azure 리소스의 콘텐츠 필터를 **DefaultV2**에서 **Default**로 변경해 보세요. ::: 1. [Azure 포털](https://portal.azure.com/)로 이동하여 **Azure OpenAI** 리소스를 만듭니다. 다음이 필요합니다: @@ -395,7 +423,7 @@ Pro/Max 구독이 없는 경우 **Create an API Key**를 선택할 수 있습니 --- -#### Baseten +### Baseten 1. [Baseten](https://app.baseten.co/)으로 이동하여 계정을 만들고 API 키를 생성합니다. @@ -422,7 +450,7 @@ Pro/Max 구독이 없는 경우 **Create an API Key**를 선택할 수 있습니 --- -#### Cerebras +### Cerebras 1. [Cerebras 콘솔](https://inference.cerebras.ai/)로 이동하여 계정을 만들고 API 키를 생성합니다. @@ -441,7 +469,7 @@ Pro/Max 구독이 없는 경우 **Create an API Key**를 선택할 수 있습니 └ enter ``` -4. `/models` 명령을 실행하여 모델(예: Qwen 3 Coder 480B)을 선택하십시오. +4. `/models` 명령을 실행하여 모델(예: _Qwen 3 Coder 480B_)을 선택하십시오. ```txt /models @@ -449,7 +477,7 @@ Pro/Max 구독이 없는 경우 **Create an API Key**를 선택할 수 있습니 --- -## Cloudflare AI Gateway +### Cloudflare AI Gateway Cloudflare AI Gateway는 OpenAI, Anthropic, Workers AI 등의 모델에 액세스할 수 있으며, 통합된 엔드포인트를 통해 더 많은 기능을 제공합니다. [Unified Billing](https://developers.cloudflare.com/ai-gateway/features/unified-billing/)을 사용하면 각 공급자의 별도 API 키가 필요하지 않습니다. @@ -507,7 +535,7 @@ Cloudflare AI Gateway는 OpenAI, Anthropic, Workers AI 등의 모델에 액세 --- -#### Cortecs +### Cortecs 1. [Cortecs 콘솔](https://cortecs.ai/)로 이동하여 계정을 만들고 API 키를 생성합니다. @@ -526,7 +554,7 @@ Cloudflare AI Gateway는 OpenAI, Anthropic, Workers AI 등의 모델에 액세 └ enter ``` -4. `/models` 명령을 실행하여 모델(예: Kimi K2 Instruct)을 선택하십시오. +4. `/models` 명령을 실행하여 모델(예: _Kimi K2 Instruct_)을 선택하십시오. ```txt /models @@ -534,7 +562,7 @@ Cloudflare AI Gateway는 OpenAI, Anthropic, Workers AI 등의 모델에 액세 --- -## DeepSeek +### DeepSeek 1. [DeepSeek 콘솔](https://platform.deepseek.com/)로 이동하여 계정을 만들고 **API Keys**를 클릭하여 키를 생성합니다. @@ -553,7 +581,7 @@ Cloudflare AI Gateway는 OpenAI, Anthropic, Workers AI 등의 모델에 액세 └ enter ``` -4. `/models` 명령을 실행하여 DeepSeek 모델(예: DeepSeek Reasoner)을 선택하십시오. +4. `/models` 명령을 실행하여 DeepSeek 모델(예: _DeepSeek Reasoner_)을 선택하십시오. ```txt /models @@ -561,7 +589,7 @@ Cloudflare AI Gateway는 OpenAI, Anthropic, Workers AI 등의 모델에 액세 --- -## Deep Infra +### Deep Infra 1. [Deep Infra 대시보드](https://deepinfra.com/dash)로 이동하여 계정을 만들고 API 키를 생성합니다. @@ -588,7 +616,7 @@ Cloudflare AI Gateway는 OpenAI, Anthropic, Workers AI 등의 모델에 액세 --- -## Firmware +### Firmware 1. [Firmware 대시보드](https://app.firmware.ai/signup)로 이동하여 계정을 만들고 API 키를 생성합니다. @@ -615,7 +643,7 @@ Cloudflare AI Gateway는 OpenAI, Anthropic, Workers AI 등의 모델에 액세 --- -## Fireworks AI +### Fireworks AI 1. [Fireworks AI 콘솔](https://app.fireworks.ai/)로 이동하여 계정을 만들고 **API Keys**를 클릭합니다. @@ -634,7 +662,7 @@ Cloudflare AI Gateway는 OpenAI, Anthropic, Workers AI 등의 모델에 액세 └ enter ``` -4. `/models` 명령을 실행하여 모델(예: Kimi K2 Instruct)을 선택하십시오. +4. `/models` 명령을 실행하여 모델(예: _Kimi K2 Instruct_)을 선택하십시오. ```txt /models @@ -662,38 +690,33 @@ GitLab Duo는 GitLab의 Anthropic 프록시를 통해 기본 도구 호출 기 └ ``` -#### OAuth 사용 (권장) + #### OAuth 사용 (권장) -**OAuth**를 선택하면 브라우저에서 권한 부여를 요청합니다. + **OAuth**를 선택하면 브라우저가 열리고 인증을 요청합니다. ---- + #### 개인 액세스 토큰 사용 + 1. [GitLab User Settings > Access Tokens](https://gitlab.com/-/user_settings/personal_access_tokens)로 이동 + 2. **Add new token** 클릭 + 3. 이름: `OpenCode`, 범위: `api` + 4. 토큰 복사 (`glpat-`로 시작) + 5. 터미널에 입력 -### 개인 액세스 토큰 사용 - -1. [GitLab User Settings > Access Tokens](https://gitlab.com/-/user_settings/personal_access_tokens)로 이동 -2. 새 토큰 추가 -3. 이름: `OpenCode`, 범위: `api` -4. 토큰 복사 (`glpat-`로 시작) -5. 터미널에 입력하십시오. - -6. 사용 가능한 모델을 보려면 `/models` 명령을 실행하십시오. +3. `/models` 명령을 실행하여 사용 가능한 모델을 확인하십시오. ```txt /models ``` -세 가지 Claude 기반 모델을 사용할 수 있습니다: - -- **duo-chat-haiku-4-5** (기본값) - 빠른 작업을 위한 빠른 응답 -- **duo-chat-sonnet-4-5** - 대부분의 워크플로우에 균형 잡힌 성능 -- **duo-chat-opus-4-5** - 복잡한 분석 가능 + 세 가지 Claude 기반 모델을 사용할 수 있습니다: + - **duo-chat-haiku-4-5** (기본값) - 빠른 작업을 위한 빠른 응답 + - **duo-chat-sonnet-4-5** - 대부분의 워크플로우에 균형 잡힌 성능 + - **duo-chat-opus-4-5** - 복잡한 분석에 적합 :::note -`GITLAB_TOKEN` 환경 변수를 지정할 수도 있습니다. -OpenCode는 인증 저장소에 토큰을 저장합니다. +`GITLAB_TOKEN` 환경 변수를 지정하여 토큰을 저장하지 않고 사용할 수도 있습니다. ::: -#### 셀프 호스팅 GitLab (Self-Hosted) +#### 셀프 호스팅 GitLab :::note[규정 준수 참고 사항] OpenCode는 세션 제목 생성과 같은 일부 AI 작업을 위해 작은 모델을 사용합니다. @@ -711,7 +734,7 @@ OpenCode를 자체 호스팅 GitLab 인스턴스만 사용하도록 제한하려 ::: -자체 호스팅 GitLab 인스턴스: +자체 호스팅 GitLab 인스턴스의 경우: ```bash export GITLAB_INSTANCE_URL=https://gitlab.company.com @@ -721,7 +744,7 @@ export GITLAB_TOKEN=glpat-... 인스턴스가 사용자 정의 AI Gateway를 실행하는 경우: ```bash -export GITLAB_AI_GATEWAY_URL=https://ai-gateway.company.com +GITLAB_AI_GATEWAY_URL=https://ai-gateway.company.com ``` 또는 bash 프로필에 추가: @@ -737,19 +760,18 @@ GitLab 관리자는 다음을 활성화해야 합니다: 1. [Duo Agent Platform](https://docs.gitlab.com/user/gitlab_duo/turn_on_off/) (사용자, 그룹 또는 인스턴스) 2. 기능 플래그 (Rails 콘솔을 통해): - -- `agent_platform_claude_code` -- `third_party_agents_enabled` - ::: + - `agent_platform_claude_code` + - `third_party_agents_enabled` + ::: #### 셀프 호스팅 인스턴스용 OAuth 자체 호스팅 인스턴스에 대해 OAuth를 작동시키려면 새로운 애플리케이션(Settings → Applications)을 만들어야 합니다. 콜백 URL `http://127.0.0.1:8080/callback` 및 다음 범위가 필요합니다: -- `api` (사용자 대신 API 액세스) -- `read_user` (개인 정보 읽기) -- `read_repository` (리포지토리 읽기 전용 액세스) +- api (사용자 대신 API 액세스) +- read_user (개인 정보 읽기) +- read_repository (리포지토리 읽기 전용 액세스) 그런 다음 애플리케이션 ID를 환경 변수로 노출하십시오: @@ -759,7 +781,7 @@ export GITLAB_OAUTH_CLIENT_ID=your_application_id_here [opencode-gitlab-auth](https://www.npmjs.com/package/@gitlab/opencode-gitlab-auth) 홈페이지에 추가 문서가 있습니다. -##### 구성 +#### 구성 `opencode.json`을 통해 사용자 정의: @@ -780,7 +802,7 @@ export GITLAB_OAUTH_CLIENT_ID=your_application_id_here } ``` -##### GitLab API 도구 (선택 사항이지만 강력 권장) +#### GitLab API 도구 (선택 사항이지만 강력 권장) GitLab 도구(병합 요청, 이슈, 파이프라인, CI/CD 등)에 액세스하려면: @@ -797,13 +819,10 @@ GitLab 도구(병합 요청, 이슈, 파이프라인, CI/CD 등)에 액세스하 ### GitHub Copilot -GitHub Copilot 구독을 사용하여 opencode: +OpenCode에서 GitHub Copilot 구독을 사용하려면: :::note -몇몇 모형은 [Pro+를 필요로 할지도 모릅니다 -구독](https://github.com/features/copilot/plans) 사용. - -일부 모델은 수동으로 활성화해야합니다 [GitHub Copilot 설정](https://docs.github.com/en/copilot/how-tos/use-ai-models/configure-access-to-ai-models#setup-for-individual-use). +일부 모델은 [Pro+ 구독](https://github.com/features/copilot/plans)이 필요할 수 있습니다. ::: 1. `/connect` 명령을 실행하고 GitHub Copilot을 검색하십시오. @@ -821,7 +840,8 @@ GitHub Copilot 구독을 사용하여 opencode: │ │ Enter code: 8F43-6FCF │ - └ Waiting for authorization... + │ Waiting for authorization... + └ ``` 3. 이제 원하는 모델을 선택하기 위해 `/models` 명령을 실행합니다. @@ -832,44 +852,42 @@ GitHub Copilot 구독을 사용하여 opencode: --- -### 구글 Vertex AI +### Google Vertex AI -opencode로 Google Vertex AI를 사용하려면: +OpenCode로 Google Vertex AI를 사용하려면: -1. Google Cloud Console에서 ** Model Garden**을 통해 헤드를 확인하고 확인하십시오. - 당신의 지역에서 유효한 모형. +1. Google Cloud Console의 **Model Garden**으로 이동하여 해당 리전에서 사용 가능한 모델을 확인하십시오. :::note - Vertex AI API를 사용하여 Google Cloud 프로젝트를 수행해야합니다. + Vertex AI API가 활성화된 Google Cloud 프로젝트가 있어야 합니다. ::: 2. 필요한 환경 변수를 설정: + - `GOOGLE_CLOUD_PROJECT`: 구글 클라우드 프로젝트 ID + - `VERTEX_LOCATION` (선택): Vertex AI 리전 (기본값: `global`) + - 인증 (하나 선택): + - `GOOGLE_APPLICATION_CREDENTIALS`: 서비스 계정 JSON 키 파일 경로 + - gcloud CLI 사용: `gcloud auth application-default login` -- `GOOGLE_CLOUD_PROJECT`: 당신의 구글 클라우드 프로젝트 ID -- `VERTEX_LOCATION` (선택): Vertex AI를 위한 지구 (`global`에 기본) -- 인증(초당): -- `GOOGLE_APPLICATION_CREDENTIALS`: 서비스 계정 JSON 키 파일 경로 -- gcloud CLI를 사용하여 인증 : `gcloud auth application-default login` + OpenCode를 실행할 때 설정: -opencode를 실행하면서 설정한다. - -```bash + ```bash GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account.json GOOGLE_CLOUD_PROJECT=your-project-id opencode -``` + ``` -또는 bash 프로파일에 추가하십시오. + 또는 bash 프로필에 추가: -```bash title="~/.bash_profile" + ```bash title="~/.bash_profile" export GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account.json export GOOGLE_CLOUD_PROJECT=your-project-id export VERTEX_LOCATION=global -``` + ``` :::tip -`global` 지구는 가용성을 개량하고 추가 비용 없이 과실을 감소시킵니다. 데이터 거주 요건에 대한 지역 엔드포인트(e.g., `us-central1`)를 사용하십시오. [더 알아보기](https://cloud.google.com/vertex-ai/generative-ai/docs/partner-models/use-partner-models#regional and global endpoints) +`global` 리전은 가용성을 높이고 오류를 줄이며 추가 비용이 없습니다. 데이터 거주 요건이 있는 경우 지역 엔드포인트(예: `us-central1`)를 사용하십시오. [더 알아보기](https://cloud.google.com/vertex-ai/generative-ai/docs/partner-models/use-partner-models#regional_and_global_endpoints) ::: -3. 당신이 원하는 모형을 선정하기 위하여 `/models` 명령을 실행하십시오. +3. `/models` 명령을 실행하여 원하는 모델을 선택하십시오. ```txt /models @@ -877,17 +895,17 @@ opencode를 실행하면서 설정한다. --- -##### Groq +### Groq -1. [Groq 콘솔](https://console.groq.com/)에 머리, click **Create API Key**, 키 복사. +1. [Groq 콘솔](https://console.groq.com/)로 이동하여 **Create API Key**를 클릭하고 키를 복사합니다. -2. `/connect` 명령을 실행하고 Groq에 대한 검색. +2. `/connect` 명령을 실행하고 Groq를 검색하십시오. ```txt /connect ``` -3. 공급자를 위한 API 열쇠를 입력하십시오. +3. API 키를 입력하십시오. ```txt ┌ API key @@ -896,7 +914,7 @@ opencode를 실행하면서 설정한다. └ enter ``` -4. `/models` 명령을 실행하여 원하는 것을 선택합니다. +4. `/models` 명령을 실행하여 원하는 모델을 선택합니다. ```txt /models @@ -906,9 +924,9 @@ opencode를 실행하면서 설정한다. ### Hugging Face -[Hugging Face Inference Provider](https://huggingface.co/docs/inference-providers)는 17+ 공급자가 지원하는 오픈 모델에 대한 액세스를 제공합니다. +[Hugging Face Inference Providers](https://huggingface.co/docs/inference-providers)는 17개 이상의 공급자가 지원하는 오픈 모델에 대한 액세스를 제공합니다. -1. [Hugging Face settings](https://huggingface.co/settings/tokens/new?ownUserPermissions=inference.serverless.write&tokenType=fineGrained)를 통해 토큰을 Inference Provider에게 호출할 권한을 부여합니다. +1. [Hugging Face settings](https://huggingface.co/settings/tokens/new?ownUserPermissions=inference.serverless.write&tokenType=fineGrained)로 이동하여 Inference Providers에 호출할 권한이 있는 토큰을 생성합니다. 2. `/connect` 명령을 실행하고 **Hugging Face**를 검색하십시오. @@ -925,7 +943,7 @@ opencode를 실행하면서 설정한다. └ enter ``` -4. `/models` 명령을 실행하여 같은 모델을 선택하십시오 Kimi-K2-Instruct 또는 GLM-4.6 . +4. `/models` 명령을 실행하여 모델(예: _Kimi-K2-Instruct_ 또는 _GLM-4.6_)을 선택하십시오. ```txt /models @@ -935,17 +953,17 @@ opencode를 실행하면서 설정한다. ### Helicone -[Helicone](https://helicone.ai)는 AI 애플리케이션에 대한 로깅, 모니터링 및 분석 기능을 제공하는 LLM Observability 플랫폼입니다. Helicone AI Gateway는 모델을 기반으로 적절한 공급자에게 요청을 자동으로 전달합니다. +[Helicone](https://helicone.ai)는 AI 애플리케이션을 위한 로깅, 모니터링 및 분석 기능을 제공하는 LLM 관찰 가능성(Observability) 플랫폼입니다. Helicone AI Gateway는 모델을 기반으로 적절한 공급자에게 요청을 자동으로 라우팅합니다. -1. [Helicone](https://helicone.ai)에 머리, 계정을 만들고, 대시보드에서 API 키를 생성합니다. +1. [Helicone](https://helicone.ai)로 이동하여 계정을 만들고 대시보드에서 API 키를 생성합니다. -2. `/connect` 명령을 실행하고 ** Helicone**를 검색하십시오. +2. `/connect` 명령을 실행하고 **Helicone**를 검색하십시오. ```txt /connect ``` -3. Helicone API 열쇠를 입력하십시오. +3. Helicone API 키를 입력하십시오. ```txt ┌ API key @@ -954,19 +972,19 @@ opencode를 실행하면서 설정한다. └ enter ``` -4. 모델을 선택하려면 `/models` 명령을 실행하십시오. +4. `/models` 명령을 실행하여 모델을 선택하십시오. ```txt /models ``` -캐싱 및 속도 제한과 같은 더 많은 공급자와 고급 기능을 위해 [Helicone 문서](https://docs.helicone.ai)를 확인하십시오. +캐싱 및 속도 제한과 같은 더 많은 공급자와 고급 기능은 [Helicone 문서](https://docs.helicone.ai)를 확인하십시오. -#### 선택 사항 +#### 선택적 구성 -이벤트에서 opencode를 통해 자동으로 구성되지 않는 Helicone의 기능 또는 모델을 볼 수 있습니다. +OpenCode를 통해 자동으로 구성되지 않는 Helicone의 기능이나 모델이 있는 경우 직접 구성할 수 있습니다. -여기에 [Helicone의 모델 디렉토리](https://helicone.ai/models), 당신은 당신이 추가 할 모델의 ID를 잡아이 필요. +[Helicone의 모델 디렉토리](https://helicone.ai/models)에서 추가하려는 모델의 ID를 확인하십시오. ```jsonc title="~/.config/opencode/opencode.jsonc" { @@ -992,7 +1010,7 @@ opencode를 실행하면서 설정한다. } ``` -##### 사용자 정의 헤더 +#### 사용자 정의 헤더 Helicone는 캐싱, 사용자 추적 및 세션 관리와 같은 기능을 위한 사용자 정의 헤더를 지원합니다. `options.headers`를 사용하여 공급자 구성에 추가하십시오: @@ -1017,7 +1035,7 @@ Helicone는 캐싱, 사용자 추적 및 세션 관리와 같은 기능을 위 ##### 세션 추적 -Helicone's [Sessions](https://docs.helicone.ai/features/sessions) 기능으로 그룹 관련 LLM 요청이 가능합니다. [opencode-helicone-session](https://github.com/H2Shami/opencode-helicone-session) 플러그인을 사용하여 각 opencode 대화를 Helicone 세션으로 자동 로그인하십시오. +Helicone의 [Sessions](https://docs.helicone.ai/features/sessions) 기능을 사용하면 관련 LLM 요청을 그룹화할 수 있습니다. [opencode-helicone-session](https://github.com/H2Shami/opencode-helicone-session) 플러그인을 사용하여 각 OpenCode 대화를 Helicone 세션으로 자동 기록하십시오. ```bash npm install -g opencode-helicone-session @@ -1031,24 +1049,24 @@ npm install -g opencode-helicone-session } ``` -플러그인은 `Helicone-Session-Id` 및 `Helicone-Session-Name` 헤더를 귀하의 요청에 주사합니다. Helicone의 세션 페이지에서는 별도의 세션으로 나열된 각 opencode 대화를 볼 수 있습니다. +이 플러그인은 `Helicone-Session-Id` 및 `Helicone-Session-Name` 헤더를 요청에 주입합니다. Helicone의 세션 페이지에서 각 OpenCode 대화가 별도의 세션으로 나열되는 것을 볼 수 있습니다. -###### 공통 Helicone 헤더 +##### 공통 Helicone 헤더 -| 헤드러 | Description | +| 헤더 | 설명 | | -------------------------- | ---------------------------------------------------------- | -| `Helicone-Cache-Enabled` | 대응 캐싱 (`true`/`false`) | -| `Helicone-User-Id` | 사용자별 추적 가능 | +| `Helicone-Cache-Enabled` | 응답 캐싱 활성화 (`true`/`false`) | +| `Helicone-User-Id` | 사용자별 지표 추적 | | `Helicone-Property-[Name]` | 사용자 정의 속성 추가(예: `Helicone-Property-Environment`) | -| `Helicone-Prompt-Id` | prompt 대응 | +| `Helicone-Prompt-Id` | 요청을 프롬프트 버전과 연관 | -모든 사용 가능한 헤더에 대한 [Helicone Header Directory](https://docs.helicone.ai/helicone-headers/header-directory)를 참조하십시오. +사용 가능한 모든 헤더는 [Helicone Header Directory](https://docs.helicone.ai/helicone-headers/header-directory)를 참조하십시오. --- -#### llama.cpp +### llama.cpp -[llama.cpp's](https://github.com/ggml-org/llama.cpp) llama-server 유틸리티를 통해 로컬 모델을 사용할 수 있습니다. +[llama.cpp](https://github.com/ggml-org/llama.cpp)의 llama-server 유틸리티를 통해 로컬 모델을 사용하도록 구성할 수 있습니다. ```json title="opencode.json" "llama.cpp" {5, 6, 8, 10-15} { @@ -1076,21 +1094,21 @@ npm install -g opencode-helicone-session 이 예제에서: -- `llama.cpp`는 주문 공급자 ID입니다. 원하는 문자열이 될 수 있습니다. -- `npm`는 이 공급자를 위해 사용할 포장을 지정합니다. 여기, `@ai-sdk/openai-compatible`는 OpenAI 호환 API에 사용됩니다. -- `name`는 UI에 있는 공급자를 위한 전시 이름입니다. -- `options.baseURL`는 로컬 서버의 엔드포인트입니다. -- `models`는 모델 ID를 구성하는 맵입니다. 모델 이름은 모델 선택 목록에 표시됩니다. +- `llama.cpp`는 사용자 정의 공급자 ID입니다. 원하는 문자열로 지정할 수 있습니다. +- `npm`은 이 공급자에 사용할 패키지를 지정합니다. 여기서는 OpenAI 호환 API를 위해 `@ai-sdk/openai-compatible`을 사용합니다. +- `name`은 UI에 표시될 공급자 이름입니다. +- `options.baseURL`은 로컬 서버의 엔드포인트입니다. +- `models`는 모델 ID와 해당 구성을 매핑합니다. 모델 이름은 모델 선택 목록에 표시됩니다. --- -###### IO.NET +### IO.NET IO.NET은 다양한 사용 사례에 최적화된 17개의 모델을 제공합니다: -1. [IO.NET 콘솔](https://ai.io.net/)에 머리, 계정을 만들고 API 키를 생성합니다. +1. [IO.NET 콘솔](https://ai.io.net/)로 이동하여 계정을 만들고 API 키를 생성합니다. -2. `/connect` 명령을 실행하고 **IO.NET**를 검색하십시오. +2. `/connect` 명령을 실행하고 **IO.NET**을 검색하십시오. ```txt /connect @@ -1115,7 +1133,7 @@ IO.NET은 다양한 사용 사례에 최적화된 17개의 모델을 제공합 ### LM Studio -LM Studio를 통해 로컬 모델을 사용할 수 있습니다. +LM Studio를 통해 로컬 모델을 사용하도록 구성할 수 있습니다. ```json title="opencode.json" "lmstudio" {5, 6, 8, 10-14} { @@ -1139,19 +1157,19 @@ LM Studio를 통해 로컬 모델을 사용할 수 있습니다. 이 예제에서: -- `lmstudio`는 주문 공급자 ID입니다. 원하는 문자열이 될 수 있습니다. -- `npm`는 이 공급자를 위해 사용할 포장을 지정합니다. 여기, `@ai-sdk/openai-compatible`는 OpenAI 호환 API에 사용됩니다. -- `name`는 UI에 있는 공급자를 위한 전시 이름입니다. -- `options.baseURL`는 로컬 서버의 엔드포인트입니다. -- `models`는 모델 ID를 구성하는 맵입니다. 모델 이름은 모델 선택 목록에 표시됩니다. +- `lmstudio`는 사용자 정의 공급자 ID입니다. 원하는 문자열로 지정할 수 있습니다. +- `npm`은 이 공급자에 사용할 패키지를 지정합니다. 여기서는 OpenAI 호환 API를 위해 `@ai-sdk/openai-compatible`을 사용합니다. +- `name`은 UI에 표시될 공급자 이름입니다. +- `options.baseURL`은 로컬 서버의 엔드포인트입니다. +- `models`는 모델 ID와 해당 구성을 매핑합니다. 모델 이름은 모델 선택 목록에 표시됩니다. --- -## Moonshot AI +### Moonshot AI -Moonshot AI에서 Kimi K2 사용 : +Moonshot AI에서 Kimi K2를 사용하려면: -1. [Moonshot AI 콘솔](https://platform.moonshot.ai/console)에 머리, 계정을 만들고, ** API 키**를 클릭합니다. +1. [Moonshot AI 콘솔](https://platform.moonshot.ai/console)로 이동하여 계정을 만들고 **Create API key**를 클릭합니다. 2. `/connect` 명령을 실행하고 **Moonshot AI**를 검색하십시오. @@ -1168,7 +1186,7 @@ Moonshot AI에서 Kimi K2 사용 : └ enter ``` -4. `/models` 명령을 실행하여 Kimi K2 . +4. `/models` 명령을 실행하여 *Kimi K2*를 선택하십시오. ```txt /models @@ -1176,9 +1194,9 @@ Moonshot AI에서 Kimi K2 사용 : --- -## MiniMax +### MiniMax -1. [MiniMax API 콘솔](https://platform.minimax.io/login)에 머리, 계정을 만들고 API 키를 생성합니다. +1. [MiniMax API 콘솔](https://platform.minimax.io/login)로 이동하여 계정을 만들고 API 키를 생성합니다. 2. `/connect` 명령을 실행하고 **MiniMax**를 검색하십시오. @@ -1195,7 +1213,7 @@ Moonshot AI에서 Kimi K2 사용 : └ enter ``` -4. `/models` 명령을 실행하여 같은 모델을 선택하십시오 M2.1 . +4. `/models` 명령을 실행하여 모델(예: _M2.1_)을 선택하십시오. ```txt /models @@ -1203,9 +1221,9 @@ Moonshot AI에서 Kimi K2 사용 : --- -## Nebius Token Factory +### Nebius Token Factory -1. [Nebius Token Factory 콘솔](https://tokenfactory.nebius.com/)에 머리, 계정을 만들고, ** 키 추가 **. +1. [Nebius Token Factory 콘솔](https://tokenfactory.nebius.com/)로 이동하여 계정을 만들고 **Add Key**를 클릭합니다. 2. `/connect` 명령을 실행하고 **Nebius Token Factory**를 검색하십시오. @@ -1213,7 +1231,7 @@ Moonshot AI에서 Kimi K2 사용 : /connect ``` -3. Nebius 토큰 공장 API 키를 입력하십시오. +3. Nebius Token Factory API 키를 입력하십시오. ```txt ┌ API key @@ -1222,7 +1240,7 @@ Moonshot AI에서 Kimi K2 사용 : └ enter ``` -4. `/models` 명령을 실행하여 같은 모델을 선택하십시오 Kimi K2 Instruct . +4. `/models` 명령을 실행하여 모델(예: _Kimi K2 Instruct_)을 선택하십시오. ```txt /models @@ -1230,12 +1248,12 @@ Moonshot AI에서 Kimi K2 사용 : --- -#### Ollama +### Ollama -Ollama를 통해 로컬 모델을 사용할 수 있습니다. +Ollama를 통해 로컬 모델을 사용하도록 구성할 수 있습니다. :::tip -Ollama는 opencode를 자동으로 구성할 수 있습니다. 자세한 내용은 [Ollama 통합 문서](https://docs.ollama.com/integrations/opencode)를 참조하십시오. +Ollama는 OpenCode에 대해 자동으로 구성될 수 있습니다. 자세한 내용은 [Ollama 통합 문서](https://docs.ollama.com/integrations/opencode)를 참조하십시오. ::: ```json title="opencode.json" "ollama" {5, 6, 8, 10-14} @@ -1260,35 +1278,35 @@ Ollama는 opencode를 자동으로 구성할 수 있습니다. 자세한 내용 이 예제에서: -- `ollama`는 주문 공급자 ID입니다. 원하는 문자열이 될 수 있습니다. -- `npm`는 이 공급자를 위해 사용할 포장을 지정합니다. 여기, `@ai-sdk/openai-compatible`는 OpenAI 호환 API에 사용됩니다. -- `name`는 UI에 있는 공급자를 위한 전시 이름입니다. -- `options.baseURL`는 로컬 서버의 엔드포인트입니다. -- `models`는 모델 ID를 구성하는 맵입니다. 모델 이름은 모델 선택 목록에 표시됩니다. +- `ollama`는 사용자 정의 공급자 ID입니다. 원하는 문자열로 지정할 수 있습니다. +- `npm`은 이 공급자에 사용할 패키지를 지정합니다. 여기서는 OpenAI 호환 API를 위해 `@ai-sdk/openai-compatible`을 사용합니다. +- `name`은 UI에 표시될 공급자 이름입니다. +- `options.baseURL`은 로컬 서버의 엔드포인트입니다. +- `models`는 모델 ID와 해당 구성을 매핑합니다. 모델 이름은 모델 선택 목록에 표시됩니다. :::tip -도구 호출이 작동하지 않는 경우, Ollama에서 `num_ctx` 증가. 주위 시작 16k - 32k. +도구 호출이 작동하지 않는 경우, Ollama에서 `num_ctx`를 늘려보십시오. 16k - 32k 정도에서 시작하십시오. ::: --- -## Ollama Cloud +### Ollama Cloud -opencode로 Ollama Cloud를 사용하려면: +OpenCode로 Ollama Cloud를 사용하려면: -1. [https://ollama.com/](https://ollama.com/) 이상 머리와 로그인하거나 계정을 만들 수 있습니다. +1. [https://ollama.com/](https://ollama.com/)으로 이동하여 로그인하거나 계정을 만듭니다. -2. Navigate to**Settings** > **Keys** 및 click **API Key**를 추가하여 새로운 API 키 생성. +2. **Settings** > **Keys**로 이동하여 **Add API Key**를 클릭해 새 API 키를 생성합니다. -3. opencode에서 사용을 위한 API 열쇠를 복사하십시오. +3. OpenCode에서 사용할 API 키를 복사합니다. -4. `/connect` 명령을 실행하고 ** Ollama Cloud**를 검색하십시오. +4. `/connect` 명령을 실행하고 **Ollama Cloud**를 검색하십시오. ```txt /connect ``` -5. Ollama Cloud API 키 입력. +5. Ollama Cloud API 키를 입력하십시오. ```txt ┌ API key @@ -1297,7 +1315,7 @@ opencode로 Ollama Cloud를 사용하려면: └ enter ``` -6. ** 중요 **: opencode의 클라우드 모델을 사용하기 전에, 로컬 모델 정보를 끌어야 합니다: +6. **중요**: OpenCode에서 클라우드 모델을 사용하기 전에, 로컬에서 모델 정보를 가져와야 합니다: ```bash ollama pull gpt-oss:20b-cloud @@ -1315,14 +1333,13 @@ opencode로 Ollama Cloud를 사용하려면: [ChatGPT Plus 또는 Pro](https://chatgpt.com/pricing)에 가입하는 것이 좋습니다. -1. 가입하면 `/connect` 명령을 실행하고 OpenAI를 선택하십시오. +1. 가입 후 `/connect` 명령을 실행하고 OpenAI를 선택하십시오. ```txt /connect ``` -2. **ChatGPT Plus/Pro** 옵션을 선택하고 브라우저를 열 수 있습니다. - 자주 묻는 질문 +2. **ChatGPT Plus/Pro** 옵션을 선택하면 브라우저가 열리고 인증을 요청합니다. ```txt ┌ Select auth method @@ -1332,7 +1349,7 @@ opencode로 Ollama Cloud를 사용하려면: └ ``` -3. 이제 모든 OpenAI 모델은 `/models` 명령을 사용할 때 사용할 수 있어야합니다. +3. 이제 `/models` 명령을 사용할 때 모든 OpenAI 모델을 사용할 수 있습니다. ```txt /models @@ -1340,23 +1357,23 @@ opencode로 Ollama Cloud를 사용하려면: ##### API 키 사용 -API 키가 이미 있다면 ** 수동으로 API 키**를 입력하고 terminal에서 붙여넣을 수 있습니다. +이미 API 키가 있다면 **Manually enter API Key**를 선택하고 터미널에 붙여넣을 수 있습니다. --- -## OpenCode Zen +### OpenCode Zen -OpenCode Zen은 opencode 팀에서 제공하는 테스트 및 검증된 모델 목록입니다. [더 알아보기](/docs/zen). +OpenCode Zen은 OpenCode 팀에서 제공하는 테스트 및 검증된 모델 목록입니다. [더 알아보기](/docs/zen). -1. 로그인 **<a href={console}>OpenCode Zen</a>** and click**Create API Key**. +1. **<a href={console}>OpenCode Zen</a>**에 로그인하고 **Create API Key**를 클릭합니다. -2. `/connect` 명령을 실행하고 **OpenCode Zen**를 검색하십시오. +2. `/connect` 명령을 실행하고 **OpenCode Zen**을 검색하십시오. ```txt /connect ``` -3. opencode API 키를 입력하십시오. +3. OpenCode API 키를 입력하십시오. ```txt ┌ API key @@ -1365,7 +1382,7 @@ OpenCode Zen은 opencode 팀에서 제공하는 테스트 및 검증된 모델 └ enter ``` -4. `/models` 명령을 실행하여 같은 모델을 선택하십시오 Qwen 3 Coder 480B . +4. `/models` 명령을 실행하여 모델(예: _Qwen 3 Coder 480B_)을 선택하십시오. ```txt /models @@ -1373,9 +1390,9 @@ OpenCode Zen은 opencode 팀에서 제공하는 테스트 및 검증된 모델 --- -## OpenRouter +### OpenRouter -1. [OpenRouter 대시보드](https://openrouter.ai/settings/keys)에 머리, click ** API Key**를 클릭하고 키를 복사합니다. +1. [OpenRouter 대시보드](https://openrouter.ai/settings/keys)로 이동하여 **Create API Key**를 클릭하고 키를 복사합니다. 2. `/connect` 명령을 실행하고 OpenRouter를 검색하십시오. @@ -1383,7 +1400,7 @@ OpenCode Zen은 opencode 팀에서 제공하는 테스트 및 검증된 모델 /connect ``` -3. 공급자를 위한 API 열쇠를 입력하십시오. +3. API 키를 입력하십시오. ```txt ┌ API key @@ -1392,28 +1409,28 @@ OpenCode Zen은 opencode 팀에서 제공하는 테스트 및 검증된 모델 └ enter ``` -4. 많은 OpenRouter 모델은 기본적으로 `/models` 명령을 실행하여 원하는 것을 선택합니다. +4. 많은 OpenRouter 모델은 기본적으로 미리 로드되어 있으므로 `/models` 명령을 실행하여 원하는 것을 선택하십시오. ```txt /models ``` -opencode config를 통해 추가 모델을 추가할 수 있습니다. + OpenCode 구성을 통해 모델을 추가할 수도 있습니다. -```json title="opencode.json" {6} -{ - "$schema": "https://opencode.ai/config.json", - "provider": { - "openrouter": { - "models": { - "somecoolnewmodel": {} - } - } - } -} -``` + ```json title="opencode.json" {6} + { + "$schema": "https://opencode.ai/config.json", + "provider": { + "openrouter": { + "models": { + "somecoolnewmodel": {} + } + } + } + } + ``` -5. 당신은 또한 당신의 opencode config를 통해 그들을 주문을 받아서 만들 수 있습니다. 공급자 지정의 예입니다. +5. 또한 OpenCode 구성을 통해 사용자 정의할 수도 있습니다. 다음은 공급자 순서를 지정하는 예입니다. ```json title="opencode.json" { @@ -1439,12 +1456,12 @@ opencode config를 통해 추가 모델을 추가할 수 있습니다. ### SAP AI Core -SAP AI Core는 OpenAI, Anthropic, Google, Amazon, Meta, Mistral 및 AI21의 40+ 모델에 대한 액세스를 제공합니다. +SAP AI Core는 OpenAI, Anthropic, Google, Amazon, Meta, Mistral 및 AI21의 40개 이상의 모델에 대한 액세스를 제공합니다. -1. [SAP BTP Cockpit](https://account.hana.ondemand.com/)로 이동하여 SAP AI Core 서비스 인스턴스로 이동하고 서비스 키를 만듭니다. +1. [SAP BTP Cockpit](https://account.hana.ondemand.com/)으로 이동하여 SAP AI Core 서비스 인스턴스로 이동하고 서비스 키를 만듭니다. :::tip - 서비스 키는 `clientid`, `clientsecret`, `url` 및 `serviceurls.AI_API_URL`를 포함하는 JSON 객체입니다. **Services** > **Instances 및 Subscriptions** 아래 AI Core 인스턴스를 찾을 수 있습니다. + 서비스 키는 `clientid`, `clientsecret`, `url` 및 `serviceurls.AI_API_URL`을 포함하는 JSON 객체입니다. **Services** > **Instances and Subscriptions** 아래에서 AI Core 인스턴스를 찾을 수 있습니다. ::: 2. `/connect` 명령을 실행하고 **SAP AI Core**를 검색하십시오. @@ -1462,29 +1479,29 @@ SAP AI Core는 OpenAI, Anthropic, Google, Amazon, Meta, Mistral 및 AI21의 40+ └ enter ``` -또는 `AICORE_SERVICE_KEY` 환경 변수를 설정: + 또는 `AICORE_SERVICE_KEY` 환경 변수를 설정합니다: -```bash + ```bash AICORE_SERVICE_KEY='{"clientid":"...","clientsecret":"...","url":"...","serviceurls":{"AI_API_URL":"..."}}' opencode -``` + ``` -또는 bash 프로파일에 추가: + 또는 bash 프로필에 추가합니다: -```bash title="~/.bash_profile" + ```bash title="~/.bash_profile" export AICORE_SERVICE_KEY='{"clientid":"...","clientsecret":"...","url":"...","serviceurls":{"AI_API_URL":"..."}}' -``` + ``` -4. 선택적으로 배치 ID 및 자원 그룹: +4. 선택적으로 배포 ID 및 리소스 그룹을 설정합니다: ```bash AICORE_DEPLOYMENT_ID=your-deployment-id AICORE_RESOURCE_GROUP=your-resource-group opencode ``` :::note - 이 설정은 선택 사항이며 SAP AI Core 설정에 따라 구성해야합니다. + 이 설정은 선택 사항이며 SAP AI Core 설정에 따라 구성해야 합니다. ::: -5. `/models` 명령을 실행하여 40+ 유효한 모형에서 선택하십시오. +5. `/models` 명령을 실행하여 40개 이상의 사용 가능한 모델 중에서 선택하십시오. ```txt /models @@ -1492,11 +1509,44 @@ SAP AI Core는 OpenAI, Anthropic, Google, Amazon, Meta, Mistral 및 AI21의 40+ --- -### OVHcloud AI 엔드포인트 +### STACKIT -1. [OVHcloud 패널](https://ovh.com/manager)에 머리. `Public Cloud` 섹션으로 이동, `AI & Machine Learning` > `AI Endpoints` 및 `API Keys` 탭에서, ** 새로운 API 키 활성화 **. +STACKIT AI Model Serving은 Llama, Mistral, Qwen과 같은 LLM에 초점을 맞추고 유럽 인프라에서 데이터 주권을 최대한 보장하는 완전 관리형 AI 모델 호스팅 환경을 제공합니다. -2. `/connect` 명령을 실행하고 ** OVHcloud AI Endpoints**를 검색하십시오. +1. [STACKIT Portal](https://portal.stackit.cloud)로 이동하여 **AI Model Serving**으로 이동한 다음 프로젝트의 인증 토큰을 만듭니다. + + :::tip + 인증 토큰을 만들기 전에 STACKIT 고객 계정, 사용자 계정 및 프로젝트가 필요합니다. + ::: + +2. `/connect` 명령을 실행하고 **STACKIT**을 검색하십시오. + + ```txt + /connect + ``` + +3. STACKIT AI Model Serving 인증 토큰을 입력하십시오. + + ```txt + ┌ API key + │ + │ + └ enter + ``` + +4. `/models` 명령을 실행하여 _Qwen3-VL 235B_ 또는 *Llama 3.3 70B*와 같은 사용 가능한 모델을 선택하십시오. + + ```txt + /models + ``` + +--- + +### OVHcloud AI Endpoints + +1. [OVHcloud 패널](https://ovh.com/manager)로 이동합니다. `Public Cloud` 섹션으로 이동하여 `AI & Machine Learning` > `AI Endpoints`로 간 뒤 `API Keys` 탭에서 **Create a new API key**를 클릭합니다. + +2. `/connect` 명령을 실행하고 **OVHcloud AI Endpoints**를 검색하십시오. ```txt /connect @@ -1511,7 +1561,7 @@ SAP AI Core는 OpenAI, Anthropic, Google, Amazon, Meta, Mistral 및 AI21의 40+ └ enter ``` -4. `/models` 명령을 실행하여 같은 모델을 선택하십시오 gpt-oss-120b . +4. `/models` 명령을 실행하여 모델(예: _gpt-oss-120b_)을 선택하십시오. ```txt /models @@ -1521,9 +1571,9 @@ SAP AI Core는 OpenAI, Anthropic, Google, Amazon, Meta, Mistral 및 AI21의 40+ ### Scaleway -opencode를 사용하여 [Scaleway Generative APIs](https://www.scaleway.com/en/docs/generative-apis/)를 사용하려면: +OpenCode로 [Scaleway Generative APIs](https://www.scaleway.com/en/docs/generative-apis/)를 사용하려면: -1. [Scaleway 콘솔 IAM 설정](https://console.scaleway.com/iam/api-keys)를 통해 새로운 API 키 생성. +1. [Scaleway Console IAM 설정](https://console.scaleway.com/iam/api-keys)에서 새 API 키를 생성합니다. 2. `/connect` 명령을 실행하고 **Scaleway**를 검색하십시오. @@ -1540,7 +1590,7 @@ opencode를 사용하여 [Scaleway Generative APIs](https://www.scaleway.com/en/ └ enter ``` -4. `/models` 명령을 실행하여 같은 모델을 선택하십시오. devstral-2-123b-instruct-2512 또는 gpt-oss-120b . +4. `/models` 명령을 실행하여 모델(예: _devstral-2-123b-instruct-2512_ 또는 _gpt-oss-120b_)을 선택하십시오. ```txt /models @@ -1548,9 +1598,9 @@ opencode를 사용하여 [Scaleway Generative APIs](https://www.scaleway.com/en/ --- -## Together AI +### Together AI -1. [Together AI 콘솔](https://api.together.ai)에 머리, 계정을 만들고 ** 키 추가 **를 클릭합니다. +1. [Together AI 콘솔](https://api.together.ai)로 이동하여 계정을 만들고 **Add Key**를 클릭합니다. 2. `/connect` 명령을 실행하고 **Together AI**를 검색하십시오. @@ -1558,7 +1608,7 @@ opencode를 사용하여 [Scaleway Generative APIs](https://www.scaleway.com/en/ /connect ``` -3. 함께 AI API 키를 입력하십시오. +3. Together AI API 키를 입력하십시오. ```txt ┌ API key @@ -1567,7 +1617,7 @@ opencode를 사용하여 [Scaleway Generative APIs](https://www.scaleway.com/en/ └ enter ``` -4. `/models` 명령을 실행하여 같은 모델을 선택하십시오 Kimi K2 Instruct . +4. `/models` 명령을 실행하여 모델(예: _Kimi K2 Instruct_)을 선택하십시오. ```txt /models @@ -1575,17 +1625,17 @@ opencode를 사용하여 [Scaleway Generative APIs](https://www.scaleway.com/en/ --- -## Venice AI +### Venice AI -1. [Venice AI 콘솔](https://venice.ai)에 머리, 계정을 만들고 API 키를 생성합니다. +1. [Venice AI 콘솔](https://venice.ai)로 이동하여 계정을 만들고 API 키를 생성합니다. -2. `/connect` 명령을 실행하고 **Venice AI **를 검색하십시오. +2. `/connect` 명령을 실행하고 **Venice AI**를 검색하십시오. ```txt /connect ``` -3. 베니스 AI API 열쇠를 입력하십시오. +3. Venice AI API 키를 입력하십시오. ```txt ┌ API key @@ -1594,7 +1644,7 @@ opencode를 사용하여 [Scaleway Generative APIs](https://www.scaleway.com/en/ └ enter ``` -4. `/models` 명령을 실행하여 같은 모델을 선택하십시오 Llama 3.3 70B . +4. `/models` 명령을 실행하여 모델(예: _Llama 3.3 70B_)을 선택하십시오. ```txt /models @@ -1602,11 +1652,11 @@ opencode를 사용하여 [Scaleway Generative APIs](https://www.scaleway.com/en/ --- -## Vercel AI 게이트웨이 +### Vercel AI Gateway -Vercel AI를 게이트웨이는 OpenAI, Anthropic, Google, xAI 등에서 모델에 액세스할 수 있습니다. 모델은 Markup없이 목록 가격에서 제공됩니다. +Vercel AI Gateway는 OpenAI, Anthropic, Google, xAI 등의 모델에 액세스할 수 있으며, 통합된 엔드포인트를 통해 더 많은 기능을 제공합니다. 모델은 마크업 없이 정가로 제공됩니다. -1. [Vercel 대시보드](https://vercel.com/)에 머리, **AI Gateway** 탭으로 이동하고, **API 키**를 클릭하여 새로운 API 키 생성. +1. [Vercel 대시보드](https://vercel.com/)로 이동하여 **AI Gateway** 탭으로 간 뒤, **API keys**를 클릭하여 새 API 키를 생성합니다. 2. `/connect` 명령을 실행하고 **Vercel AI Gateway**를 검색하십시오. @@ -1614,7 +1664,7 @@ Vercel AI를 게이트웨이는 OpenAI, Anthropic, Google, xAI 등에서 모델 /connect ``` -3. Vercel AI Gateway API 키 입력. +3. Vercel AI Gateway API 키를 입력하십시오. ```txt ┌ API key @@ -1623,13 +1673,13 @@ Vercel AI를 게이트웨이는 OpenAI, Anthropic, Google, xAI 등에서 모델 └ enter ``` -4. 모델을 선택하려면 `/models` 명령을 실행하십시오. +4. `/models` 명령을 실행하여 모델을 선택하십시오. ```txt /models ``` -opencode config를 통해 모델을 사용자 정의 할 수 있습니다. 공급자 routing 순서를 지정하는 예입니다. +OpenCode 구성을 통해 모델을 사용자 정의할 수도 있습니다. 다음은 공급자 라우팅 순서를 지정하는 예입니다. ```json title="opencode.json" { @@ -1648,19 +1698,19 @@ opencode config를 통해 모델을 사용자 정의 할 수 있습니다. 공 } ``` -몇몇 유용한 여정 선택권: +몇 가지 유용한 라우팅 옵션: | 옵션 | 설명 | | ------------------- | --------------------------------- | -| `order` | 공급자의 순서 | -| `only` | 특정 공급자 제한 | -| `zeroDataRetention` | 제로 데이터 보유 정책만 이용 가능 | +| `order` | 시도할 공급자 순서 | +| `only` | 특정 공급자로 제한 | +| `zeroDataRetention` | 데이터 보유 정책이 없는 곳만 사용 | --- ### xAI -1. [xAI 콘솔](https://console.x.ai/)에 머리, 계정을 만들고 API 키를 생성합니다. +1. [xAI 콘솔](https://console.x.ai/)로 이동하여 계정을 만들고 API 키를 생성합니다. 2. `/connect` 명령을 실행하고 **xAI**를 검색하십시오. @@ -1677,7 +1727,7 @@ opencode config를 통해 모델을 사용자 정의 할 수 있습니다. 공 └ enter ``` -4. `/models` 명령을 실행하여 같은 모델을 선택하십시오 Grok Beta . +4. `/models` 명령을 실행하여 모델(예: _Grok Beta_)을 선택하십시오. ```txt /models @@ -1687,15 +1737,15 @@ opencode config를 통해 모델을 사용자 정의 할 수 있습니다. 공 ### Z.AI -1. [Z.AI API 콘솔](https://z.ai/manage-apikey/apikey-list)에 머리, 계정을 만들고, **새로운 API 키**를 클릭합니다. +1. [Z.AI API 콘솔](https://z.ai/manage-apikey/apikey-list)로 이동하여 계정을 만들고 **Create a new API key**를 클릭합니다. -2. `/connect` 명령을 실행하고 ** Z.AI**를 검색하십시오. +2. `/connect` 명령을 실행하고 **Z.AI**를 검색하십시오. ```txt /connect ``` -**GLM 코딩 플랜**에 가입하면 **Z.AI 코딩 플랜**을 선택하십시오. + **GLM Coding Plan**에 가입했다면 **Z.AI Coding Plan**을 선택하십시오. 3. Z.AI API 키를 입력하십시오. @@ -1706,7 +1756,7 @@ opencode config를 통해 모델을 사용자 정의 할 수 있습니다. 공 └ enter ``` -4. `/models` 명령을 실행하여 같은 모델을 선택하십시오 GLM-4.7 . +4. `/models` 명령을 실행하여 모델(예: _GLM-4.7_)을 선택하십시오. ```txt /models @@ -1714,9 +1764,9 @@ opencode config를 통해 모델을 사용자 정의 할 수 있습니다. 공 --- -## ZenMux +### ZenMux -1. [ZenMux 대쉬보드](https://zenmux.ai/settings/keys)에 머리, click **Create API Key**, 키 복사. +1. [ZenMux 대시보드](https://zenmux.ai/settings/keys)로 이동하여 **Create API Key**를 클릭하고 키를 복사합니다. 2. `/connect` 명령을 실행하고 ZenMux를 검색하십시오. @@ -1724,7 +1774,7 @@ opencode config를 통해 모델을 사용자 정의 할 수 있습니다. 공 /connect ``` -3. 공급자를 위한 API 열쇠를 입력하십시오. +3. API 키를 입력하십시오. ```txt ┌ API key @@ -1733,38 +1783,38 @@ opencode config를 통해 모델을 사용자 정의 할 수 있습니다. 공 └ enter ``` -4. 많은 ZenMux 모델은 기본적으로 사전 로드되며 `/models` 명령을 실행하여 원하는 것을 선택합니다. +4. 많은 ZenMux 모델은 기본적으로 미리 로드되어 있으므로 `/models` 명령을 실행하여 원하는 것을 선택하십시오. ```txt /models ``` -opencode config를 통해 추가 모델을 추가할 수 있습니다. + OpenCode 구성을 통해 모델을 추가할 수도 있습니다. -```json title="opencode.json" {6} -{ - "$schema": "https://opencode.ai/config.json", - "provider": { - "zenmux": { - "models": { - "somecoolnewmodel": {} - } - } - } -} -``` + ```json title="opencode.json" {6} + { + "$schema": "https://opencode.ai/config.json", + "provider": { + "zenmux": { + "models": { + "somecoolnewmodel": {} + } + } + } + } + ``` --- ## 사용자 정의 공급자 -`/connect` 명령에 나열되지 않은 **OpenAI-compatible** 공급자를 추가하려면: +`/connect` 명령에 나열되지 않은 **OpenAI 호환** 공급자를 추가하려면: :::tip -opencode를 사용하여 OpenAI 호환 공급자를 사용할 수 있습니다. 가장 현대적인 AI 제공 업체는 OpenAI 호환 API를 제공합니다. +OpenCode에서 모든 OpenAI 호환 공급자를 사용할 수 있습니다. 대부분의 최신 AI 공급자는 OpenAI 호환 API를 제공합니다. ::: -1. `/connect` 명령을 실행하고 ** 다른**로 스크롤하십시오. +1. `/connect` 명령을 실행하고 **Other**로 스크롤하십시오. ```bash $ /connect @@ -1777,7 +1827,7 @@ opencode를 사용하여 OpenAI 호환 공급자를 사용할 수 있습니다. └ ``` -2. 공급자를 위한 유일한 ID를 입력하십시오. +2. 공급자를 위한 고유한 ID를 입력하십시오. ```bash $ /connect @@ -1790,10 +1840,10 @@ opencode를 사용하여 OpenAI 호환 공급자를 사용할 수 있습니다. ``` :::note - 기억에 남는 ID를 선택하면 구성 파일에서 이것을 사용할 수 있습니다. + 기억하기 쉬운 ID를 선택하십시오. 구성 파일에서 이 ID를 사용하게 됩니다. ::: -3. 공급자를 위한 당신의 API 열쇠를 입력하십시오. +3. 공급자의 API 키를 입력하십시오. ```bash $ /connect @@ -1829,23 +1879,23 @@ opencode를 사용하여 OpenAI 호환 공급자를 사용할 수 있습니다. } ``` -여기에 구성 옵션: + 구성 옵션은 다음과 같습니다: + - **npm**: 사용할 AI SDK 패키지. OpenAI 호환 공급자의 경우 `@ai-sdk/openai-compatible` + - **name**: UI에 표시될 이름 + - **models**: 사용 가능한 모델 + - **options.baseURL**: API 엔드포인트 URL + - **options.apiKey**: 인증을 사용하지 않는 경우 선택적으로 API 키 설정 + - **options.headers**: 선택적으로 사용자 정의 헤더 설정 -- **npm**: AI SDK 패키지, OpenAI 호환 공급자 `@ai-sdk/openai-compatible` -**name**: UI의 표시 이름. -- ** 모델**: 유효한 모델. -- **options.baseURL**: API 엔드포인트 URL. -- **options.apiKey**: 선택적으로 auth를 사용하지 않는 경우 API 키 설정. -- **options.headers**: 선택적으로 사용자 정의 헤더를 설정합니다. + 고급 옵션에 대한 자세한 내용은 아래 예제를 참조하십시오. -아래 예에서 고급 옵션에 더. - -5. `/models` 명령을 실행하고 사용자 정의 공급자와 모델은 선택 목록에서 나타납니다. +5. `/models` 명령을 실행하면 사용자 정의 공급자와 모델이 선택 목록에 나타납니다. --- ##### 예제 -다음은 `apiKey`, `headers` 및 모델 `limit` 옵션 설정 예입니다. +다음은 `apiKey`, `headers` 및 모델 `limit` 옵션을 설정하는 예입니다. ```json title="opencode.json" {9,11,17-20} { @@ -1877,11 +1927,12 @@ opencode를 사용하여 OpenAI 호환 공급자를 사용할 수 있습니다. 구성 세부 사항: -- **apiKey**: `env` 변수 구문을 사용하여 설정, [learn more](/docs/config#env-vars). -**headers**: 각 요청으로 전송된 사용자 정의 헤더. -- **limit.context**: 모델이 허용하는 최대 Input Tokens. -- **limit.output**: 모델이 생성할 수 있는 최대 Output Tokens. +- **apiKey**: `env` 변수 구문을 사용하여 설정, [더 알아보기](/docs/config#env-vars). +- **headers**: 각 요청과 함께 전송되는 사용자 정의 헤더. +- **limit.context**: 모델이 허용하는 최대 입력 토큰. +- **limit.output**: 모델이 생성할 수 있는 최대 출력 토큰. -`limit` 필드를 사용하면 opencode가 얼마나 많은 컨텍스트를 이해 할 수 있습니다. 표준 공급자는 model.dev에서 자동적으로 당깁니다. +`limit` 필드를 사용하면 OpenCode가 남은 컨텍스트 양을 파악할 수 있습니다. 표준 공급자는 models.dev에서 자동으로 이를 가져옵니다. --- @@ -1889,13 +1940,11 @@ opencode를 사용하여 OpenAI 호환 공급자를 사용할 수 있습니다. 공급자 구성에 문제가 있는 경우 다음을 확인하십시오. -1. **주의 설정 확인 **: `opencode auth list`를 실행하여 자격 증명을 볼 수 있습니다. - 공급자는 config에 추가됩니다. +1. **인증 설정 확인**: `opencode auth list`를 실행하여 공급자의 자격 증명이 구성에 추가되었는지 확인하십시오. -이것은 Amazon Bedrock과 같은 공급자에 적용되지 않습니다. 환경 변수에 의존합니다. + Amazon Bedrock과 같이 인증을 위해 환경 변수에 의존하는 공급자에는 적용되지 않습니다. -2. 주문 공급자를 위해, opencode config를 검사하고: - -- `/connect` 명령에 사용되는 공급자 ID가 opencode config에서 ID를 일치시킵니다. -- 오른쪽 npm 패키지는 공급자에 사용됩니다. 예를 들어 Cerebras의 `@ai-sdk/cerebras`를 사용합니다. 그리고 다른 모든 OpenAI 호환 공급자를 위해, 사용 `@ai-sdk/openai-compatible`. -- 올바른 API 엔드포인트는 `options.baseURL` 필드에 사용됩니다. +2. 사용자 정의 공급자의 경우, OpenCode 구성을 확인하고 다음을 수행하십시오: + - `/connect` 명령에 사용된 공급자 ID가 OpenCode 구성의 ID와 일치하는지 확인하십시오. + - 공급자에 올바른 npm 패키지가 사용되었는지 확인하십시오. 예를 들어 Cerebras에는 `@ai-sdk/cerebras`를 사용하고, 다른 모든 OpenAI 호환 공급자에는 `@ai-sdk/openai-compatible`을 사용하십시오. + - `options.baseURL` 필드에 올바른 API 엔드포인트가 사용되었는지 확인하십시오. diff --git a/packages/web/src/content/docs/ko/sdk.mdx b/packages/web/src/content/docs/ko/sdk.mdx index f6d43c136d..a5d12d1ab0 100644 --- a/packages/web/src/content/docs/ko/sdk.mdx +++ b/packages/web/src/content/docs/ko/sdk.mdx @@ -117,13 +117,85 @@ try { --- +## 구조화된 출력 + +JSON 스키마와 함께 `format`을 지정하여 모델에서 구조화된 JSON 출력을 요청할 수 있습니다. 모델은 `StructuredOutput` 도구를 사용하여 스키마와 일치하는 검증된 JSON을 반환합니다. + +### 기본 사용법 + +```typescript +const result = await client.session.prompt({ + path: { id: sessionId }, + body: { + parts: [{ type: "text", text: "Research Anthropic and provide company info" }], + format: { + type: "json_schema", + schema: { + type: "object", + properties: { + company: { type: "string", description: "Company name" }, + founded: { type: "number", description: "Year founded" }, + products: { + type: "array", + items: { type: "string" }, + description: "Main products", + }, + }, + required: ["company", "founded"], + }, + }, + }, +}) + +// Access the structured output +console.log(result.data.info.structured_output) +// { company: "Anthropic", founded: 2021, products: ["Claude", "Claude API"] } +``` + +### 출력 형식 유형 + +| 유형 | 설명 | +| ------------- | ------------------------------------------------- | +| `text` | 기본값. 표준 텍스트 응답 (구조화된 출력 없음) | +| `json_schema` | 제공된 스키마와 일치하는 검증된 JSON을 반환합니다 | + +### JSON 스키마 형식 + +`type: 'json_schema'`를 사용할 때 다음을 제공하십시오: + +| 필드 | 유형 | 설명 | +| ------------ | --------------- | ------------------------------------------- | +| `type` | `'json_schema'` | 필수. JSON 스키마 모드를 지정합니다 | +| `schema` | `object` | 필수. 출력 구조를 정의하는 JSON 스키마 객체 | +| `retryCount` | `number` | 선택 사항. 검증 재시도 횟수 (기본값: 2) | + +### 오류 처리 + +모델이 모든 재시도 후에도 유효한 구조화된 출력을 생성하지 못하면 응답에 `StructuredOutputError`가 포함됩니다: + +```typescript +if (result.data.info.error?.name === "StructuredOutputError") { + console.error("Failed to produce structured output:", result.data.info.error.message) + console.error("Attempts:", result.data.info.error.retries) +} +``` + +### 모범 사례 + +1. **명확한 설명 제공**: 모델이 추출할 데이터를 이해하는 데 도움이 되도록 스키마 속성에 명확한 설명을 제공하십시오. +2. **`required` 사용**: 필수 필드를 지정하려면 `required`를 사용하십시오. +3. **스키마를 집중적으로 유지**: 복잡한 중첩 스키마는 모델이 올바르게 채우기 더 어려울 수 있습니다. +4. **적절한 `retryCount` 설정**: 복잡한 스키마의 경우 늘리고 단순한 스키마의 경우 줄이십시오. + +--- + ## API SDK는 type-safe 클라이언트를 통해 모든 서버 API를 노출합니다. --- -## 글로벌 +### 글로벌 | 메서드 | 설명 | 응답 | | ----------------- | ---------------------- | ------------------------------------ | @@ -142,10 +214,10 @@ console.log(health.data.version) ### 앱 -| 방법 | 설명 | 응답 | -| -------------- | ------------------------- | ----------------------------------------------- | -| `app.log()` | 로그 항목 작성 | `boolean` | -| `app.agents()` | 이용 가능한 모든 에이전트 | <a href={typesUrl}><code> 에이전트[]</code></a> | +| 방법 | 설명 | 응답 | +| -------------- | ------------------------- | ------------------------------------------- | +| `app.log()` | 로그 항목 작성 | `boolean` | +| `app.agents()` | 이용 가능한 모든 에이전트 | <a href={typesUrl}><code>Agent[]</code></a> | --- @@ -167,7 +239,7 @@ const agents = await client.app.agents() --- -## 프로젝트 +### 프로젝트 | 방법 | 설명 | 응답 | | ------------------- | ----------------------- | --------------------------------------------- | @@ -205,7 +277,7 @@ const pathInfo = await client.path.get() --- -#### 구성 +### 구성 | 방법 | 설명 | 응답 | | -------------------- | -------------------------- | ----------------------------------------------------------------------------------------------------- | @@ -224,29 +296,29 @@ const { providers, default: defaults } = await client.config.providers() --- -## 세션 +### 세션 -| 메서드 | 설명 | 비고 | -| ---------------------------------------------------------- | ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | -| `session.list()` | 세션 일람 | <a href={typesUrl}><code>Session[]</code></a> | -| `session.get({ path })` | 세션 가져 오기 | <a href={typesUrl}><code>Session</code></a> | -| `session.children({ path })` | 하위 세션 목록 | 반품 <a href={typesUrl}><code>Session</code></a> | -| `session.create({ body })` | 세션 만들기 | 리턴 <a href={typesUrl}><code>Session</code></a> | -| `session.delete({ path })` | 세션 삭제 | `boolean` 반품 | -| `session.update({ path, body })` | 업데이트 세션 속성 | 반품 <a href={typesUrl}><code>Session</code></a> | -| `session.init({ path, body })` | 앱 초기화 및 `AGENTS.md` 분석 | `boolean`를 반환 | -| `session.abort({ path })` | 운영 중인 세션 | 반품 `boolean` | -| `session.share({ path })` | 공유 세션 | 반품 <a href={typesUrl}><code>Session</code></a> | -| `session.unshare({ path })` | 공유 세션 | 반품 <a href={typesUrl}><code>Session</code></a> | -| `session.summarize({ path, body })` | 세션 요약 | 반품 `boolean` | -| `session.messages({ path })` | 세션의 메시지 목록 | `{ info: `<a href={typesUrl}><code>Message</code></a>`, parts: `<a href={typesUrl}><code>Part</code></a>`}[]` | -| `session.message({ path })` | 메시지 상세정보 | 반품 `{ info: `<a href={typesUrl}><code>Message</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}` | -| `session.prompt({ path, body })` | prompt 메시지 보내기 | `body.noReply: true` 반환 UserMessage (콘텍스트 전용). 기본 반환 <a href={typesUrl}><code>AssistantMessage</code></a> 에 AI 응답 | -| `session.command({ path, body })` | 세션으로 명령을 전송 | `{ info: `<a href={typesUrl}><code>AssistantMessage</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}` | -| `session.shell({ path, body })` | shell 명령을 실행 | <a href={typesUrl}><code>AssistantMessage</code></a> | -| `session.revert({ path, body })` | 메시지 다시 변환 | <a href={typesUrl}><code>Session</code></a> | -| `session.unrevert({ path })` | 메시지 되돌리기 취소 | 반품 <a href={typesUrl}><code>Session</code></a> | -| `postSessionByIdPermissionsByPermissionId({ path, body })` | 허가 요청 대응 | 반품 `boolean` | +| 메서드 | 설명 | 비고 | +| ---------------------------------------------------------- | ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `session.list()` | 세션 일람 | <a href={typesUrl}><code>Session[]</code></a> | +| `session.get({ path })` | 세션 가져 오기 | <a href={typesUrl}><code>Session</code></a> | +| `session.children({ path })` | 하위 세션 목록 | 반품 <a href={typesUrl}><code>Session</code></a> | +| `session.create({ body })` | 세션 만들기 | 리턴 <a href={typesUrl}><code>Session</code></a> | +| `session.delete({ path })` | 세션 삭제 | `boolean` 반품 | +| `session.update({ path, body })` | 업데이트 세션 속성 | 반품 <a href={typesUrl}><code>Session</code></a> | +| `session.init({ path, body })` | 앱 초기화 및 `AGENTS.md` 분석 | `boolean`를 반환 | +| `session.abort({ path })` | 운영 중인 세션 | 반품 `boolean` | +| `session.share({ path })` | 공유 세션 | 반품 <a href={typesUrl}><code>Session</code></a> | +| `session.unshare({ path })` | 공유 세션 취소 | 반품 <a href={typesUrl}><code>Session</code></a> | +| `session.summarize({ path, body })` | 세션 요약 | 반품 `boolean` | +| `session.messages({ path })` | 세션의 메시지 목록 | `{ info: `<a href={typesUrl}><code>Message</code></a>`, parts: `<a href={typesUrl}><code>Part</code></a>`}[]` | +| `session.message({ path })` | 메시지 상세정보 | 반품 `{ info: `<a href={typesUrl}><code>Message</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}` | +| `session.prompt({ path, body })` | prompt 메시지 보내기 | `body.noReply: true`는 UserMessage(컨텍스트 전용)를 반환합니다. 기본값은 AI 응답과 함께 <a href={typesUrl}><code>AssistantMessage</code></a>를 반환합니다. [구조화된 출력](#구조화된-출력)을 위한 `body.outputFormat`을 지원합니다 | +| `session.command({ path, body })` | 세션으로 명령을 전송 | `{ info: `<a href={typesUrl}><code>AssistantMessage</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}` | +| `session.shell({ path, body })` | shell 명령을 실행 | <a href={typesUrl}><code>AssistantMessage</code></a> | +| `session.revert({ path, body })` | 메시지 다시 변환 | <a href={typesUrl}><code>Session</code></a> | +| `session.unrevert({ path })` | 메시지 되돌리기 취소 | 반품 <a href={typesUrl}><code>Session</code></a> | +| `postSessionByIdPermissionsByPermissionId({ path, body })` | 허가 요청 대응 | 반품 `boolean` | --- @@ -281,7 +353,7 @@ await client.session.prompt({ --- -## 파일 +### 파일 | 방법 | 설명 | 응답 | | ------------------------- | ---------------------------- | -------------------------------------------------------------------------------------- | @@ -322,7 +394,7 @@ const content = await client.file.read({ --- -#### TUI +### TUI | 방법 | 설명 | 응답 | | ------------------------------ | ------------------------ | --------- | @@ -353,7 +425,7 @@ await client.tui.showToast({ --- -##### 인증 +### 인증 | 방법 | 설명 | 응답 | | ------------------- | -------------- | --------- | @@ -372,7 +444,7 @@ await client.auth.set({ --- -## 이벤트 +### 이벤트 | 방법 | 설명 | 응답 | | ------------------- | ----------------------- | ----------------------- | diff --git a/packages/web/src/content/docs/ko/share.mdx b/packages/web/src/content/docs/ko/share.mdx index 55cf6a2c3e..9e5c638824 100644 --- a/packages/web/src/content/docs/ko/share.mdx +++ b/packages/web/src/content/docs/ko/share.mdx @@ -41,7 +41,7 @@ opencode는 대화가 공유되는 방법을 제어하는 세 가지 공유 모 ```json title="opencode.json" { - "$schema": "https://opncd.ai/config.json", + "$schema": "https://opencode.ai/config.json", "share": "manual" } ``` @@ -54,7 +54,7 @@ opencode는 대화가 공유되는 방법을 제어하는 세 가지 공유 모 ```json title="opencode.json" { - "$schema": "https://opncd.ai/config.json", + "$schema": "https://opencode.ai/config.json", "share": "auto" } ``` @@ -69,7 +69,7 @@ opencode는 대화가 공유되는 방법을 제어하는 세 가지 공유 모 ```json title="opencode.json" { - "$schema": "https://opncd.ai/config.json", + "$schema": "https://opencode.ai/config.json", "share": "disabled" } ``` diff --git a/packages/web/src/content/docs/ko/themes.mdx b/packages/web/src/content/docs/ko/themes.mdx index b83b620170..af148eda10 100644 --- a/packages/web/src/content/docs/ko/themes.mdx +++ b/packages/web/src/content/docs/ko/themes.mdx @@ -3,28 +3,27 @@ title: 테마 description: 내장 테마를 선택하거나 자신만의 테마를 정의하세요. --- -opencode를 사용하면 여러 내장 테마 중 하나에서 선택할 수 있으며 terminal 테마에 적응하는 테마를 사용하거나 사용자 정의 테마를 정의 할 수 있습니다. +OpenCode를 사용하면 여러 내장 테마 중 하나에서 선택할 수 있으며 terminal 테마에 적응하는 테마를 사용하거나 사용자 정의 테마를 정의 할 수 있습니다. -기본적으로 opencode는 자체 `opencode` 테마를 사용합니다. +기본적으로 OpenCode는 자체 `opencode` 테마를 사용합니다. --- ## 터미널 요구 사항 -자신의 풀 컬러 팔레트로 올바르게 표시하려면 terminal을 지원해야합니다 ** truecolor** (24 비트 색상). 대부분의 현대 terminal은 기본적으로 이것을 지원합니다, 그러나 당신은 그것을 가능하게 할 필요가 있을지도 모릅니다: +테마가 전체 색상 팔레트로 올바르게 표시되려면 터미널이 **truecolor** (24비트 색상)를 지원해야 합니다. 대부분의 최신 터미널은 기본적으로 이를 지원하지만, 활성화해야 할 수도 있습니다: --**체크 지원**: `echo $COLORTERM` - 그것은 `truecolor` 또는 `24bit`를 출력해야 합니다 +- **지원 확인**: `echo $COLORTERM` 실행 - `truecolor` 또는 `24bit`가 출력되어야 합니다. +- **truecolor 활성화**: 셸 프로필에서 환경 변수 `COLORTERM=truecolor`를 설정하십시오. +- **터미널 호환성**: 터미널 에뮬레이터가 24비트 색상을 지원하는지 확인하십시오 (iTerm2, Alacritty, Kitty, Windows Terminal 및 최신 버전의 GNOME Terminal 등 대부분의 최신 터미널이 지원함). -- ** truecolor 사용 가능**: shell 프로파일에서 환경 변수 `COLORTERM=truecolor`를 설정 -- **Terminal 호환성 **: terminal 에뮬레이터 지원 24 비트 색상 (iTerm2, Alacritty, Kitty, Windows Terminal 및 GNOME Terminal의 최신 버전) - -truecolor 지원 없이, 테마는 감소된 색깔 정확도로 나타날지도 모릅니다 또는 가장 가까운 256 색깔 대류로 뒤떨어질지도 모릅니다. +truecolor 지원이 없으면 테마가 감소된 색상 정확도로 표시되거나 가장 가까운 256색 근사치로 대체될 수 있습니다. --- ## 내장 테마 -opencode는 여러 내장 테마와 함께 제공됩니다. +OpenCode는 여러 내장 테마와 함께 제공됩니다. | 이름 | 설명 | | ---------------------- | ------------------------------------------------------------------- | @@ -46,27 +45,27 @@ opencode는 여러 내장 테마와 함께 제공됩니다. ## 시스템 테마 -`system` 테마는 terminal의 색깔 계획에 자동적으로 적응시키기 위하여 디자인됩니다. 고정 색상을 사용하는 전통적인 테마와 달리, system 테마: +`system` 테마는 터미널의 색상 스키마에 자동으로 적응하도록 설계되었습니다. 고정 색상을 사용하는 기존 테마와 달리, system 테마는: -- **그레이스케일**: terminal의 배경 색상을 기반으로 사용자 정의 회색 가늠자를 만들고 최적의 대조를 보장합니다. -- ** ANSI 색상 사용 ** : terminal의 색상 팔레트를 존중하는 구문 강조 및 UI 요소에 대한 표준 ANSI 색상 (0-15). -- ** terminal 기본 사항**: `none` 텍스트 및 배경 색상을 사용하여 terminal의 네이티브 외관을 유지합니다. +- **그레이스케일 생성**: 터미널의 배경 색상을 기반으로 사용자 정의 그레이스케일을 생성하여 최적의 대비를 보장합니다. +- **ANSI 색상 사용**: 구문 강조 및 UI 요소에 표준 ANSI 색상(0-15)을 활용하여 터미널의 색상 팔레트를 존중합니다. +- **터미널 기본값 유지**: 텍스트 및 배경 색상에 `none`을 사용하여 터미널의 기본 모양을 유지합니다. -시스템 테마는 사용자를위한 것입니다 : +시스템 테마는 다음과 같은 사용자에게 적합합니다: -- opencode가 terminal의 외관과 일치해야 합니다. -- 사용자 정의 terminal 색상 구성 -- 모든 terminal 응용 분야의 일관된 모습 +- OpenCode가 터미널의 모양과 일치하기를 원하는 경우 +- 사용자 정의 터미널 색상 스키마를 사용하는 경우 +- 모든 터미널 애플리케이션에서 일관된 모양을 선호하는 경우 --- ## 테마 사용 -테마를 `/theme` 명령어로 선택하여 테마를 선택할 수 있습니다. 또는 [config](/docs/config)에서 지정할 수 있습니다. +`/theme` 명령어로 테마 선택기를 불러와 테마를 선택할 수 있습니다. 또는 `tui.json`에서 지정할 수 있습니다. -```json title="opencode.json" {3} +```json title="tui.json" {3} { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "theme": "tokyonight" } ``` @@ -75,32 +74,35 @@ opencode는 여러 내장 테마와 함께 제공됩니다. ## 사용자 정의 테마 -opencode는 사용자가 쉽게 테마를 만들 수 있도록 유연한 JSON 기반 테마 시스템을 지원합니다. +OpenCode는 사용자가 쉽게 테마를 만들고 사용자 정의할 수 있도록 유연한 JSON 기반 테마 시스템을 지원합니다. --- -##### 계층 구조 +### 계층 구조 -테마는 다음과 같은 순서에서 여러 디렉토리에서로드됩니다. 나중에 감독은 이전 것을 무시합니다. +테마는 다음 순서대로 여러 디렉토리에서 로드되며, 나중 디렉토리가 이전 디렉토리를 덮어씁니다: -1.**Built-in themes** - 이것은 바이너리에 내장되어 있습니다. 2. **사용자 설정 디렉토리 ** - `~/.config/opencode/themes/*.json` 또는 `$XDG_CONFIG_HOME/opencode/themes/*.json`에서 정의 3. ** 루트 디렉토리 ** - `<project-root>/.opencode/themes/*.json`에서 정의 4. **현재 작업 디렉토리 ** - `./.opencode/themes/*.json`에서 정의 +1. **내장 테마 (Built-in themes)** - 바이너리에 내장되어 있습니다. +2. **사용자 설정 디렉토리 (User config directory)** - `~/.config/opencode/themes/*.json` 또는 `$XDG_CONFIG_HOME/opencode/themes/*.json`에 정의됩니다. +3. **프로젝트 루트 디렉토리 (Project root directory)** - `<project-root>/.opencode/themes/*.json`에 정의됩니다. +4. **현재 작업 디렉토리 (Current working directory)** - `./.opencode/themes/*.json`에 정의됩니다. -여러 디렉토리가 같은 이름을 가진 테마를 포함한다면, 더 높은 우선 순위를 가진 디렉토리의 테마가 사용됩니다. +여러 디렉토리에 같은 이름의 테마가 있는 경우, 더 높은 우선 순위를 가진 디렉토리의 테마가 사용됩니다. --- ### 테마 만들기 -사용자 정의 테마를 만들려면 테마 디렉토리 중 하나에서 JSON 파일을 만듭니다. +사용자 정의 테마를 만들려면 테마 디렉토리 중 하나에 JSON 파일을 만듭니다. -사용자 넓은 테마: +사용자 전역 테마: ```bash no-frame mkdir -p ~/.config/opencode/themes vim ~/.config/opencode/themes/my-theme.json ``` -프로젝트 별 테마. +프로젝트별 테마: ```bash no-frame mkdir -p .opencode/themes @@ -111,35 +113,34 @@ vim .opencode/themes/my-theme.json ### JSON 형식 -테마는 유연한 JSON 형식을 사용하여 지원: +테마는 다음을 지원하는 유연한 JSON 형식을 사용합니다: --**Hex 색상**: `"#ffffff"` - -- ** ANSI 색상**: `3` (0-255) -- ** 색상 참조 ** : `"primary"` 또는 사용자 정의 정의 -- ** 어두운 / 조명 변형 ** : `{"dark": "#000", "light": "#fff"}` -- ** 색상 없음 ** : `"none"` - terminal의 기본 색상 또는 투명 사용 +- **Hex 색상**: `"#ffffff"` +- **ANSI 색상**: `3` (0-255) +- **색상 참조**: `"primary"` 또는 사용자 정의 정의 +- **다크/라이트 변형**: `{"dark": "#000", "light": "#fff"}` +- **색상 없음**: `"none"` - 터미널의 기본 색상 또는 투명 사용 --- ### 색상 정의 -`defs` 단면도는 선택적이고 당신은 주제에서 참조될 수 있는 재사용할 수 있는 색깔을 정의할 수 있습니다. +`defs` 섹션은 선택 사항이며 테마 내에서 참조할 수 있는 재사용 가능한 색상을 정의할 수 있습니다. --- -## 터미널 기본값 +### 터미널 기본값 -특별한 가치 `"none"`는 terminal의 기본 색깔을 상속하기 위하여 어떤 색깔든지를 위해 사용될 수 있습니다. 이것은 특히 당신의 terminal의 색깔 계획과 이음새가 없는 혼합 테마 창조를 위해 유용합니다: +`"none"`이라는 특별한 값은 모든 색상에 대해 터미널의 기본 색상을 상속하는 데 사용할 수 있습니다. 이는 특히 터미널의 색상 스키마와 매끄럽게 어우러지는 테마를 만들 때 유용합니다: -- `"text": "none"` - terminal의 기본 전경 색상 사용 -- `"background": "none"` - terminal의 기본 배경 색상 사용 +- `"text": "none"` - 터미널의 기본 전경색 사용 +- `"background": "none"` - 터미널의 기본 배경색 사용 --- ### 예제 -사용자 정의 테마의 예입니다 : +사용자 정의 테마의 예입니다: ```json title="my-theme.json" { diff --git a/packages/web/src/content/docs/ko/tui.mdx b/packages/web/src/content/docs/ko/tui.mdx index 8717cc785f..669d899d0c 100644 --- a/packages/web/src/content/docs/ko/tui.mdx +++ b/packages/web/src/content/docs/ko/tui.mdx @@ -5,9 +5,9 @@ description: OpenCode 터미널 사용자 인터페이스 사용. import { Tabs, TabItem } from "@astrojs/starlight/components" -opencode는 LLM과 함께 프로젝트를 위해 대화형 terminal 인터페이스 또는 TUI를 제공합니다. +OpenCode는 LLM과 함께 프로젝트 작업을 하기 위한 대화형 터미널 인터페이스(TUI)를 제공합니다. -opencode는 현재 디렉토리에 TUI를 시작합니다. +OpenCode를 실행하면 현재 디렉토리에서 TUI가 시작됩니다. ```bash opencode @@ -19,7 +19,7 @@ opencode opencode /path/to/project ``` -TUI에 있다면 메시지가 표시됩니다. +TUI에 들어가면 메시지를 입력하여 프롬프트할 수 있습니다. ```text Give me a quick summary of the codebase. @@ -29,10 +29,10 @@ Give me a quick summary of the codebase. ## 파일 참조 -`@`를 사용하여 메시지에 파일을 참조 할 수 있습니다. 이것은 현재 작업 디렉토리에서 fuzzy 파일 검색입니다. +`@`를 사용하여 메시지에서 파일을 참조할 수 있습니다. 이것은 현재 작업 디렉토리에서 퍼지(fuzzy) 파일 검색을 수행합니다. :::tip -`@`를 사용하여 메시지의 참조 파일을 사용할 수 있습니다. +`@`를 사용하여 메시지에서 파일을 참조할 수 있습니다. ::: ```text "@packages/functions/src/api/index.ts" @@ -45,7 +45,7 @@ How is auth handled in @packages/functions/src/api/index.ts? ## Bash 명령 -`!`를 사용하여 shell 명령을 실행합니다. +`!`로 메시지를 시작하여 셸 명령을 실행합니다. ```bash frame="none" !ls -la @@ -57,21 +57,21 @@ How is auth handled in @packages/functions/src/api/index.ts? ## 명령 -opencode TUI를 사용할 때, `/`를 입력하여 명령 이름을 따라 작업을 신속하게 실행할 수 있습니다. 예를 들면: +OpenCode TUI를 사용할 때 `/` 뒤에 명령 이름을 입력하여 작업을 빠르게 실행할 수 있습니다. 예를 들어: ```bash frame="none" /help ``` -대부분의 명령은 `ctrl+x`를 `ctrl+x`가 기본 리더 키입니다. [더 알아보기](/docs/keybinds). +대부분의 명령에는 기본 리더 키인 `ctrl+x`를 사용하는 키바인드도 있습니다. [더 알아보기](/docs/keybinds). -여기에 모든 가능한 슬래시 명령이 있습니다. +사용 가능한 모든 슬래시 명령은 다음과 같습니다: --- -### /connect +### connect -opencode에 대한 공급자를 추가합니다. 사용 가능한 공급자에서 선택하고 API 키를 추가 할 수 있습니다. +OpenCode에 공급자를 추가합니다. 사용 가능한 공급자 중에서 선택하고 API 키를 추가할 수 있습니다. ```bash frame="none" /connect @@ -79,67 +79,67 @@ opencode에 대한 공급자를 추가합니다. 사용 가능한 공급자에 --- -### /compact +### compact -현재 세션을 압축합니다. 앨리스 : `/summarize` +현재 세션을 압축합니다. _별칭_: `/summarize` ```bash frame="none" /compact ``` -** Keybind:** `ctrl+x c` +**키바인드:** `ctrl+x c` --- -### /details +### details -토글 툴 실행 세부 사항. +도구 실행 세부 정보 토글. ```bash frame="none" /details ``` -** Keybind:** `ctrl+x d` +**키바인드:** `ctrl+x d` --- -### /editor +### editor -메시지를 작성하기 위한 외부 편집기를 엽니다. `EDITOR` 환경에서 설정된 편집기를 사용합니다. [더 알아보기](#editor-setup). +메시지 작성을 위한 외부 편집기를 엽니다. `EDITOR` 환경 변수에 설정된 편집기를 사용합니다. [더 알아보기](#editor-setup). ```bash frame="none" /editor ``` -** Keybind:** `ctrl+x e` +**키바인드:** `ctrl+x e` --- -### /exit +### exit -opencode를 종료합니다. Aliases : `/quit`, `/q` +OpenCode를 종료합니다. _별칭_: `/quit`, `/q` ```bash frame="none" /exit ``` -** Keybind:** `ctrl+x q` +**키바인드:** `ctrl+x q` --- -### /export +### export -Markdown에 대한 현재 대화를 내보내고 기본 편집기에서 열립니다. `EDITOR` 환경에서 설정된 편집기를 사용합니다. [더 알아보기](#editor-setup). +현재 대화를 Markdown으로 내보내고 기본 편집기에서 엽니다. `EDITOR` 환경 변수에 설정된 편집기를 사용합니다. [더 알아보기](#editor-setup). ```bash frame="none" /export ``` -** Keybind:** `ctrl+x x` +**키바인드:** `ctrl+x x` --- -### /help +### help 도움말 대화 상자를 표시합니다. @@ -147,107 +147,106 @@ Markdown에 대한 현재 대화를 내보내고 기본 편집기에서 열립 /help ``` -** Keybind:** `ctrl+x h` +**키바인드:** `ctrl+x h` --- -###### /init +### init -`AGENTS.md` 파일을 만들거나 업데이트하십시오. [더 알아보기](/docs/rules). +`AGENTS.md` 파일을 생성하거나 업데이트합니다. [더 알아보기](/docs/rules). ```bash frame="none" /init ``` -** Keybind:** `ctrl+x i` +**키바인드:** `ctrl+x i` --- -## /models +### models -사용 가능한 모델 목록. +사용 가능한 모델 목록을 표시합니다. ```bash frame="none" /models ``` -** Keybind:** `ctrl+x m` +**키바인드:** `ctrl+x m` --- -## /new +### new -새로운 세션을 시작합니다. 앨리스 : `/clear` +새 세션을 시작합니다. _별칭_: `/clear` ```bash frame="none" /new ``` -** Keybind:** `ctrl+x n` +**키바인드:** `ctrl+x n` --- -##### /redo +### redo -이전 undone 메시지 Redo. `/undo`를 사용하는 후에만 유효한. +이전에 실행 취소한 메시지를 다시 실행합니다. `/undo`를 사용한 후에만 사용할 수 있습니다. :::tip -모든 파일 변경도 복원됩니다. +모든 파일 변경 사항도 복원됩니다. ::: -내부적으로 Git을 사용하여 파일 변경을 관리합니다. 그래서 프로젝트 ** -Git 저장소**입니다. +내부적으로 Git을 사용하여 파일 변경 사항을 관리합니다. 따라서 프로젝트가 **Git 저장소**여야 합니다. ```bash frame="none" /redo ``` -** Keybind:** `ctrl+x r` +**키바인드:** `ctrl+x r` --- -## /sessions +### sessions -세션 간 목록 및 전환. Aliases : `/resume`, `/continue` +세션 목록을 표시하고 세션 간을 전환합니다. _별칭_: `/resume`, `/continue` ```bash frame="none" /sessions ``` -** Keybind:** `ctrl+x l` +**키바인드:** `ctrl+x l` --- -## 공유 +### share -현재 세션 공유. [더 알아보기](/docs/share). +현재 세션을 공유합니다. [더 알아보기](/docs/share). ```bash frame="none" /share ``` -** Keybind:** `ctrl+x s` +**키바인드:** `ctrl+x s` --- -## /theme +### themes -사용할 수 있는 테마 목록. +사용 가능한 테마 목록을 표시합니다. ```bash frame="none" -/theme +/themes ``` -** Keybind:** `ctrl+x t` +**키바인드:** `ctrl+x t` --- -### /thinking +### thinking -대화의 사고/거주 블록의 가시성을 토합니다. 사용할 때, 확장 된 생각을 지원하는 모델의 이유 프로세스를 볼 수 있습니다. +대화에서 생각/추론 블록의 가시성을 토글합니다. 활성화하면 확장된 사고를 지원하는 모델의 추론 과정을 볼 수 있습니다. :::note -이 명령은 생각 블록이 ** 표시되었는지 여부 만 제어 ** - 모델의 소싱 기능을 활성화하거나 비활성화하지 않습니다. toggle 실제적인 reasoning 기능에, 모형 변종을 통해서 주기 위하여 `ctrl+t`를 이용합니다. +이 명령은 생각 블록이 **표시되는지 여부만 제어**하며 모델의 추론 기능을 활성화하거나 비활성화하지 않습니다. 실제 추론 기능을 토글하려면 `ctrl+t`를 사용하여 모델 변형을 순환하십시오. ::: ```bash frame="none" @@ -256,28 +255,27 @@ Git 저장소**입니다. --- -##### /undo +### undo -대화에서 마지막 메시지. 가장 최근의 사용자 메시지, 모든 후속 응답 및 모든 파일 변경 제거. +대화의 마지막 메시지를 실행 취소합니다. 가장 최근의 사용자 메시지, 모든 후속 응답 및 모든 파일 변경 사항을 제거합니다. :::tip -어떤 파일 변경도 복제됩니다. +모든 파일 변경 사항도 되돌려집니다. ::: -내부적으로 Git을 사용하여 파일 변경을 관리합니다. 그래서 프로젝트 ** -Git 저장소**입니다. +내부적으로 Git을 사용하여 파일 변경 사항을 관리합니다. 따라서 프로젝트가 **Git 저장소**여야 합니다. ```bash frame="none" /undo ``` -** Keybind:** `ctrl+x u` +**키바인드:** `ctrl+x u` --- -#### /unshare +### unshare -Unshare 현재 세션. [더 알아보기](/docs/share#un-sharing). +현재 세션 공유를 취소합니다. [더 알아보기](/docs/share#un-sharing). ```bash frame="none" /unshare @@ -285,9 +283,9 @@ Unshare 현재 세션. [더 알아보기](/docs/share#un-sharing). --- -## 편집기 설정 +## Editor setup -`/editor`와 `/export` 명령 모두는 `EDITOR` 환경변수에서 지정된 편집기를 사용합니다. +`/editor`와 `/export` 명령 모두 `EDITOR` 환경 변수에 지정된 편집기를 사용합니다. <Tabs> <TabItem label="Linux/macOS"> @@ -301,8 +299,7 @@ Unshare 현재 세션. [더 알아보기](/docs/share#un-sharing). export EDITOR="code --wait" ``` -영원한 만들기 위하여, 당신의 shell 프로파일에 이것을 추가하십시오; -`~/.bashrc`, `~/.zshrc`, 등. + 영구적으로 설정하려면 셸 프로필(`~/.bashrc`, `~/.zshrc` 등)에 추가하십시오. </TabItem> @@ -315,8 +312,7 @@ Unshare 현재 세션. [더 알아보기](/docs/share#un-sharing). set EDITOR=code --wait ``` -영구적으로, use **System Properties** > ** 환경 -변수**. + 영구적으로 설정하려면 **시스템 속성** > **환경 변수**를 사용하십시오. </TabItem> @@ -329,62 +325,72 @@ Unshare 현재 세션. [더 알아보기](/docs/share#un-sharing). $env:EDITOR = "code --wait" ``` -영구적으로 만들려면 PowerShell 프로파일에 추가하십시오. + 영구적으로 설정하려면 PowerShell 프로필에 추가하십시오. </TabItem> </Tabs> -인기있는 편집기 옵션은 다음과 같습니다 : +인기 있는 편집기 옵션은 다음과 같습니다: -- `code` - Visual Studio 코드 -- `cursor` - 커서 -- `windsurf` - 윈드 서핑 -- `nvim` - Neovim 편집기 -- `vim` - Vim 편집기 -- `nano` - 나노 편집기 -- `notepad` - 윈도우 노트패드 -- `subl` - 승화 텍스트 +- `code` - Visual Studio Code +- `cursor` - Cursor +- `windsurf` - Windsurf +- `nvim` - Neovim editor +- `vim` - Vim editor +- `nano` - Nano editor +- `notepad` - Windows Notepad +- `subl` - Sublime Text :::note -VS Code와 같은 일부 편집기는 `--wait` 플래그와 함께 시작해야합니다. +VS Code와 같은 일부 편집기는 `--wait` 플래그와 함께 시작해야 합니다. ::: -일부 편집기는 명령줄 인수가 차단 모드에서 실행되어야 합니다. `--wait` 플래그는 닫힐 때까지 편집기 프로세스 블록을 만듭니다. +일부 편집기는 차단 모드에서 실행하려면 명령줄 인수가 필요합니다. `--wait` 플래그는 편집기 프로세스가 닫힐 때까지 차단되도록 합니다. --- ## 구성 -opencode config 파일을 통해 TUI 동작을 사용자 정의할 수 있습니다. +`tui.json` (또는 `tui.jsonc`) 파일을 통해 TUI 동작을 사용자 정의할 수 있습니다. -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", - "tui": { - "scroll_speed": 3, - "scroll_acceleration": { - "enabled": true - } - } + "$schema": "https://opencode.ai/tui.json", + "theme": "opencode", + "keybinds": { + "leader": "ctrl+x" + }, + "scroll_speed": 3, + "scroll_acceleration": { + "enabled": true + }, + "diff_style": "auto" } ``` +이는 서버/런타임 동작을 구성하는 `opencode.json`과는 별개입니다. + ### 옵션 -- `scroll_acceleration` - 부드러운 자연 스크롤을위한 macOS 스타일 스크롤 가속 가능. 사용할 때, 스크롤 속도는 빠른 스크롤 제스처로 증가하고 느린 움직임을 위해 정확한 유지. **이 설정은 `scroll_speed`를 통해 우선 순위를 부여하고 활성화 할 때. ** -- `scroll_speed` - 스크롤 명령 (최소 : `1`)을 사용하여 TUI 스크롤을 빠르게 제어합니다. 기본 `3`. ** 참고: `scroll_acceleration.enabled`가 `true`로 설정되면 무시됩니다.** +- `theme` - UI 테마를 설정합니다. [더 알아보기](/docs/themes). +- `keybinds` - 키보드 단축키를 사용자 정의합니다. [더 알아보기](/docs/keybinds). +- `scroll_acceleration.enabled` - 부드럽고 자연스러운 스크롤을 위해 macOS 스타일의 스크롤 가속을 활성화합니다. 활성화하면 빠른 스크롤 제스처로 스크롤 속도가 증가하고 느린 움직임에서는 정밀하게 유지됩니다. **이 설정은 `scroll_speed`보다 우선하며 활성화 시 이를 덮어씁니다.** +- `scroll_speed` - 스크롤 명령을 사용할 때 TUI 스크롤 속도를 제어합니다 (최소: `0.001`, 소수점 값 지원). 기본값은 `3`입니다. **참고: `scroll_acceleration.enabled`가 `true`로 설정되면 무시됩니다.** +- `diff_style` - diff 렌더링 방식을 제어합니다. `"auto"`는 터미널 너비에 적응하고, `"stacked"`는 항상 단일 열 레이아웃을 표시합니다. + +`OPENCODE_TUI_CONFIG`를 사용하여 사용자 정의 TUI 설정 경로를 로드할 수 있습니다. --- ## 사용자 정의 -명령 팔레트 (`ctrl+x h` 또는 `/help`)를 사용하여 TUI보기의 다양한 측면을 사용자 정의 할 수 있습니다. 재시작에 따른 설정 persist. +명령 팔레트(`ctrl+x h` 또는 `/help`)를 사용하여 TUI 보기의 다양한 측면을 사용자 정의할 수 있습니다. 설정은 다시 시작해도 유지됩니다. --- #### 사용자 이름 표시 -사용자 이름이 채팅 메시지에 나타나는지 여부를 수정합니다. 이것을 통해 접근: +채팅 메시지에 사용자 이름이 표시되는지 여부를 토글합니다. 다음을 통해 액세스: -- 명령 팔레트 : "username" 또는 "hide 사용자" 검색 -- 자동 설정은 TUI 세션을 통해 기억됩니다. +- 명령 팔레트: "username" 또는 "hide username" 검색 +- 설정은 자동으로 유지되며 TUI 세션 간에 기억됩니다. diff --git a/packages/web/src/content/docs/ko/zen.mdx b/packages/web/src/content/docs/ko/zen.mdx index 04d5c0df8e..5c2b9644ff 100644 --- a/packages/web/src/content/docs/ko/zen.mdx +++ b/packages/web/src/content/docs/ko/zen.mdx @@ -55,6 +55,8 @@ OpenCode Zen은 OpenCode의 다른 제공자와 동일한 방식으로 작동합 | 모델 | 모델 ID | 엔드포인트 | AI SDK 패키지 | | ------------------ | ------------------ | -------------------------------------------------- | --------------------------- | +| GPT 5.4 | gpt-5.4 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| GPT 5.3 Codex | gpt-5.3-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.2 | gpt-5.2 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.2 Codex | gpt-5.2-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.1 | gpt-5.1 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | @@ -64,28 +66,30 @@ OpenCode Zen은 OpenCode의 다른 제공자와 동일한 방식으로 작동합 | GPT 5 | gpt-5 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5 Codex | gpt-5-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5 Nano | gpt-5-nano | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| Claude Opus 4.6 | claude-opus-4-6 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Opus 4.5 | claude-opus-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Opus 4.1 | claude-opus-4-1 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Sonnet 4.6 | claude-sonnet-4-6 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Sonnet 4.5 | claude-sonnet-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Sonnet 4 | claude-sonnet-4 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Haiku 4.5 | claude-haiku-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Haiku 3.5 | claude-3-5-haiku | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| Claude Opus 4.6 | claude-opus-4-6 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| Claude Opus 4.5 | claude-opus-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| Claude Opus 4.1 | claude-opus-4-1 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Gemini 3.1 Pro | gemini-3.1-pro | `https://opencode.ai/zen/v1/models/gemini-3.1-pro` | `@ai-sdk/google` | | Gemini 3 Pro | gemini-3-pro | `https://opencode.ai/zen/v1/models/gemini-3-pro` | `@ai-sdk/google` | | Gemini 3 Flash | gemini-3-flash | `https://opencode.ai/zen/v1/models/gemini-3-flash` | `@ai-sdk/google` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.5 Free | minimax-m2.5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.1 | minimax-m2.1 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.1 Free | minimax-m2.1-free | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| GLM 5 | glm-5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | GLM 4.7 | glm-4.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM 4.7 Free | glm-4.7-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | GLM 4.6 | glm-4.6 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 Free | kimi-k2.5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2 Thinking | kimi-k2-thinking | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2 | kimi-k2 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Qwen3 Coder 480B | qwen3-coder | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Big Pickle | big-pickle | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -OpenCode 설정 파일에서 사용하는 [모델 ID](/docs/config/#models)는 `opencode/<model-id>` 형식을 따릅니다. +OpenCode 설정 파일에서 사용하는 [모델 ID](/docs/config/#models)는 `opencode/<model-id>` 형식을 따릅니다. 예를 들어 GPT 5.2 Codex의 경우 설정에서 `opencode/gpt-5.2-codex`와 같이 사용합니다. --- @@ -107,29 +111,35 @@ https://opencode.ai/zen/v1/models | 모델 | 입력 | 출력 | 캐시 읽기 | 캐시 쓰기 | | --------------------------------- | ------ | ------ | --------- | --------- | | Big Pickle | Free | Free | Free | - | -| MiniMax M2.1 Free | Free | Free | Free | - | +| MiniMax M2.5 Free | Free | Free | Free | - | +| MiniMax M2.5 | $0.30 | $1.20 | $0.06 | $0.375 | | MiniMax M2.1 | $0.30 | $1.20 | $0.10 | - | -| GLM 4.7 Free | Free | Free | Free | - | +| GLM 5 | $1.00 | $3.20 | $0.20 | - | | GLM 4.7 | $0.60 | $2.20 | $0.10 | - | | GLM 4.6 | $0.60 | $2.20 | $0.10 | - | -| Kimi K2.5 Free | Free | Free | Free | - | -| Kimi K2.5 | $0.60 | $3.00 | $0.08 | - | +| Kimi K2.5 | $0.60 | $3.00 | $0.10 | - | | Kimi K2 Thinking | $0.40 | $2.50 | - | - | | Kimi K2 | $0.40 | $2.50 | - | - | | Qwen3 Coder 480B | $0.45 | $1.50 | - | - | +| Claude Opus 4.6 (≤ 200K tokens) | $5.00 | $25.00 | $0.50 | $6.25 | +| Claude Opus 4.6 (> 200K tokens) | $10.00 | $37.50 | $1.00 | $12.50 | +| Claude Opus 4.5 | $5.00 | $25.00 | $0.50 | $6.25 | +| Claude Opus 4.1 | $15.00 | $75.00 | $1.50 | $18.75 | +| Claude Sonnet 4.6 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 | +| Claude Sonnet 4.6 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 | | Claude Sonnet 4.5 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 | | Claude Sonnet 4.5 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 | | Claude Sonnet 4 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 | | Claude Sonnet 4 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 | | Claude Haiku 4.5 | $1.00 | $5.00 | $0.10 | $1.25 | | Claude Haiku 3.5 | $0.80 | $4.00 | $0.08 | $1.00 | -| Claude Opus 4.6 (≤ 200K tokens) | $5.00 | $25.00 | $0.50 | $6.25 | -| Claude Opus 4.6 (> 200K tokens) | $10.00 | $37.50 | $1.00 | $12.50 | -| Claude Opus 4.5 | $5.00 | $25.00 | $0.50 | $6.25 | -| Claude Opus 4.1 | $15.00 | $75.00 | $1.50 | $18.75 | +| Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | +| Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | | Gemini 3 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | +| GPT 5.4 | $2.50 | $15.00 | $0.25 | - | +| GPT 5.3 Codex | $1.75 | $14.00 | $0.175 | - | | GPT 5.2 | $1.75 | $14.00 | $0.175 | - | | GPT 5.2 Codex | $1.75 | $14.00 | $0.175 | - | | GPT 5.1 | $1.07 | $8.50 | $0.107 | - | @@ -148,8 +158,6 @@ https://opencode.ai/zen/v1/models 무료 모델: -- GLM 5 Free는 한정된 기간 동안 OpenCode에서 제공됩니다. 해당 기간 동안 팀은 사용자 피드백을 수집하고 모델을 개선할 예정입니다. -- Kimi K2.5 Free는 한정된 기간 동안 OpenCode에서 제공됩니다. 해당 기간 동안 팀은 사용자 피드백을 수집하고 모델을 개선할 예정입니다. - MiniMax M2.5 Free는 한정된 기간 동안 OpenCode에서 제공됩니다. 해당 기간 동안 팀은 사용자 피드백을 수집하고 모델을 개선할 예정입니다. - Big Pickle은 한정된 기간 동안 OpenCode에서 무료로 제공되는 스텔스 모델입니다. 해당 기간 동안 팀은 사용자 피드백을 수집하고 모델을 개선할 예정입니다. @@ -169,18 +177,29 @@ https://opencode.ai/zen/v1/models 워크스페이스 전체 및 각 팀 구성원별로 월간 사용 한도를 설정할 수 있습니다. -예를 들어 월간 사용 한도를 $20로 설정한 경우, Zen은 한 달 동안 $20을 초과하여 사용하지 않습니다. +예를 들어 월간 사용 한도를 $20로 설정한 경우, Zen은 한 달 동안 $20을 초과하여 사용하지 않습니다. 다만 자동 충전이 활성화되어 있는 경우, 잔액이 $5 미만으로 내려가면 자동으로 충전이 이루어질 수 있으므로 실제 청구 금액이 $20을 초과할 수 있습니다. --- +### 지원 중단 모델 + +| 모델 | 지원 중단일 | +| ---------------- | --------------- | +| Qwen3 Coder 480B | 2026년 2월 6일 | +| Kimi K2 Thinking | 2026년 3월 6일 | +| Kimi K2 | 2026년 3월 6일 | +| MiniMax M2.1 | 2026년 3월 15일 | +| GLM 4.7 | 2026년 3월 15일 | +| GLM 4.6 | 2026년 3월 15일 | + +--- + ## 개인정보 보호 당사의 모든 모델은 미국에서 호스팅됩니다. 당사 제공자는 데이터 무보존(zero-retention) 정책을 따르며, 아래의 예외를 제외하고는 귀하의 데이터를 모델 학습에 사용하지 않습니다. - Big Pickle: 무료 제공 기간 동안 수집된 데이터는 모델 개선을 위해 사용될 수 있습니다. -- GLM 5 Free: 무료 제공 기간 동안 수집된 데이터는 모델 개선을 위해 사용될 수 있습니다. -- Kimi K2.5 Free: 무료 제공 기간 동안 수집된 데이터는 모델 개선을 위해 사용될 수 있습니다. - MiniMax M2.5 Free: 무료 제공 기간 동안 수집된 데이터는 모델 개선을 위해 사용될 수 있습니다. - OpenAI APIs: 요청 데이터는 [OpenAI의 데이터 정책](https://platform.openai.com/docs/guides/your-data)에 따라 30일간 보관됩니다. - Anthropic APIs: 요청 데이터는 [Anthropic의 데이터 정책](https://docs.anthropic.com/en/docs/claude-code/data-usage)에 따라 30일간 보관됩니다. diff --git a/packages/web/src/content/docs/nb/cli.mdx b/packages/web/src/content/docs/nb/cli.mdx index 2f1b3884ea..409fdb2378 100644 --- a/packages/web/src/content/docs/nb/cli.mdx +++ b/packages/web/src/content/docs/nb/cli.mdx @@ -558,6 +558,7 @@ OpenCode kan konfigureres ved hjelp av miljøvariabler. | `OPENCODE_AUTO_SHARE` | boolsk | Del økter automatisk | | `OPENCODE_GIT_BASH_PATH` | streng | Bane til Git Bash-kjørbar på Windows | | `OPENCODE_CONFIG` | streng | Bane til konfigurasjonsfil | +| `OPENCODE_TUI_CONFIG` | streng | Bane til TUI-konfigurasjonsfil | | `OPENCODE_CONFIG_DIR` | streng | Bane til konfigurasjonskatalog | | `OPENCODE_CONFIG_CONTENT` | streng | Innebygd json-konfigurasjonsinnhold | | `OPENCODE_DISABLE_AUTOUPDATE` | boolsk | Deaktiver automatiske oppdateringskontroller | diff --git a/packages/web/src/content/docs/nb/config.mdx b/packages/web/src/content/docs/nb/config.mdx index 8f54335794..e8b32d5a06 100644 --- a/packages/web/src/content/docs/nb/config.mdx +++ b/packages/web/src/content/docs/nb/config.mdx @@ -14,10 +14,11 @@ OpenCode støtter både **JSON** og **JSONC** (JSON med kommentarer) formater. ```jsonc title="opencode.jsonc" { "$schema": "https://opencode.ai/config.json", - // Theme configuration - "theme": "opencode", "model": "anthropic/claude-sonnet-4-5", "autoupdate": true, + "server": { + "port": 4096, + }, } ``` @@ -301,12 +302,12 @@ Bærer-tokens (`AWS_BEARER_TOKEN_BEDROCK` eller `/connect`) har forrang over pro ### Temaer -Du kan konfigurere temaet du vil bruke i OpenCode-konfigurasjonen gjennom alternativet `theme`. +Angi UI-temaet ditt i `tui.json`. -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", - "theme": "" + "$schema": "https://opencode.ai/tui.json", + "theme": "tokyonight" } ``` @@ -406,11 +407,11 @@ Du kan også definere kommandoer ved å bruke markdown-filer i `~/.config/openco ### Tastebindinger -Du kan tilpasse tastebindingene dine gjennom alternativet `keybinds`. +Tilpass tastebindinger i `tui.json`. -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "keybinds": {} } ``` @@ -490,13 +491,15 @@ Du kan styre kontekstkomprimering gjennom alternativet `compaction`. "$schema": "https://opencode.ai/config.json", "compaction": { "auto": true, - "prune": true + "prune": true, + "reserved": 10000 } } ``` - `auto` - Komprimer økten automatisk når konteksten er full (standard: `true`). - `prune` - Fjern gamle verktøyutdata for å spare tokens (standard: `true`). +- `reserved` - Token-buffer for komprimering. Etterlater nok vindu til å unngå overflyt under komprimering --- diff --git a/packages/web/src/content/docs/nb/custom-tools.mdx b/packages/web/src/content/docs/nb/custom-tools.mdx index 0b88f75077..505c261a0b 100644 --- a/packages/web/src/content/docs/nb/custom-tools.mdx +++ b/packages/web/src/content/docs/nb/custom-tools.mdx @@ -79,6 +79,32 @@ Dette lager to verktøy: `math_add` og `math_multiply`. --- +#### Navnekollisjoner med innebygde verktøy + +Egendefinerte verktøy er nøklet etter verktøynavn. Hvis et egendefinert verktøy bruker samme navn som et innebygd verktøy, vil det egendefinerte verktøyet ha forrang. + +For eksempel erstatter denne filen det innebygde `bash`-verktøyet: + +```ts title=".opencode/tools/bash.ts" +import { tool } from "@opencode-ai/plugin" + +export default tool({ + description: "Restricted bash wrapper", + args: { + command: tool.schema.string(), + }, + async execute(args) { + return `blocked: ${args.command}` + }, +}) +``` + +:::note +Foretrekk unike navn med mindre du med vilje ønsker å erstatte et innebygd verktøy. Hvis du vil deaktivere et innebygd verktøy, men ikke overstyre det, bruk [tillatelser](/docs/permissions). +::: + +--- + ### Argumenter Du kan bruke `tool.schema`, som bare er [Zod](https://zod.dev), for å definere argumenttyper. diff --git a/packages/web/src/content/docs/nb/ecosystem.mdx b/packages/web/src/content/docs/nb/ecosystem.mdx index 714a9ee95e..2c67b9fd8e 100644 --- a/packages/web/src/content/docs/nb/ecosystem.mdx +++ b/packages/web/src/content/docs/nb/ecosystem.mdx @@ -15,38 +15,40 @@ Du kan også sjekke ut [awesome-opencode](https://github.com/awesome-opencode/aw ## Utvidelser -| Navn | Beskrivelse | -| --------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | -| [opencode-daytona](https://github.com/jamesmurdza/daytona/blob/main/guides/typescript/opencode/README.md) | Kjør OpenCode-økter automatisk i isolerte Daytona-sandkasser med git-synkronisering og live-forhåndsvisninger | -| [opencode-helicone-session](https://github.com/H2Shami/opencode-helicone-session) | Injiser automatisk Helicone-headers for forespørselsgruppering | -| [opencode-type-inject](https://github.com/nick-vi/opencode-type-inject) | Auto-injiser TypeScript/Svelte-typer i fillesninger med oppslagsverktøy | -| [opencode-openai-codex-auth](https://github.com/numman-ali/opencode-openai-codex-auth) | Bruk ChatGPT Plus/Pro-abonnementet ditt i stedet for API kreditter | -| [opencode-gemini-auth](https://github.com/jenslys/opencode-gemini-auth) | Bruk din eksisterende Gemini-plan i stedet for API-fakturering | -| [opencode-antigravity-auth](https://github.com/NoeFabris/opencode-antigravity-auth) | Bruk Antigravitys gratis modeller i stedet for API-fakturering | -| [opencode-devcontainers](https://github.com/athal7/opencode-devcontainers) | Multi-branch devcontainer-isolasjon med grunne kloner og automatisk tildelte porter | -| [opencode-google-antigravity-auth](https://github.com/shekohex/opencode-google-antigravity-auth) | Google Antigravity OAuth-plugin, med støtte for Google Søk og mer robust API-håndtering | -| [opencode-dynamic-context-pruning](https://github.com/Tarquinen/opencode-dynamic-context-pruning) | Optimaliser bruken av token ved å beskjære utdaterte verktøy | -| [opencode-websearch-cited](https://github.com/ghoulr/opencode-websearch-cited.git) | Legg til innebygd støtte for nettsøk for støttede leverandører med Googles kildebaserte stil | -| [opencode-pty](https://github.com/shekohex/opencode-pty.git) | Gjør det mulig for AI-agenter å kjøre bakgrunnsprosesser i en PTY, sende interaktiv inndata til dem. | -| [opencode-shell-strategy](https://github.com/JRedeker/opencode-shell-strategy) | Instruksjoner for ikke-interaktive skallkommandoer - forhindrer heng ved TTY-avhengige operasjoner | -| [opencode-wakatime](https://github.com/angristan/opencode-wakatime) | Spor OpenCode-bruk med Wakatime | -| [opencode-md-table-formatter](https://github.com/franlol/opencode-md-table-formatter/tree/main) | Rydd opp i markdown-tabeller produsert av LLMs | -| [opencode-morph-fast-apply](https://github.com/JRedeker/opencode-morph-fast-apply) | 10 ganger raskere koderedigering med Morph Fast Apply API og lazy-redigeringsmarkører | -| [oh-my-opencode](https://github.com/code-yeongyu/oh-my-opencode) | Bakgrunnsagenter, forhåndsbygde LSP/AST/MCP verktøy, kurerte agenter, Claude Code-kompatibel | -| [opencode-notificator](https://github.com/panta82/opencode-notificator) | Skrivebordsvarsler og lydvarsler for OpenCode-økter | -| [opencode-notifier](https://github.com/mohak34/opencode-notifier) | Skrivebordsvarsler og lydvarsler for tillatelse, fullføring og feilhendelser | -| [opencode-zellij-namer](https://github.com/24601/opencode-zellij-namer) | AI-drevet automatisk Zellij-sesjonsnavn basert på OpenCode-kontekst | -| [opencode-skillful](https://github.com/zenobi-us/opencode-skillful) | Tillat OpenCode-agenter å lazy-loade meldinger på forespørsel med ferdighetsoppdagelse og injeksjon | -| [opencode-supermemory](https://github.com/supermemoryai/opencode-supermemory) | Vedvarende minne på tvers av økter ved hjelp av Supermemory | -| [@plannotator/opencode](https://github.com/backnotprop/plannotator/tree/main/apps/opencode-plugin) | Interaktiv plangjennomgang med visuell merknad og privat/offline deling | -| [@openspoon/subtask2](https://github.com/spoons-and-mirrors/subtask2) | Utvid OpenCode /kommandoer til et kraftig orkestreringssystem med granulær flytkontroll | -| [opencode-scheduler](https://github.com/different-ai/opencode-scheduler) | Planlegg gjentakende jobber ved hjelp av launchd (Mac) eller systemd (Linux) med cron-syntaks | -| [micode](https://github.com/vtemian/micode) | Strukturert brainstorm → Plan → Implementer arbeidsflyt med øktkontinuitet | -| [octto](https://github.com/vtemian/octto) | Interaktiv nettleser UI for AI idédugnad med flerspørsmålsskjemaer | -| [opencode-background-agents](https://github.com/kdcokenny/opencode-background-agents) | Claude Bakgrunnsagenter i kodestil med asynkrondelegering og kontekstutholdenhet | -| [opencode-notify](https://github.com/kdcokenny/opencode-notify) | Innfødte OS-varsler for OpenCode – vet når oppgaver fullføres | -| [opencode-workspace](https://github.com/kdcokenny/opencode-workspace) | Medfølgende multi-agent orkestreringsrammeverk – 16 komponenter, én installasjon | -| [opencode-worktree](https://github.com/kdcokenny/opencode-worktree) | Nullfriksjon git-arbeidstre for OpenCode | +| Navn | Beskrivelse | +| -------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | +| [opencode-daytona](https://github.com/daytonaio/daytona/tree/main/libs/opencode-plugin) | Kjør OpenCode-økter automatisk i isolerte Daytona-sandkasser med git-synkronisering og live-forhåndsvisninger | +| [opencode-helicone-session](https://github.com/H2Shami/opencode-helicone-session) | Injiser automatisk Helicone-headers for forespørselsgruppering | +| [opencode-type-inject](https://github.com/nick-vi/opencode-type-inject) | Auto-injiser TypeScript/Svelte-typer i fillesninger med oppslagsverktøy | +| [opencode-openai-codex-auth](https://github.com/numman-ali/opencode-openai-codex-auth) | Bruk ChatGPT Plus/Pro-abonnementet ditt i stedet for API kreditter | +| [opencode-gemini-auth](https://github.com/jenslys/opencode-gemini-auth) | Bruk din eksisterende Gemini-plan i stedet for API-fakturering | +| [opencode-antigravity-auth](https://github.com/NoeFabris/opencode-antigravity-auth) | Bruk Antigravitys gratis modeller i stedet for API-fakturering | +| [opencode-devcontainers](https://github.com/athal7/opencode-devcontainers) | Multi-branch devcontainer-isolasjon med grunne kloner og automatisk tildelte porter | +| [opencode-google-antigravity-auth](https://github.com/shekohex/opencode-google-antigravity-auth) | Google Antigravity OAuth-plugin, med støtte for Google Søk og mer robust API-håndtering | +| [opencode-dynamic-context-pruning](https://github.com/Tarquinen/opencode-dynamic-context-pruning) | Optimaliser bruken av token ved å beskjære utdaterte verktøy | +| [opencode-vibeguard](https://github.com/inkdust2021/opencode-vibeguard) | Sladd hemmeligheter/PII til VibeGuard-stil plassholdere før LLM-kall; gjenopprett lokalt | +| [opencode-websearch-cited](https://github.com/ghoulr/opencode-websearch-cited.git) | Legg til innebygd støtte for nettsøk for støttede leverandører med Googles kildebaserte stil | +| [opencode-pty](https://github.com/shekohex/opencode-pty.git) | Gjør det mulig for AI-agenter å kjøre bakgrunnsprosesser i en PTY, sende interaktiv inndata til dem. | +| [opencode-shell-strategy](https://github.com/JRedeker/opencode-shell-strategy) | Instruksjoner for ikke-interaktive skallkommandoer - forhindrer heng ved TTY-avhengige operasjoner | +| [opencode-wakatime](https://github.com/angristan/opencode-wakatime) | Spor OpenCode-bruk med Wakatime | +| [opencode-md-table-formatter](https://github.com/franlol/opencode-md-table-formatter/tree/main) | Rydd opp i markdown-tabeller produsert av LLMs | +| [opencode-morph-fast-apply](https://github.com/JRedeker/opencode-morph-fast-apply) | 10 ganger raskere koderedigering med Morph Fast Apply API og lazy-redigeringsmarkører | +| [oh-my-opencode](https://github.com/code-yeongyu/oh-my-opencode) | Bakgrunnsagenter, forhåndsbygde LSP/AST/MCP verktøy, kurerte agenter, Claude Code-kompatibel | +| [opencode-notificator](https://github.com/panta82/opencode-notificator) | Skrivebordsvarsler og lydvarsler for OpenCode-økter | +| [opencode-notifier](https://github.com/mohak34/opencode-notifier) | Skrivebordsvarsler og lydvarsler for tillatelse, fullføring og feilhendelser | +| [opencode-zellij-namer](https://github.com/24601/opencode-zellij-namer) | AI-drevet automatisk Zellij-sesjonsnavn basert på OpenCode-kontekst | +| [opencode-skillful](https://github.com/zenobi-us/opencode-skillful) | Tillat OpenCode-agenter å lazy-loade meldinger på forespørsel med ferdighetsoppdagelse og injeksjon | +| [opencode-supermemory](https://github.com/supermemoryai/opencode-supermemory) | Vedvarende minne på tvers av økter ved hjelp av Supermemory | +| [@plannotator/opencode](https://github.com/backnotprop/plannotator/tree/main/apps/opencode-plugin) | Interaktiv plangjennomgang med visuell merknad og privat/offline deling | +| [@openspoon/subtask2](https://github.com/spoons-and-mirrors/subtask2) | Utvid OpenCode /kommandoer til et kraftig orkestreringssystem med granulær flytkontroll | +| [opencode-scheduler](https://github.com/different-ai/opencode-scheduler) | Planlegg gjentakende jobber ved hjelp av launchd (Mac) eller systemd (Linux) med cron-syntaks | +| [micode](https://github.com/vtemian/micode) | Strukturert brainstorm → Plan → Implementer arbeidsflyt med øktkontinuitet | +| [octto](https://github.com/vtemian/octto) | Interaktiv nettleser UI for AI idédugnad med flerspørsmålsskjemaer | +| [opencode-background-agents](https://github.com/kdcokenny/opencode-background-agents) | Claude Code-stil bakgrunnsagenter med asynkrondelegering og kontekstbevaring | +| [opencode-notify](https://github.com/kdcokenny/opencode-notify) | Innfødte OS-varsler for OpenCode – vet når oppgaver fullføres | +| [opencode-workspace](https://github.com/kdcokenny/opencode-workspace) | Medfølgende multi-agent orkestreringsrammeverk – 16 komponenter, én installasjon | +| [opencode-worktree](https://github.com/kdcokenny/opencode-worktree) | Nullfriksjon git-arbeidstre for OpenCode | +| [opencode-sentry-monitor](https://github.com/stolinski/opencode-sentry-monitor) | Spor og feilsøk AI-agentene dine med Sentry AI Monitoring | --- diff --git a/packages/web/src/content/docs/nb/go.mdx b/packages/web/src/content/docs/nb/go.mdx new file mode 100644 index 0000000000..dcda3ec346 --- /dev/null +++ b/packages/web/src/content/docs/nb/go.mdx @@ -0,0 +1,159 @@ +--- +title: Go +description: Lavkostnadsabonnement for åpne kodemodeller. +--- + +import config from "../../../../config.mjs" +export const console = config.console +export const email = `mailto:${config.email}` + +OpenCode Go er et lavkostnadsabonnement til **$10/måned** som gir deg pålitelig tilgang til populære åpne kodemodeller. + +:::note +OpenCode Go er for tiden i beta. +::: + +Go fungerer som enhver annen leverandør i OpenCode. Du abonnerer på OpenCode Go og +får din API-nøkkel. Det er **helt valgfritt** og du trenger ikke bruke det for å +bruke OpenCode. + +Det er designet primært for internasjonale brukere, med modeller driftet i USA, EU og Singapore for stabil global tilgang. + +--- + +## Bakgrunn + +Åpne modeller har blitt veldig bra. De når nå ytelse nær +proprietære modeller for kodeoppgaver. Og fordi mange leverandører kan servere dem +konkurransedyktig, er de vanligvis mye billigere. + +Imidlertid kan det være vanskelig å få pålitelig tilgang med lav ventetid. Leverandører +varierer i kvalitet og tilgjengelighet. + +:::tip +Vi testet en utvalgt gruppe modeller og leverandører som fungerer bra med OpenCode. +::: + +For å fikse dette gjorde vi et par ting: + +1. Vi testet en utvalgt gruppe åpne modeller og snakket med teamene deres om hvordan man + best kjører dem. +2. Vi jobbet deretter med noen få leverandører for å sikre at disse ble servert + riktig. +3. Til slutt ytelsestestet vi kombinasjonen av modell/leverandør og kom opp + med en liste som vi føler oss trygge på å anbefale. + +OpenCode Go gir deg tilgang til disse modellene for **$10/måned**. + +--- + +## Hvordan det fungerer + +OpenCode Go fungerer som enhver annen leverandør i OpenCode. + +1. Du logger deg inn på **<a href={console}>OpenCode Zen</a>**, abonnerer på Go, og + kopierer API-nøkkelen din. +2. Du kjører kommandoen `/connect` i TUI-en, velger `OpenCode Go`, og limer inn + API-nøkkelen din. +3. Kjør `/models` i TUI-en for å se listen over modeller tilgjengelig gjennom Go. + +:::note +Bare ett medlem per arbeidsområde kan abonnere på OpenCode Go. +::: + +Den nåværende listen over modeller inkluderer: + +- **GLM-5** +- **Kimi K2.5** +- **MiniMax M2.5** + +Listen over modeller kan endres etter hvert som vi tester og legger til nye. + +--- + +## Bruksgrenser + +OpenCode Go inkluderer følgende grenser: + +- **5 timers grense** — $12 i bruk +- **Ukentlig grense** — $30 i bruk +- **Månedlig grense** — $60 i bruk + +Grensene er definert i dollarverdi. Dette betyr at ditt faktiske antall forespørsler avhenger av modellen du bruker. Billigere modeller som MiniMax M2.5 tillater flere forespørsler, mens dyrere modeller som GLM-5 tillater færre. + +Tabellen nedenfor gir et estimert antall forespørsler basert på typiske Go-bruksmønstre: + +| | GLM-5 | Kimi K2.5 | MiniMax M2.5 | +| ------------------------ | ----- | --------- | ------------ | +| forespørsler per 5 timer | 1,150 | 1,850 | 30,000 | +| forespørsler per uke | 2,880 | 4,630 | 75,000 | +| forespørsler per måned | 5,750 | 9,250 | 150,000 | + +Estimater er basert på observerte gjennomsnittlige forespørselsmønstre: + +- GLM-5 — 700 input, 52,000 cached, 150 output tokens per forespørsel +- Kimi K2.5 — 870 input, 55,000 cached, 200 output tokens per forespørsel +- MiniMax M2.5 — 300 input, 55,000 cached, 125 output tokens per forespørsel + +Du kan spore din nåværende bruk i **<a href={console}>konsollen</a>**. + +:::tip +Hvis du når bruksgrensen, kan du fortsette å bruke de gratis modellene. +::: + +Bruksgrenser kan endres etter hvert som vi lærer fra tidlig bruk og tilbakemeldinger. + +--- + +### Priser + +OpenCode Go er et **$10/måned** abonnementsplan. Nedenfor er prisene **per 1M tokens**. + +| Modell | Input | Output | Bufret lesing | +| ------------ | ----- | ------ | ------------- | +| GLM-5 | $1.00 | $3.20 | $0.20 | +| Kimi K2.5 | $0.60 | $3.00 | $0.10 | +| MiniMax M2.5 | $0.30 | $1.20 | $0.03 | + +--- + +### Bruk utover grensene + +Hvis du også har kreditter på din Zen-saldo, kan du aktivere alternativet **Bruk saldo** +i konsollen. Når aktivert, vil Go falle tilbake til Zen-saldoen din +etter at du har nådd bruksgrensene dine i stedet for å blokkere forespørsler. + +--- + +## Endepunkter + +Du kan også få tilgang til Go-modeller gjennom følgende API-endepunkter. + +| Modell | Modell-ID | Endepunkt | AI SDK Pakke | +| ------------ | ------------ | ------------------------------------------------ | --------------------------- | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | + +[Modell-ID-en](/docs/config/#models) i din OpenCode-konfigurasjon +bruker formatet `opencode-go/<model-id>`. For eksempel, for Kimi K2.5, ville du +bruke `opencode-go/kimi-k2.5` i konfigurasjonen din. + +--- + +## Personvern + +Planen er designet primært for internasjonale brukere, med modeller driftet i USA, EU og Singapore for stabil global tilgang. + +<a href={email}>Kontakt oss</a> hvis du har noen spørsmål. + +--- + +## Mål + +Vi opprettet OpenCode Go for å: + +1. Gjøre AI-koding **tilgjengelig** for flere mennesker med et lavkostnadsabonnement. +2. Gi **pålitelig** tilgang til de beste åpne kodemodellene. +3. Kurere modeller som er **testet og ytelsestestet** for bruk av kodeagenter. +4. Ha **ingen innlåsing** ved å tillate deg å bruke hvilken som helst annen leverandør med OpenCode også. diff --git a/packages/web/src/content/docs/nb/keybinds.mdx b/packages/web/src/content/docs/nb/keybinds.mdx index d762a647f2..f9837480dc 100644 --- a/packages/web/src/content/docs/nb/keybinds.mdx +++ b/packages/web/src/content/docs/nb/keybinds.mdx @@ -3,11 +3,11 @@ title: Tastebindinger description: Tilpass tastebindingene dine. --- -OpenCode har en liste over tastebindinger som du kan tilpasse gjennom OpenCode-konfigurasjonen. +OpenCode har en liste over tastebindinger som du kan tilpasse gjennom `tui.json`. -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "keybinds": { "leader": "ctrl+x", "app_exit": "ctrl+c,ctrl+d,<leader>q", @@ -28,6 +28,7 @@ OpenCode har en liste over tastebindinger som du kan tilpasse gjennom OpenCode-k "session_unshare": "none", "session_interrupt": "escape", "session_compact": "<leader>c", + "session_child_first": "<leader>down", "session_child_cycle": "<leader>right", "session_child_cycle_reverse": "<leader>left", "session_parent": "<leader>up", @@ -117,11 +118,11 @@ Du trenger ikke å bruke en ledertast for tastebindingene dine, men vi anbefaler ## Deaktivering av tastebindinger -Du kan deaktivere en tastebinding ved å legge til tasten til konfigurasjonen med verdien "none". +Du kan deaktivere en tastebinding ved å legge til tasten til `tui.json` med en verdi på "none". -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "keybinds": { "session_compact": "none" } diff --git a/packages/web/src/content/docs/nb/lsp.mdx b/packages/web/src/content/docs/nb/lsp.mdx index c52b79a32d..924b0dad1a 100644 --- a/packages/web/src/content/docs/nb/lsp.mdx +++ b/packages/web/src/content/docs/nb/lsp.mdx @@ -27,6 +27,7 @@ OpenCode kommer med flere innebygde LSP-servere for populære språk: | gopls | .go | `go` kommando tilgjengelig | | hls | .hs, .lhs | `haskell-language-server-wrapper` kommando tilgjengelig | | jdtls | .java | `Java SDK (version 21+)` installert | +| julials | .jl | `julia` og `LanguageServer.jl` installert | | kotlin-ls | .kt, .kts | Installeres automatisk for Kotlin-prosjekter | | lua-ls | .lua | Installeres automatisk for Lua-prosjekter | | nixd | .nix | `nixd` kommando tilgjengelig | diff --git a/packages/web/src/content/docs/nb/modes.mdx b/packages/web/src/content/docs/nb/modes.mdx index 0322f06930..ccf9180e4e 100644 --- a/packages/web/src/content/docs/nb/modes.mdx +++ b/packages/web/src/content/docs/nb/modes.mdx @@ -4,7 +4,7 @@ description: Ulike moduser for forskjellige brukstilfeller. --- :::caution -Moduser er nå konfigurert gjennom alternativet `agent` i OpenCode-konfigurasjonen. De +Moduser konfigureres nå gjennom alternativet `agent` i OpenCode-konfigurasjonen. Alternativet `mode` er nå utdatert. [Finn ut mer](/docs/agents). ::: @@ -13,6 +13,14 @@ Moduser i OpenCode lar deg tilpasse oppførselen, verktøyene og prompter for ul Den kommer med to innebygde moduser: **bygg** og **plan**. Du kan tilpasse disse eller konfigurer din egen gjennom OpenCode-konfigurasjonen. +Du kan bytte mellom moduser under en økt eller konfigurere dem i konfigurasjonsfilen din. + +--- + +## Innebygd + +OpenCode kommer med to innebygde moduser. + --- ### Bygg @@ -34,6 +42,96 @@ Denne modusen er nyttig når du vil at AI skal analysere kode, foreslå endringe --- +## Bytte + +Du kan bytte mellom moduser under en økt ved å bruke _Tab_-tasten. Eller din konfigurerte `switch_mode` hurtigtast. + +Se også: [Formatters](/docs/formatters) for informasjon om kodeformateringskonfigurasjon. + +--- + +## Konfigurer + +Du kan tilpasse de innebygde modusene eller opprette din egen gjennom konfigurasjon. Moduser kan konfigureres på to måter: + +### JSON-konfigurasjon + +Konfigurer moduser i din `opencode.json` konfigurasjonsfil: + +```json title="opencode.json" +{ + "$schema": "https://opencode.ai/config.json", + "mode": { + "build": { + "model": "anthropic/claude-sonnet-4-20250514", + "prompt": "{file:./prompts/build.txt}", + "tools": { + "write": true, + "edit": true, + "bash": true + } + }, + "plan": { + "model": "anthropic/claude-haiku-4-20250514", + "tools": { + "write": false, + "edit": false, + "bash": false + } + } + } +} +``` + +### Markdown-konfigurasjon + +Du kan også definere moduser ved hjelp av markdown-filer. Plasser dem i: + +- Globalt: `~/.config/opencode/modes/` +- Prosjekt: `.opencode/modes/` + +```markdown title="~/.config/opencode/modes/review.md" +--- +model: anthropic/claude-sonnet-4-20250514 +temperature: 0.1 +tools: + write: false + edit: false + bash: false +--- + +You are in code review mode. Focus on: + +- Code quality and best practices +- Potential bugs and edge cases +- Performance implications +- Security considerations + +Provide constructive feedback without making direct changes. +``` + +Filnavnet til markdown-filen blir modusnavnet (f.eks. `review.md` oppretter en `review`-modus). + +La oss se på disse konfigurasjonsalternativene i detalj. + +--- + +### Modell + +Bruk `model`-konfigurasjonen for å overstyre standardmodellen for denne modusen. Nyttig for å bruke forskjellige modeller optimalisert for forskjellige oppgaver. For eksempel en raskere modell for planlegging, en mer kapabel modell for implementering. + +```json title="opencode.json" +{ + "mode": { + "plan": { + "model": "anthropic/claude-haiku-4-20250514" + } + } +} +``` + +--- + ### Temperatur Kontroller tilfeldigheten og kreativiteten til AI-ens svar med `temperature`-konfigurasjonen. Lavere verdier gjør svarene mer fokuserte og deterministiske, mens høyere verdier øker kreativiteten og variasjonen. @@ -54,13 +152,171 @@ Kontroller tilfeldigheten og kreativiteten til AI-ens svar med `temperature`-kon Temperaturverdier varierer vanligvis fra 0,0 til 1,0: - **0.0-0.2**: Veldig fokuserte og deterministiske svar, ideelt for kodeanalyse og planlegging -- **0,3-0,5**: Balanserte svar med litt kreativitet, bra for generelle utviklingsoppgaver +- **0.3-0.5**: Balanserte svar med litt kreativitet, bra for generelle utviklingsoppgaver - **0.6-1.0**: Mer kreative og varierte svar, nyttig for idédugnad og utforskning +```json title="opencode.json" +{ + "mode": { + "analyze": { + "temperature": 0.1, + "prompt": "{file:./prompts/analysis.txt}" + }, + "build": { + "temperature": 0.3 + }, + "brainstorm": { + "temperature": 0.7, + "prompt": "{file:./prompts/creative.txt}" + } + } +} +``` + Hvis ingen temperatur er spesifisert, bruker OpenCode modellspesifikke standardinnstillinger (vanligvis 0 for de fleste modeller, 0,55 for Qwen-modeller). --- +### Prompt + +Angi en tilpasset systemprompt-fil for denne modusen med `prompt`-konfigurasjonen. Prompt-filen skal inneholde instruksjoner som er spesifikke for modusens formål. + +```json title="opencode.json" +{ + "mode": { + "review": { + "prompt": "{file:./prompts/code-review.txt}" + } + } +} +``` + +Denne banen er relativ til der konfigurasjonsfilen er plassert. Så dette fungerer for både den globale OpenCode-konfigurasjonen og den prosjektspesifikke konfigurasjonen. + +--- + +### Verktøy + +Kontroller hvilke verktøy som er tilgjengelige i denne modusen med `tools`-konfigurasjonen. Du kan aktivere eller deaktivere spesifikke verktøy ved å sette dem til `true` eller `false`. + +```json +{ + "mode": { + "readonly": { + "tools": { + "write": false, + "edit": false, + "bash": false, + "read": true, + "grep": true, + "glob": true + } + } + } +} +``` + +Hvis ingen verktøy er spesifisert, er alle verktøy aktivert som standard. + +--- + +#### Tilgjengelige verktøy + +Her er alle verktøyene som kan kontrolleres gjennom moduskonfigurasjonen. + +| Verktøy | Beskrivelse | +| ----------- | --------------------------- | +| `bash` | Utfør shell-kommandoer | +| `edit` | Endre eksisterende filer | +| `write` | Opprett nye filer | +| `read` | Les filinnhold | +| `grep` | Søk i filinnhold | +| `glob` | Finn filer etter mønster | +| `list` | List opp kataloginnhold | +| `patch` | Bruk patcher på filer | +| `todowrite` | Administrer gjøremålslister | +| `todoread` | Les gjøremålslister | +| `webfetch` | Hent webinnhold | + +--- + +## Egendefinerte moduser + +Du kan opprette dine egne tilpassede moduser ved å legge dem til i konfigurasjonen. Her er eksempler på bruk av begge metodene: + +### Bruke JSON-konfigurasjon + +```json title="opencode.json" {4-14} +{ + "$schema": "https://opencode.ai/config.json", + "mode": { + "docs": { + "prompt": "{file:./prompts/documentation.txt}", + "tools": { + "write": true, + "edit": true, + "bash": false, + "read": true, + "grep": true, + "glob": true + } + } + } +} +``` + +### Bruke markdown-filer + +Opprett modusfiler i `.opencode/modes/` for prosjektspesifikke moduser eller `~/.config/opencode/modes/` for globale moduser: + +```markdown title=".opencode/modes/debug.md" +--- +temperature: 0.1 +tools: + bash: true + read: true + grep: true + write: false + edit: false +--- + +You are in debug mode. Your primary goal is to help investigate and diagnose issues. + +Focus on: + +- Understanding the problem through careful analysis +- Using bash commands to inspect system state +- Reading relevant files and logs +- Searching for patterns and anomalies +- Providing clear explanations of findings + +Do not make any changes to files. Only investigate and report. +``` + +```markdown title="~/.config/opencode/modes/refactor.md" +--- +model: anthropic/claude-sonnet-4-20250514 +temperature: 0.2 +tools: + edit: true + read: true + grep: true + glob: true +--- + +You are in refactoring mode. Focus on improving code quality without changing functionality. + +Priorities: + +- Improve code readability and maintainability +- Apply consistent naming conventions +- Reduce code duplication +- Optimize performance where appropriate +- Ensure all tests continue to pass +``` + +--- + ### Bruksområder Her er noen vanlige bruksområder for forskjellige moduser. diff --git a/packages/web/src/content/docs/nb/plugins.mdx b/packages/web/src/content/docs/nb/plugins.mdx index 6b6e1edf3f..27d23ec63a 100644 --- a/packages/web/src/content/docs/nb/plugins.mdx +++ b/packages/web/src/content/docs/nb/plugins.mdx @@ -1,6 +1,6 @@ --- title: Programtillegg -description: Skriv dine egne programtillegg for å utvide opencode. +description: Skriv dine egne programtillegg for å utvide OpenCode. --- Plugins lar deg utvide OpenCode ved å koble til ulike hendelser og tilpasse atferd. Du kan lage plugins for å legge til nye funksjoner, integrere med eksterne tjenester eller endre standardoppførselen til OpenCode. @@ -308,6 +308,10 @@ export const CustomToolsPlugin: Plugin = async (ctx) => { Dine egendefinerte verktøy vil være tilgjengelige for OpenCode sammen med innebygde verktøy. +:::note +Hvis et plugin-verktøy bruker samme navn som et innebygd verktøy, vil plugin-verktøyet ha forrang. +::: + --- ### Logging diff --git a/packages/web/src/content/docs/nb/providers.mdx b/packages/web/src/content/docs/nb/providers.mdx index 58d325cab8..682f923f8c 100644 --- a/packages/web/src/content/docs/nb/providers.mdx +++ b/packages/web/src/content/docs/nb/providers.mdx @@ -57,7 +57,7 @@ testet og verifisert for å fungere godt med OpenCode. [Finn ut mer](/docs/zen). Hvis du er ny, anbefaler vi å starte med OpenCode Zen. ::: -1. Kjør kommandoen `/connect` i TUI, velg opencode og gå til [opencode.ai/auth](https://opencode.ai/auth). +1. Kjør kommandoen `/connect` i TUI, velg `OpenCode Zen` og gå til [opencode.ai/auth](https://opencode.ai/zen). ```txt /connect @@ -84,6 +84,39 @@ Det fungerer som alle andre leverandører i OpenCode og er helt valgfritt å bru --- +## OpenCode Go + +OpenCode Go er en lavpris abonnementsplan som gir pålitelig tilgang til populære åpne kodemodeller levert av OpenCode-teamet som har vært +testet og verifisert for å fungere godt med OpenCode. + +1. Kjør kommandoen `/connect` i TUI, velg `OpenCode Go`, og gå til [opencode.ai/auth](https://opencode.ai/zen). + + ```txt + /connect + ``` + +2. Logg på, legg til faktureringsdetaljene dine og kopier API-nøkkelen. + +3. Lim inn API-nøkkelen. + + ```txt + ┌ API key + │ + │ + │ + └ enter + ``` + +4. Kjør `/models` i TUI for å se listen over modeller vi anbefaler. + + ```txt + /models + ``` + +Det fungerer som alle andre leverandører i OpenCode og er helt valgfritt å bruke. + +--- + ## Katalog La oss se på noen av leverandørene i detalj. Hvis du vil legge til en leverandør til diff --git a/packages/web/src/content/docs/nb/sdk.mdx b/packages/web/src/content/docs/nb/sdk.mdx index bbff8ebece..a947094476 100644 --- a/packages/web/src/content/docs/nb/sdk.mdx +++ b/packages/web/src/content/docs/nb/sdk.mdx @@ -117,6 +117,78 @@ try { --- +## Strukturert Utdata + +Du kan be om strukturert JSON-utdata fra modellen ved å spesifisere et `format` med et JSON-skjema. Modellen vil bruke et `StructuredOutput`-verktøy for å returnere validert JSON som samsvarer med skjemaet ditt. + +### Grunnleggende bruk + +```typescript +const result = await client.session.prompt({ + path: { id: sessionId }, + body: { + parts: [{ type: "text", text: "Research Anthropic and provide company info" }], + format: { + type: "json_schema", + schema: { + type: "object", + properties: { + company: { type: "string", description: "Company name" }, + founded: { type: "number", description: "Year founded" }, + products: { + type: "array", + items: { type: "string" }, + description: "Main products", + }, + }, + required: ["company", "founded"], + }, + }, + }, +}) + +// Access the structured output +console.log(result.data.info.structured_output) +// { company: "Anthropic", founded: 2021, products: ["Claude", "Claude API"] } +``` + +### Utdataformattyper + +| Type | Beskrivelse | +| ------------- | --------------------------------------------------------------- | +| `text` | Standard. Standard tekstrespons (ingen strukturert utdata) | +| `json_schema` | Returnerer validert JSON som samsvarer med det angitte skjemaet | + +### JSON Skjemaformat + +Når du bruker `type: 'json_schema'`, oppgi: + +| Felt | Type | Beskrivelse | +| ------------ | --------------- | ---------------------------------------------------------- | +| `type` | `'json_schema'` | Påkrevd. Spesifiserer JSON-skjemamodus | +| `schema` | `object` | Påkrevd. JSON Schema-objekt som definerer utdatastrukturen | +| `retryCount` | `number` | Valgfritt. Antall valideringsforsøk (standard: 2) | + +### Feilhåndtering + +Hvis modellen ikke klarer å produsere gyldig strukturert utdata etter alle forsøk, vil svaret inkludere en `StructuredOutputError`: + +```typescript +if (result.data.info.error?.name === "StructuredOutputError") { + console.error("Failed to produce structured output:", result.data.info.error.message) + console.error("Attempts:", result.data.info.error.retries) +} +``` + +### Beste praksis + +1. **Gi klare beskrivelser** i skjemaegenskapene dine for å hjelpe modellen med å forstå hvilke data som skal trekkes ut +2. **Bruk `required`** for å spesifisere hvilke felt som må være til stede +3. **Hold skjemaer fokuserte** - komplekse nøstede skjemaer kan være vanskeligere for modellen å fylle ut riktig +4. **Angi passende `retryCount`** - øk for komplekse skjemaer, reduser for enkle + +--- + ## API-er SDK-en eksponerer alle server-API-er gjennom en typesikker klient. @@ -226,27 +298,27 @@ const { providers, default: defaults } = await client.config.providers() ### Sesjoner -| Metode | Beskrivelse | Merknader | -| ---------------------------------------------------------- | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | -| `session.list()` | List økter | Returnerer <a href={typesUrl}><code>Session[]</code></a> | -| `session.get({ path })` | Hent økt | Returnerer <a href={typesUrl}><code>Session</code></a> | -| `session.children({ path })` | List barneøkter | Returnerer <a href={typesUrl}><code>Session[]</code></a> | -| `session.create({ body })` | Opprett økt | Returnerer <a href={typesUrl}><code>Session</code></a> | -| `session.delete({ path })` | Slett økt | Returnerer `boolean` | -| `session.update({ path, body })` | Oppdater øktegenskaper | Returnerer <a href={typesUrl}><code>Session</code></a> | -| `session.init({ path, body })` | Analyser appen og lag `AGENTS.md` | Returnerer `boolean` | -| `session.abort({ path })` | Avbryt en kjørende økt | Returnerer `boolean` | -| `session.share({ path })` | Del økten | Returnerer <a href={typesUrl}><code>Session</code></a> | -| `session.unshare({ path })` | Slutt å dele økten | Returnerer <a href={typesUrl}><code>Session</code></a> | -| `session.summarize({ path, body })` | Oppsummer økten | Returnerer `boolean` | -| `session.messages({ path })` | List meldinger i en økt | Returnerer `{ info: `<a href={typesUrl}><code>Message</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}[]` | -| `session.message({ path })` | Hent meldingsdetaljer | Returnerer `{ info: `<a href={typesUrl}><code>Message</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}` | -| `session.prompt({ path, body })` | Send melding | `body.noReply: true` returnerer UserMessage (kun kontekst). Standard returnerer <a href={typesUrl}><code>AssistantMessage</code></a> med AI svar | -| `session.command({ path, body })` | Send kommando til økt | Returnerer `{ info: `<a href={typesUrl}><code>AssistantMessage</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}` | -| `session.shell({ path, body })` | Kjør en shell-kommando | Returnerer <a href={typesUrl}><code>AssistantMessage</code></a> | -| `session.revert({ path, body })` | Tilbakestill en melding | Returnerer <a href={typesUrl}><code>Session</code></a> | -| `session.unrevert({ path })` | Gjenopprett reverserte meldinger | Returnerer <a href={typesUrl}><code>Session</code></a> | -| `postSessionByIdPermissionsByPermissionId({ path, body })` | Svar på en tillatelsesforespørsel | Returnerer `boolean` | +| Metode | Beskrivelse | Merknader | +| ---------------------------------------------------------- | --------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `session.list()` | List økter | Returnerer <a href={typesUrl}><code>Session[]</code></a> | +| `session.get({ path })` | Hent økt | Returnerer <a href={typesUrl}><code>Session</code></a> | +| `session.children({ path })` | List barneøkter | Returnerer <a href={typesUrl}><code>Session[]</code></a> | +| `session.create({ body })` | Opprett økt | Returnerer <a href={typesUrl}><code>Session</code></a> | +| `session.delete({ path })` | Slett økt | Returnerer `boolean` | +| `session.update({ path, body })` | Oppdater øktegenskaper | Returnerer <a href={typesUrl}><code>Session</code></a> | +| `session.init({ path, body })` | Analyser appen og lag `AGENTS.md` | Returnerer `boolean` | +| `session.abort({ path })` | Avbryt en kjørende økt | Returnerer `boolean` | +| `session.share({ path })` | Del økten | Returnerer <a href={typesUrl}><code>Session</code></a> | +| `session.unshare({ path })` | Slutt å dele økten | Returnerer <a href={typesUrl}><code>Session</code></a> | +| `session.summarize({ path, body })` | Oppsummer økten | Returnerer `boolean` | +| `session.messages({ path })` | List meldinger i en økt | Returnerer `{ info: `<a href={typesUrl}><code>Message</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}[]` | +| `session.message({ path })` | Hent meldingsdetaljer | Returnerer `{ info: `<a href={typesUrl}><code>Message</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}` | +| `session.prompt({ path, body })` | Send melding | `body.noReply: true` returnerer UserMessage (kun kontekst). Standard returnerer <a href={typesUrl}><code>AssistantMessage</code></a> med AI svar. Støtter `body.outputFormat` for [strukturert utdata](#strukturert-utdata) | +| `session.command({ path, body })` | Send kommando til økt | Returnerer `{ info: `<a href={typesUrl}><code>AssistantMessage</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}` | +| `session.shell({ path, body })` | Kjør en shell-kommando | Returnerer <a href={typesUrl}><code>AssistantMessage</code></a> | +| `session.revert({ path, body })` | Tilbakestill en melding | Returnerer <a href={typesUrl}><code>Session</code></a> | +| `session.unrevert({ path })` | Gjenopprett reverserte meldinger | Returnerer <a href={typesUrl}><code>Session</code></a> | +| `postSessionByIdPermissionsByPermissionId({ path, body })` | Svar på en tillatelsesforespørsel | Returnerer `boolean` | --- diff --git a/packages/web/src/content/docs/nb/share.mdx b/packages/web/src/content/docs/nb/share.mdx index 370477d1cf..ca0cb4829a 100644 --- a/packages/web/src/content/docs/nb/share.mdx +++ b/packages/web/src/content/docs/nb/share.mdx @@ -41,7 +41,7 @@ For å eksplisitt angi manuell modus i [konfigurasjonsfilen](/docs/config): ```json title="opencode.json" { - "$schema": "https://opncd.ai/config.json", + "$schema": "https://opencode.ai/config.json", "share": "manual" } ``` @@ -54,7 +54,7 @@ Du kan aktivere automatisk deling for alle nye samtaler ved å sette alternative ```json title="opencode.json" { - "$schema": "https://opncd.ai/config.json", + "$schema": "https://opencode.ai/config.json", "share": "auto" } ``` @@ -69,7 +69,7 @@ Du kan deaktivere deling helt ved å sette alternativet `share` til `"disabled"` ```json title="opencode.json" { - "$schema": "https://opncd.ai/config.json", + "$schema": "https://opencode.ai/config.json", "share": "disabled" } ``` diff --git a/packages/web/src/content/docs/nb/themes.mdx b/packages/web/src/content/docs/nb/themes.mdx index a294a6a0fa..2284848e31 100644 --- a/packages/web/src/content/docs/nb/themes.mdx +++ b/packages/web/src/content/docs/nb/themes.mdx @@ -3,9 +3,9 @@ title: Temaer description: Velg et innebygd tema eller definer ditt eget. --- -Med opencode kan du velge fra ett av flere innebygde temaer, bruke et tema som tilpasser seg terminaltemaet ditt, eller definere ditt eget tilpassede tema. +Med OpenCode kan du velge fra ett av flere innebygde temaer, bruke et tema som tilpasser seg terminaltemaet ditt, eller definere ditt eget tilpassede tema. -Som standard bruker opencode vårt eget `opencode`-tema. +Som standard bruker OpenCode vårt eget `opencode`-tema. --- @@ -23,7 +23,7 @@ Uten truecolor-støtte kan temaer vises med redusert fargenøyaktighet eller fal ## Innebygde temaer -opencode kommer med flere innebygde temaer. +OpenCode kommer med flere innebygde temaer. | Navn | Beskrivelse | | ---------------------- | ------------------------------------------------------------------------- | @@ -53,7 +53,7 @@ Og mer, vi legger stadig til nye temaer. Systemtemaet er for brukere som: -- Vil at opencode skal matche terminalens utseende +- Vil at OpenCode skal matche terminalens utseende - Bruker tilpassede terminalfargeskjemaer - Foretrekker et konsistent utseende på tvers av alle terminalapplikasjoner @@ -61,11 +61,11 @@ Systemtemaet er for brukere som: ## Bruke et tema -Du kan velge et tema ved å åpne temavelgeren med kommandoen `/theme`. Eller du kan spesifisere det i [config](/docs/config). +Du kan velge et tema ved å åpne temavelgeren med kommandoen `/theme`. Eller du kan spesifisere det i `tui.json`. -```json title="opencode.json" {3} +```json title="tui.json" {3} { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "theme": "tokyonight" } ``` @@ -74,7 +74,7 @@ Du kan velge et tema ved å åpne temavelgeren med kommandoen `/theme`. Eller du ## Egendefinerte temaer -opencode støtter et fleksibelt JSON-basert temasystem som lar brukere enkelt lage og tilpasse temaer. +OpenCode støtter et fleksibelt JSON-basert temasystem som lar brukere enkelt lage og tilpasse temaer. --- diff --git a/packages/web/src/content/docs/nb/tui.mdx b/packages/web/src/content/docs/nb/tui.mdx index fae2a2364c..741ba46029 100644 --- a/packages/web/src/content/docs/nb/tui.mdx +++ b/packages/web/src/content/docs/nb/tui.mdx @@ -5,9 +5,9 @@ description: Bruke opencode-terminalbrukergrensesnittet. import { Tabs, TabItem } from "@astrojs/starlight/components" -opencode gir et interaktivt terminalgrensesnitt (TUI) for å jobbe med prosjektene dine med en LLM. +OpenCode gir et interaktivt terminalgrensesnitt (TUI) for å jobbe med prosjektene dine med en LLM. -Å kjøre opencode starter TUI for gjeldende katalog. +Å kjøre OpenCode starter TUI for gjeldende katalog. ```bash opencode @@ -57,7 +57,7 @@ Utdataene fra kommandoen legges til samtalen som et verktøyresultat. ## Kommandoer -Når du bruker opencode TUI, kan du skrive `/` etterfulgt av et kommandonavn for raskt å utføre handlinger. For eksempel: +Når du bruker OpenCode TUI, kan du skrive `/` etterfulgt av et kommandonavn for raskt å utføre handlinger. For eksempel: ```bash frame="none" /help @@ -71,7 +71,7 @@ Her er alle tilgjengelige slash-kommandoer: ### connect -Legg til en leverandør til opencode. Lar deg velge fra tilgjengelige leverandører og legge til deres API-nøkler. +Legg til en leverandør til OpenCode. Lar deg velge fra tilgjengelige leverandører og legge til deres API-nøkler. ```bash frame="none" /connect @@ -117,7 +117,7 @@ Veksle visning av verktøydetaljer. ### exit -Avslutt opencode. _Aliaser_: `/quit`, `/q` +Avslutt OpenCode. _Aliaser_: `/quit`, `/q` ```bash frame="none" /exit @@ -230,12 +230,12 @@ Del gjeldende økt. [Finn ut mer](/docs/share). --- -### theme +### themes Liste over tilgjengelige temaer. ```bash frame="none" -/theme +/themes ``` **Nøkkelbinding:** `ctrl+x t` @@ -355,24 +355,34 @@ Noen editorer trenger kommandolinjeargumenter for å kjøre i blokkeringsmodus. ## Konfigurasjon -Du kan tilpasse TUI-oppførselen gjennom opencode-konfigurasjonsfilen. +Du kan tilpasse TUI-oppførselen gjennom `tui.json` (eller `tui.jsonc`). -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", - "tui": { - "scroll_speed": 3, - "scroll_acceleration": { - "enabled": true - } - } + "$schema": "https://opencode.ai/tui.json", + "theme": "opencode", + "keybinds": { + "leader": "ctrl+x" + }, + "scroll_speed": 3, + "scroll_acceleration": { + "enabled": true + }, + "diff_style": "auto" } ``` +Dette er atskilt fra `opencode.json`, som konfigurerer server-/kjøretidsoppførsel. + ### Alternativer -- `scroll_acceleration` - Aktiver rulleakselerasjon i macOS-stil for jevn, naturlig rulling. Når aktivert, øker rullehastigheten med raske rullebevegelser og forblir presis for langsommere bevegelser. **Denne innstillingen har forrang over `scroll_speed` og overstyrer den når den er aktivert.** -- `scroll_speed` - Styrer hvor raskt TUI ruller når du bruker rullekommandoer (minimum: `1`). Standard er `3`. **Merk: Dette ignoreres hvis `scroll_acceleration.enabled` er satt til `true`.** +- `theme` - Angir UI-temaet ditt. [Finn ut mer](/docs/themes). +- `keybinds` - Tilpasser hurtigtaster. [Finn ut mer](/docs/keybinds). +- `scroll_acceleration.enabled` - Aktiver rulleakselerasjon i macOS-stil for jevn, naturlig rulling. Når aktivert, øker rullehastigheten med raske rullebevegelser og forblir presis for langsommere bevegelser. **Denne innstillingen har forrang over `scroll_speed` og overstyrer den når den er aktivert.** +- `scroll_speed` - Styrer hvor raskt TUI ruller når du bruker rullekommandoer (minimum: `0.001`, støtter desimalverdier). Standard er `3`. **Merk: Dette ignoreres hvis `scroll_acceleration.enabled` er satt til `true`.** +- `diff_style` - Kontrollerer diff-gjengivelse. `"auto"` tilpasser seg terminalbredden, `"stacked"` viser alltid en enkeltkolonneoppsett. + +Bruk `OPENCODE_TUI_CONFIG` for å laste en egendefinert TUI-konfigurasjonsbane. --- diff --git a/packages/web/src/content/docs/nb/zen.mdx b/packages/web/src/content/docs/nb/zen.mdx index f8dac0f391..71dd0e9eaf 100644 --- a/packages/web/src/content/docs/nb/zen.mdx +++ b/packages/web/src/content/docs/nb/zen.mdx @@ -14,7 +14,7 @@ OpenCode Zen er for øyeblikket i beta. ::: Zen fungerer som alle andre leverandører i OpenCode. Du logger på OpenCode Zen og får -din API nøkkel. Den er **helt valgfri** og du trenger ikke bruke den for å bruke den +din API nøkkel. Den er **helt valgfri** og du trenger ikke bruke den for å bruke OpenCode. --- @@ -64,6 +64,8 @@ Du kan også få tilgang til modellene våre gjennom følgende API-endepunkter. | Modell | Modell ID | Endepunkt | AI SDK Pakke | | ------------------ | ------------------ | -------------------------------------------------- | --------------------------- | +| GPT 5.4 | gpt-5.4 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| GPT 5.3 Codex | gpt-5.3-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.2 | gpt-5.2 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.2 Codex | gpt-5.2-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.1 | gpt-5.1 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | @@ -73,22 +75,24 @@ Du kan også få tilgang til modellene våre gjennom følgende API-endepunkter. | GPT 5 | gpt-5 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5 Codex | gpt-5-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5 Nano | gpt-5-nano | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| Claude Opus 4.6 | claude-opus-4-6 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Opus 4.5 | claude-opus-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Opus 4.1 | claude-opus-4-1 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Sonnet 4.6 | claude-sonnet-4-6 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Sonnet 4.5 | claude-sonnet-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Sonnet 4 | claude-sonnet-4 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Haiku 4.5 | claude-haiku-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Haiku 3.5 | claude-3-5-haiku | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| Claude Opus 4.6 | claude-opus-4-6 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| Claude Opus 4.5 | claude-opus-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| Claude Opus 4.1 | claude-opus-4-1 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Gemini 3.1 Pro | gemini-3.1-pro | `https://opencode.ai/zen/v1/models/gemini-3.1-pro` | `@ai-sdk/google` | | Gemini 3 Pro | gemini-3-pro | `https://opencode.ai/zen/v1/models/gemini-3-pro` | `@ai-sdk/google` | | Gemini 3 Flash | gemini-3-flash | `https://opencode.ai/zen/v1/models/gemini-3-flash` | `@ai-sdk/google` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.5 Free | minimax-m2.5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.1 | minimax-m2.1 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.1 Free | minimax-m2.1-free | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| GLM 5 | glm-5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | GLM 4.7 | glm-4.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM 4.7 Free | glm-4.7-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | GLM 4.6 | glm-4.6 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 Free | kimi-k2.5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2 Thinking | kimi-k2-thinking | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2 | kimi-k2 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Qwen3 Coder 480B | qwen3-coder | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -117,29 +121,35 @@ Vi støtter en pay-as-you-go-modell. Nedenfor er prisene **per 1 million tokens* | Modell | Inndata | Utdata | Bufret lesing | Bufret skriving | | --------------------------------- | ------- | ------ | ------------- | --------------- | | Big Pickle | Gratis | Gratis | Gratis | - | -| MiniMax M2.1 Free | Gratis | Gratis | Gratis | - | +| MiniMax M2.5 Free | Gratis | Gratis | Gratis | - | +| MiniMax M2.5 | $0,30 | $1,20 | $0,06 | $0,375 | | MiniMax M2.1 | $0,30 | $1,20 | $0,10 | - | -| GLM 4.7 Free | Gratis | Gratis | Gratis | - | +| GLM 5 | $1,00 | $3,20 | $0,20 | - | | GLM 4.7 | $0,60 | $2,20 | $0,10 | - | | GLM 4.6 | $0,60 | $2,20 | $0,10 | - | -| Kimi K2.5 Free | Gratis | Gratis | Gratis | - | | Kimi K2.5 | $0,60 | $3,00 | $0,08 | - | | Kimi K2 Thinking | $0,40 | $2,50 | - | - | | Kimi K2 | $0,40 | $2,50 | - | - | | Qwen3 Coder 480B | $0,45 | $1,50 | - | - | +| Claude Opus 4.6 (≤ 200K tokens) | $5,00 | $25,00 | $0,50 | $6,25 | +| Claude Opus 4.6 (> 200K tokens) | $10,00 | $37,50 | $1,00 | $12,50 | +| Claude Opus 4.5 | $5,00 | $25,00 | $0,50 | $6,25 | +| Claude Opus 4.1 | $15,00 | $75,00 | $1,50 | $18,75 | +| Claude Sonnet 4.6 (≤ 200K tokens) | $3,00 | $15,00 | $0,30 | $3,75 | +| Claude Sonnet 4.6 (> 200K tokens) | $6,00 | $22,50 | $0,60 | $7,50 | | Claude Sonnet 4.5 (≤ 200K tokens) | $3,00 | $15,00 | $0,30 | $3,75 | | Claude Sonnet 4.5 (> 200K tokens) | $6,00 | $22,50 | $0,60 | $7,50 | | Claude Sonnet 4 (≤ 200K tokens) | $3,00 | $15,00 | $0,30 | $3,75 | | Claude Sonnet 4 (> 200K tokens) | $6,00 | $22,50 | $0,60 | $7,50 | | Claude Haiku 4.5 | $1,00 | $5,00 | $0,10 | $1,25 | | Claude Haiku 3.5 | $0,80 | $4,00 | $0,08 | $1,00 | -| Claude Opus 4.6 (≤ 200K tokens) | $5,00 | $25,00 | $0,50 | $6,25 | -| Claude Opus 4.6 (> 200K tokens) | $10,00 | $37,50 | $1,00 | $12,50 | -| Claude Opus 4.5 | $5,00 | $25,00 | $0,50 | $6,25 | -| Claude Opus 4.1 | $15,00 | $75,00 | $1,50 | $18,75 | +| Gemini 3.1 Pro (≤ 200K tokens) | $2,00 | $12,00 | $0,20 | - | +| Gemini 3.1 Pro (> 200K tokens) | $4,00 | $18,00 | $0,40 | - | | Gemini 3 Pro (≤ 200K tokens) | $2,00 | $12,00 | $0,20 | - | | Gemini 3 Pro (> 200K tokens) | $4,00 | $18,00 | $0,40 | - | | Gemini 3 Flash | $0,50 | $3,00 | $0,05 | - | +| GPT 5.4 | $2,50 | $15,00 | $0,25 | - | +| GPT 5.3 Codex | $1,75 | $14,00 | $0,175 | - | | GPT 5.2 | $1,75 | $14,00 | $0,175 | - | | GPT 5.2 Codex | $1,75 | $14,00 | $0,175 | - | | GPT 5.1 | $1,07 | $8,50 | $0,107 | - | @@ -158,9 +168,7 @@ Kredittkortgebyrer overføres til kostpris (4,4 % + $0,30 per transaksjon); vi b De gratis modellene: -- GLM 4.7 Free er tilgjengelig på OpenCode i en begrenset periode. Teamet bruker denne tiden til å samle tilbakemeldinger og forbedre modellen. -- Kimi K2.5 Free er tilgjengelig på OpenCode i en begrenset periode. Teamet bruker denne tiden til å samle tilbakemeldinger og forbedre modellen. -- MiniMax M2.1 Free er tilgjengelig på OpenCode i en begrenset periode. Teamet bruker denne tiden til å samle tilbakemeldinger og forbedre modellen. +- MiniMax M2.5 Free er tilgjengelig på OpenCode i en begrenset periode. Teamet bruker denne tiden til å samle tilbakemeldinger og forbedre modellen. - Big Pickle er en stealth-modell som er gratis på OpenCode i en begrenset periode. Teamet bruker denne tiden til å samle tilbakemeldinger og forbedre modellen. <a href={email}>Kontakt oss</a> hvis du har spørsmål. @@ -186,14 +194,25 @@ belaster deg mer enn $20 hvis saldoen din går under $5. --- +### Utfasede modeller + +| Modell | Utfasingdato | +| ---------------- | ------------- | +| Qwen3 Coder 480B | 6. feb. 2026 | +| Kimi K2 Thinking | 6. mars 2026 | +| Kimi K2 | 6. mars 2026 | +| MiniMax M2.1 | 15. mars 2026 | +| GLM 4.7 | 15. mars 2026 | +| GLM 4.6 | 15. mars 2026 | + +--- + ## Personvern Alle våre modeller er hostet i USA. Leverandørene våre følger retningslinjer om ingen datalagring og bruker ikke dataene dine til modellopplæring, med følgende unntak: - Big Pickle: I løpet av gratisperioden kan innsamlede data brukes til å forbedre modellen. -- GLM 4.7 Free: I løpet av gratisperioden kan innsamlede data brukes til å forbedre modellen. -- Kimi K2.5 Free: I løpet av gratisperioden kan innsamlede data brukes til å forbedre modellen. -- MiniMax M2.1 Free: I løpet av gratisperioden kan innsamlede data brukes til å forbedre modellen. +- MiniMax M2.5 Free: I løpet av gratisperioden kan innsamlede data brukes til å forbedre modellen. - OpenAI APIer: Forespørsler oppbevares i 30 dager i samsvar med [OpenAIs datapolicyer](https://platform.openai.com/docs/guides/your-data). - Anthropic APIer: Forespørsler oppbevares i 30 dager i samsvar med [Anthropics datapolicyer](https://docs.anthropic.com/en/docs/claude-code/data-usage). @@ -251,4 +270,4 @@ Vi opprettet OpenCode Zen for å: 1. **Benchmark** de beste modellene/leverandørene for kodingsagenter. 2. Ha tilgang til alternativene for **høyeste kvalitet** og ikke nedgrader ytelsen eller rute trafikk til billigere leverandører. 3. Gi videre eventuelle **prisfall** ved å selge til kostpris; så det eneste påslaget er å dekke behandlingsgebyrene våre. -4. Ha **ingen låsing** ved å la deg bruke den med en hvilken som helst annen kodeagent. Og la deg alltid bruke en hvilken som helst annen leverandør med opencode også. +4. Ha **ingen låsing** ved å la deg bruke den med en hvilken som helst annen kodeagent. Og la deg alltid bruke en hvilken som helst annen leverandør med OpenCode også. diff --git a/packages/web/src/content/docs/pl/cli.mdx b/packages/web/src/content/docs/pl/cli.mdx index 3521859018..82ff7f52b2 100644 --- a/packages/web/src/content/docs/pl/cli.mdx +++ b/packages/web/src/content/docs/pl/cli.mdx @@ -558,6 +558,7 @@ OpenCode można skonfigurować za pomocą zmiennych środowiskowych. | `OPENCODE_AUTO_SHARE` | boolean | Automatycznie udostępniaj sesje | | `OPENCODE_GIT_BASH_PATH` | string | Ścieżka do pliku wykonywalnego Git Bash w systemie Windows | | `OPENCODE_CONFIG` | string | Ścieżka do pliku konfiguracyjnego | +| `OPENCODE_TUI_CONFIG` | string | Ścieżka do pliku konfiguracyjnego TUI | | `OPENCODE_CONFIG_DIR` | string | Ścieżka do katalogu konfiguracyjnego | | `OPENCODE_CONFIG_CONTENT` | string | Treść konfiguracji JSON (inline) | | `OPENCODE_DISABLE_AUTOUPDATE` | boolean | Wyłącz automatyczne sprawdzanie aktualizacji | diff --git a/packages/web/src/content/docs/pl/config.mdx b/packages/web/src/content/docs/pl/config.mdx index cde2e312ea..a6a6fb156d 100644 --- a/packages/web/src/content/docs/pl/config.mdx +++ b/packages/web/src/content/docs/pl/config.mdx @@ -94,7 +94,9 @@ Możesz włączyć serwer w konfiguracji projektu: ### Globalna -Umieść swoją globalną konfigurację OpenCode w `~/.config/opencode/opencode.json`. Użyj jej do ustawień ogólnych dla użytkownika, takich jak motywy, domyślny dostawca lub skróty klawiszowe. +Umieść swoją globalną konfigurację OpenCode w `~/.config/opencode/opencode.json`. Użyj jej do ustawień ogólnych dla użytkownika, takich jak dostawcy, modele i uprawnienia. + +Dla ustawień specyficznych dla TUI, użyj `~/.config/opencode/tui.json`. Konfiguracja globalna ma pierwszeństwo przed konfiguracją zdalną. @@ -104,8 +106,10 @@ Konfiguracja globalna ma pierwszeństwo przed konfiguracją zdalną. Dodaj `opencode.json` w katalogu głównym projektu. Konfiguracja projektu ma najwyższy priorytet wśród plików konfiguracyjnych — nadpisuje konfiguracje globalne i zdalne. +Dla ustawień TUI specyficznych dla projektu, dodaj plik `tui.json` obok niego. + :::tip -Dodaj ten plik do kontroli wersji, aby udostępniać konfigurację zespołowi. +Umieść konfigurację specyficzną dla projektu w katalogu głównym projektu. ::: Kiedy OpenCode się uruchamia, szuka pliku konfiguracyjnego w katalogu głównym repozytorium Git. @@ -150,28 +154,24 @@ Twój edytor powinien zapewniać walidację i autouzupełnianie na podstawie teg ### TUI -Możesz skonfigurować zachowanie TUI za pomocą opcji `tui`. +Użyj dedykowanego pliku `tui.json` (lub `tui.jsonc`) dla ustawień specyficznych dla TUI. -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", - "tui": { - "scroll_speed": 3, - "scroll_acceleration": { - "enabled": true - }, - "diff_style": "auto" - } + "$schema": "https://opencode.ai/tui.json", + "scroll_speed": 3, + "scroll_acceleration": { + "enabled": true + }, + "diff_style": "auto" } ``` -Dostępne opcje: +Użyj `OPENCODE_TUI_CONFIG`, aby wskazać niestandardowy plik konfiguracyjny TUI. -- `scroll_acceleration.enabled` - Włącz przyspieszenie przewijania na gładzikach macOS. **Ma pierwszeństwo przed `scroll_speed`.** -- `scroll_speed` - Niestandardowy mnożnik szybkości przewijania (domyślnie: `3`, minimalnie: `1`). Ignorowane, jeśli `scroll_acceleration.enabled` ustawiono na `true`. -- `diff_style` – Sterowanie renderowaniem różnic. `"auto"` przełącza się w zależności od szerokości terminala, `"stacked"` zawsze wymusza pojedynczą kolumnę. +Przestarzałe klucze `theme`, `keybinds` i `tui` w `opencode.json` są wycofywane i automatycznie migrowane, gdy to możliwe. -[Dowiedz się więcej o korzystaniu z TUI](/docs/tui). +[Dowiedz się więcej o konfiguracji TUI tutaj](/docs/tui#configure). --- @@ -297,16 +297,16 @@ Token okaziciela (`AWS_BEARER_TOKEN_BEDROCK` lub `/connect`) ma pierwszeństwo p ### Theme (Motyw) -Skonfiguruj motyw interfejsu OpenCode za pomocą opcji `theme`. +Ustaw motyw interfejsu użytkownika w `tui.json`. -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", - "theme": "" + "$schema": "https://opencode.ai/tui.json", + "theme": "tokyonight" } ``` -[Dowiedz się więcej o motywach](/docs/themes). +[Dowiedz się więcej tutaj](/docs/themes). --- @@ -402,16 +402,16 @@ Możesz także definiować polecenia przy użyciu plików Markdown w `~/.config/ ### Keybinds (Skróty klawiszowe) -Możesz dostosować skróty klawiszowe za pomocą opcji `keybinds`. +Dostosuj skróty klawiszowe w `tui.json`. -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "keybinds": {} } ``` -[Dowiedz się więcej o skrótach klawiszowych](/docs/keybinds). +[Dowiedz się więcej tutaj](/docs/keybinds). --- diff --git a/packages/web/src/content/docs/pl/custom-tools.mdx b/packages/web/src/content/docs/pl/custom-tools.mdx index eaf403d2de..7a38512c18 100644 --- a/packages/web/src/content/docs/pl/custom-tools.mdx +++ b/packages/web/src/content/docs/pl/custom-tools.mdx @@ -3,7 +3,7 @@ title: Narzędzia specjalistyczne description: Twórz narzędzi, które LLM mogą być uruchamiane w otwartym kodzie. --- -Narzędzia stosowane do funkcji, z których LLM może korzystać podczas rozmów. Współpracują z [wbudowanymi narzędziami] (./tools) opencode, wtyczka jak `read`, `write` i `bash`. +Narzędzia specjalistyczne to funkcje, które tworzysz i które LLM może wywoływać podczas rozmów. Współpracują one z [wbudowanymi narzędziami](/docs/tools) opencode, takimi jak `read`, `write` i `bash`. --- @@ -75,7 +75,33 @@ export const multiply = tool({ }) ``` -Tworzy do dwóch narzędzi: `math_add` i `math_multiply`. +Tworzy to dwa narzędzia: `math_add` i `math_multiply`. + +--- + +#### Kolizje nazw z wbudowanymi narzędziami + +Niestandardowe narzędzia są identyfikowane według nazwy narzędzia. Jeśli niestandardowe narzędzie używa tej samej nazwy co wbudowane narzędzie, niestandardowe narzędzie ma pierwszeństwo. + +Na przykład ten plik zastępuje wbudowane narzędzie `bash`: + +```ts title=".opencode/tools/bash.ts" +import { tool } from "@opencode-ai/plugin" + +export default tool({ + description: "Restricted bash wrapper", + args: { + command: tool.schema.string(), + }, + async execute(args) { + return `blocked: ${args.command}` + }, +}) +``` + +:::note +Preferuj unikalne nazwy, chyba że celowo chcesz zastąpić wbudowane narzędzie. Jeśli chcesz wyłączyć wbudowane narzędzie, ale go nie nadpisywać, użyj [uprawnień](/docs/permissions). +::: --- @@ -135,9 +161,9 @@ export default tool({ ### Napisz narzędzie w Pythonie -Napisz swoje narzędzie w języku angielskim. Oto przykład dodania dwóch liczb przy użyciu języka Python. +Możesz pisać swoje narzędzia w dowolnym języku. Oto przykład dodania dwóch liczb przy użyciu języka Python. -Fragment utworu jako skrypt w języku Python: +Najpierw utwórz narzędzie jako skrypt w języku Python: ```python title=".opencode/tools/add.py" import sys @@ -147,7 +173,7 @@ b = int(sys.argv[2]) print(a + b) ``` -Utwór instrumentalny, który jest ukryty: +Następnie utwórz definicję narzędzia, która go wywołuje: ```ts title=".opencode/tools/python-add.ts" {10} import { tool } from "@opencode-ai/plugin" @@ -167,4 +193,4 @@ export default tool({ }) ``` -Tutaj istnieje narzędzie [`Bun.$`](https://bun.com/docs/runtime/shell) uruchamiające skryptu w języku Python. +Tutaj używamy narzędzia [`Bun.$`](https://bun.com/docs/runtime/shell) do uruchomienia skryptu w języku Python. diff --git a/packages/web/src/content/docs/pl/ecosystem.mdx b/packages/web/src/content/docs/pl/ecosystem.mdx index 7c75340c57..9dc4179b75 100644 --- a/packages/web/src/content/docs/pl/ecosystem.mdx +++ b/packages/web/src/content/docs/pl/ecosystem.mdx @@ -1,76 +1,78 @@ --- title: Ekosystem -description: Projekty i integracje zbudowane w opencode. +description: Projekty i integracje zbudowane przy użyciu OpenCode. --- -Zgromadzenie stowarzyszenia organizacji na opencode. +Zbiór projektów społeczności zbudowanych na OpenCode. :::note -Chcesz zadać swój projekt badawczy z opencode do tej listy? Prześlij PR. +Chcesz dodać swój projekt związany z OpenCode do tej listy? Prześlij PR. ::: -Możesz także sprawdzić [awesome-opencode](https://github.com/awesome-opencode/awesome-opencode) i [opencode.cafe](https://opencode.cafe), grupę skupiającą ekosystem i społeczność. +Możesz również sprawdzić [awesome-opencode](https://github.com/awesome-opencode/awesome-opencode) oraz [opencode.cafe](https://opencode.cafe), społeczność agregującą ekosystem i społeczność. --- -## Wtyki +## Wtyczki -| Imię | Opis | -| --------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | -| [opencode-daytona](https://github.com/jamesmurdza/daytona/blob/main/guides/typescript/opencode/README.md) | Automatycznie uruchamiaj sesje opencode w izolowanych piaskownicach Daytona z synchronizacją git i podglądami na żywo | -| [opencode-helicone-session](https://github.com/H2Shami/opencode-helicone-session) | Automatycznie wstawiaj nagłówki sesji Helicone w celu grupowania urządzeń | -| [opencode-type-inject](https://github.com/nick-vi/opencode-type-inject) | Automatyczne wstrzykiwacze TypeScript/Svelte do odczytania plików za pomocą narzędzi wyszukiwania | -| [opencode-openai-codex-auth](https://github.com/numman-ali/opencode-openai-codex-auth) | wykorzystać do wykorzystania ChatGPT Plus/Pro zamiast kredytu API | -| [opencode-gemini-auth](https://github.com/jenslys/opencode-gemini-auth) | korzystać z planu Gemini zamiast rozliczeń API | -| [opencode-antigravity-auth](https://github.com/NoeFabris/opencode-antigravity-auth) | Wykorzystanie z bezpłatnych modeli Antigravity zamiast rozliczeń API | -| [opencode-devcontainers](https://github.com/athal7/opencode-devcontainers) | Izolacja wielooddziałowych kontenerów deweloperskich z płytkami klonami i automatycznie przypisywanymi portami | -| [opencode-google-antigravity-auth](https://github.com/shekohex/opencode-google-antigravity-auth) | Wtyczka Google Antigravity OAuth z obsługą obsługi Google i bardziej niezawodną obsługą API | -| [opencode-dynamic-context-pruning](https://github.com/Tarquinen/opencode-dynamic-context-pruning) | Zoptymalizuj wykorzystanie tokena, usuwając przestarzałe dane wyjściowe narzędzia | -| [opencode-websearch-cited](https://github.com/ghoulr/opencode-websearch-cited.git) | Dodaj natywną obsługę wyszukiwania w sieci dla dostawców w stylu opartym na Google | -| [opencode-pty](https://github.com/shekohex/opencode-pty.git) | Uruchomienie agenta AI uruchamiającego się w tle w PTY i wytwarzanie ich interaktywnych danych. | -| [opencode-shell-strategy](https://github.com/JRedeker/opencode-shell-strategy) | Instrukcje dla nieinteraktywnych obowiązków - zaniechanie zawieszenia operacji zależnych od TTY | -| [opencode-wakatime](https://github.com/angristan/opencode-wakatime) | Śledź udostępnić opencode za pomocą Wakatime | -| [opencode-md-table-formatter](https://github.com/franlol/opencode-md-table-formatter/tree/main) | Oczyść tabelę przecenioną przez LLM | -| [opencode-morph-fast-apply](https://github.com/JRedeker/opencode-morph-fast-apply) | 10x szybsza edycja kodu dzięki Morph Fast Apply API i znacznikom leniwej edycji | -| [oh-my-opencode](https://github.com/code-yeongyu/oh-my-opencode) | Agencje odpowiedzialne w tle, gotowe narzędzia LSP/AST/MCP, wyselekcjonowani agenci, kompatybilni z Claude Code | -| [opencode-notificator](https://github.com/panta82/opencode-notificator) | Powiadomienia na pulpicie i alerty dźwiękowe dotyczące sesji opencode | -| [opencode-notifier](https://github.com/mohak34/opencode-notifier) | Powiadomienia na pulpicie i alerty dźwiękowe dotyczące uprawnień, wyników i zdarzeń o błędach | -| [opencode-zellij-namer](https://github.com/24601/opencode-zellij-namer) | Automatyczne nazewnictwo sesji Zellij oparte na sztucznej inteligencji w oparciu o kontekst opencode | -| [opencode-skillful](https://github.com/zenobi-us/opencode-skillful) | Zezwalaj agentom opencode na leniwe ładowanie podpowiedzi na podstawie odkrywania możliwości i wstrzykiwania | -| [opencode-supermemory](https://github.com/supermemoryai/opencode-supermemory) | Trwała pamięć w sesjach przy użyciu Supermemory | -| [@plannotator/opencode](https://github.com/backnotprop/plannotator/tree/main/apps/opencode-plugin) | Interaktywny przegląd planu z adnotacją wizualną i użytkową prywatną/offline | -| [@openspoon/subtask2](https://github.com/spoons-and-mirrors/subtask2) | Rozszerzony opencode/polecenia do połączenia sieciowego ze szczegółową kontrolą bezpieczeństwa | -| [opencode-scheduler](https://github.com/different-ai/opencode-scheduler) | Zaplanuj powtarzające się zadania, używając launchd (Mac) lub systemd (Linux) ze składaną cron | -| [micode](https://github.com/vtemian/micode) | Ustrukturyzowana burza mózgów → Plan → Wdrożenie wyjścia z ciągłością sesji | -| [octto](https://github.com/vtemian/octto) | Interaktywny interfejs do burzy mózgów AI z formularzami kontrolnymi wielu pytań | -| [opencode-background-agents](https://github.com/kdcokenny/opencode-background-agents) | Agencje krytyczne w tle w stylu Claude Code z delegowaniem asynchronicznym i trwałością kontekstu | -| [opencode-notify](https://github.com/kdcokenny/opencode-notify) | Natywne uruchomienie systemu dla opencode – wiesz, kiedy zadania zostaną zakończone | -| [opencode-workspace](https://github.com/kdcokenny/opencode-workspace) | Lista wiązek orkiestracji wieloagentowej – 16 dostępna, jedna instalacja | -| [opencode-worktree](https://github.com/kdcokenny/opencode-worktree) | Drzewa robocze Git o zerowym tarciu dla opencode | +| Nazwa | Opis | +| -------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | +| [opencode-daytona](https://github.com/daytonaio/daytona/tree/main/libs/opencode-plugin) | Automatyczne uruchamianie sesji OpenCode w izolowanych piaskownicach Daytona z synchronizacją git i podglądem na żywo | +| [opencode-helicone-session](https://github.com/H2Shami/opencode-helicone-session) | Automatyczne wstrzykiwanie nagłówków sesji Helicone do grupowania żądań | +| [opencode-type-inject](https://github.com/nick-vi/opencode-type-inject) | Automatyczne wstrzykiwanie typów TypeScript/Svelte do odczytów plików za pomocą narzędzi wyszukiwania | +| [opencode-openai-codex-auth](https://github.com/numman-ali/opencode-openai-codex-auth) | Użyj subskrypcji ChatGPT Plus/Pro zamiast kredytów API | +| [opencode-gemini-auth](https://github.com/jenslys/opencode-gemini-auth) | Użyj istniejącego planu Gemini zamiast płatności za API | +| [opencode-antigravity-auth](https://github.com/NoeFabris/opencode-antigravity-auth) | Użyj darmowych modeli Antigravity zamiast płatności za API | +| [opencode-devcontainers](https://github.com/athal7/opencode-devcontainers) | Izolacja kontenerów deweloperskich dla wielu gałęzi z płytkim klonowaniem i automatycznie przypisywanymi portami | +| [opencode-google-antigravity-auth](https://github.com/shekohex/opencode-google-antigravity-auth) | Wtyczka Google Antigravity OAuth ze wsparciem dla wyszukiwarki Google i bardziej niezawodną obsługą API | +| [opencode-dynamic-context-pruning](https://github.com/Tarquinen/opencode-dynamic-context-pruning) | Optymalizacja zużycia tokenów poprzez usuwanie przestarzałych wyników narzędzi | +| [opencode-vibeguard](https://github.com/inkdust2021/opencode-vibeguard) | Redagowanie sekretów/danych osobowych do placeholderów w stylu VibeGuard przed wywołaniem LLM; przywracanie lokalnie | +| [opencode-websearch-cited](https://github.com/ghoulr/opencode-websearch-cited.git) | Dodaj natywną obsługę wyszukiwania w sieci dla wspieranych dostawców w stylu Google grounded | +| [opencode-pty](https://github.com/shekohex/opencode-pty.git) | Umożliwia agentom AI uruchamianie procesów w tle w PTY i wysyłanie do nich interaktywnych danych wejściowych. | +| [opencode-shell-strategy](https://github.com/JRedeker/opencode-shell-strategy) | Instrukcje dla nieinteraktywnych poleceń powłoki - zapobiega zawieszeniom operacji zależnych od TTY | +| [opencode-wakatime](https://github.com/angristan/opencode-wakatime) | Śledź użycie OpenCode za pomocą Wakatime | +| [opencode-md-table-formatter](https://github.com/franlol/opencode-md-table-formatter/tree/main) | Oczyść tabele markdown generowane przez LLM | +| [opencode-morph-fast-apply](https://github.com/JRedeker/opencode-morph-fast-apply) | 10x szybsza edycja kodu dzięki API Morph Fast Apply i leniwym znacznikom edycji | +| [oh-my-opencode](https://github.com/code-yeongyu/oh-my-opencode) | Agenci w tle, wbudowane narzędzia LSP/AST/MCP, wyselekcjonowani agenci, kompatybilność z Claude Code | +| [opencode-notificator](https://github.com/panta82/opencode-notificator) | Powiadomienia na pulpicie i alerty dźwiękowe dla sesji OpenCode | +| [opencode-notifier](https://github.com/mohak34/opencode-notifier) | Powiadomienia na pulpicie i alerty dźwiękowe dla uprawnień, zakończeń zadań i błędów | +| [opencode-zellij-namer](https://github.com/24601/opencode-zellij-namer) | Automatyczne nazywanie sesji Zellij oparte na AI w oparciu o kontekst OpenCode | +| [opencode-skillful](https://github.com/zenobi-us/opencode-skillful) | Pozwól agentom OpenCode na leniwe ładowanie promptów na żądanie z odkrywaniem umiejętności i wstrzykiwaniem | +| [opencode-supermemory](https://github.com/supermemoryai/opencode-supermemory) | Trwała pamięć między sesjami przy użyciu Supermemory | +| [@plannotator/opencode](https://github.com/backnotprop/plannotator/tree/main/apps/opencode-plugin) | Interaktywny przegląd planów z wizualnymi adnotacjami i prywatnym/offline udostępnianiem | +| [@openspoon/subtask2](https://github.com/spoons-and-mirrors/subtask2) | Rozszerz komendy /commands OpenCode w potężny system orkiestracji ze szczegółową kontrolą przepływu | +| [opencode-scheduler](https://github.com/different-ai/opencode-scheduler) | Planuj cykliczne zadania używając launchd (Mac) lub systemd (Linux) ze składnią cron | +| [micode](https://github.com/vtemian/micode) | Ustrukturyzowany przepływ pracy Burza mózgów → Plan → Implementacja z ciągłością sesji | +| [octto](https://github.com/vtemian/octto) | Interaktywny interfejs przeglądarkowy do burzy mózgów AI z formularzami wielopytaniowymi | +| [opencode-background-agents](https://github.com/kdcokenny/opencode-background-agents) | Agenci w tle w stylu Claude Code z asynchronicznym delegowaniem i trwałością kontekstu | +| [opencode-notify](https://github.com/kdcokenny/opencode-notify) | Natywne powiadomienia systemowe dla OpenCode – wiedz, kiedy zadania się zakończą | +| [opencode-workspace](https://github.com/kdcokenny/opencode-workspace) | Zestaw orkiestracji wieloagentowej – 16 komponentów, jedna instalacja | +| [opencode-worktree](https://github.com/kdcokenny/opencode-worktree) | Bezproblemowe drzewa robocze git dla OpenCode | +| [opencode-sentry-monitor](https://github.com/stolinski/opencode-sentry-monitor) | Śledź i debuguj swoich agentów AI za pomocą Sentry AI Monitoring | --- -## Projektowanie +## Projekty -| Imię | Opis | -| ------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------- | -| [kimaki](https://github.com/remorses/kimaki) | Bot Discord do kontrolowania sesji opencode, zbudowany na SDK | -| [opencode.nvim](https://github.com/NickvanDyke/opencode.nvim) | Wtyczka Neovim do podpowiedzi, zbudowana w oparciu o API | -| [portal](https://github.com/hosenur/portal) | Interfejs sieciowy do urządzeń mobilnych dla opencode poprzez Tailscale/VPN | -| [opencode plugin template](https://github.com/zenobi-us/opencode-plugin-template/) | Szablon do budowy wtyczek opencode | -| [opencode.nvim](https://github.com/sudo-tee/opencode.nvim) | Frontend Neovim dla opencode - agent kodujący AI oparty na terminalu | -| [ai-sdk-provider-opencode-sdk](https://github.com/ben-vargas/ai-sdk-provider-opencode-sdk) | Stosowanie Vercel AI SDK do użytku z opencode poprzez @opencode-ai/sdk | -| [OpenChamber](https://github.com/btriapitsyn/openchamber) | Aplikacja internetowa/stacjonarna i rozszerzenie VS Code dla opencode | -| [OpenCode-Obsidian](https://github.com/mtymek/opencode-obsidian) | Wtyczka Obsidian osadzająca opencode w interfejsie użytkownika Obsidian | -| [OpenWork](https://github.com/different-ai/openwork) | Alternatywa typu open source dla Claude Cowork, obsługa przez opencode | -| [ocx](https://github.com/kdcokenny/ocx) | Menedżer rozszerzony opencode z przenośnymi, izolowanymi profilami. | -| [CodeNomad](https://github.com/NeuralNomadsAI/CodeNomad) | Aplikacja komputerowa, internetowa, mobilna i zdalna dla opencode | +| Nazwa | Opis | +| ------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------- | +| [kimaki](https://github.com/remorses/kimaki) | Bot Discord do sterowania sesjami OpenCode, zbudowany na SDK | +| [opencode.nvim](https://github.com/NickvanDyke/opencode.nvim) | Wtyczka Neovim dla promptów świadomych edytora, zbudowana na API | +| [portal](https://github.com/hosenur/portal) | Interfejs webowy mobile-first dla OpenCode przez Tailscale/VPN | +| [opencode plugin template](https://github.com/zenobi-us/opencode-plugin-template/) | Szablon do tworzenia wtyczek OpenCode | +| [opencode.nvim](https://github.com/sudo-tee/opencode.nvim) | Frontend Neovim dla OpenCode - terminalowy agent kodujący AI | +| [ai-sdk-provider-opencode-sdk](https://github.com/ben-vargas/ai-sdk-provider-opencode-sdk) | Dostawca Vercel AI SDK do używania OpenCode przez @opencode-ai/sdk | +| [OpenChamber](https://github.com/btriapitsyn/openchamber) | Aplikacja Web / Desktop i rozszerzenie VS Code dla OpenCode | +| [OpenCode-Obsidian](https://github.com/mtymek/opencode-obsidian) | Wtyczka Obsidian osadzająca OpenCode w interfejsie Obsidian | +| [OpenWork](https://github.com/different-ai/openwork) | Otwartoźródłowa alternatywa dla Claude Cowork, napędzana przez OpenCode | +| [ocx](https://github.com/kdcokenny/ocx) | Menedżer rozszerzeń OpenCode z przenośnymi, izolowanymi profilami. | +| [CodeNomad](https://github.com/NeuralNomadsAI/CodeNomad) | Aplikacja kliencka Desktop, Web, Mobile i Remote dla OpenCode | --- -## Agencja +## Agenci -| Imię | Opis | -| ----------------------------------------------------------------- | ------------------------------------------------------------------------- | -| [Agentic](https://github.com/Cluster444/agentic) | Modułowi agencje i polecenia AI do rozwoju strukturalnego | -| [opencode-agents](https://github.com/darrenhinde/opencode-agents) | Konfiguracje, podpowiedzi, agencje i wtyczki usprawniające przepływ pracy | +| Nazwa | Opis | +| ----------------------------------------------------------------- | ------------------------------------------------------------------------ | +| [Agentic](https://github.com/Cluster444/agentic) | Modułowi agenci AI i komendy do strukturalnego rozwoju | +| [opencode-agents](https://github.com/darrenhinde/opencode-agents) | Konfiguracje, prompty, agenci i wtyczki dla ulepszonych przepływów pracy | diff --git a/packages/web/src/content/docs/pl/go.mdx b/packages/web/src/content/docs/pl/go.mdx new file mode 100644 index 0000000000..99547da18c --- /dev/null +++ b/packages/web/src/content/docs/pl/go.mdx @@ -0,0 +1,145 @@ +--- +title: Go +description: Tani abonament na otwarte modele kodowania. +--- + +import config from "../../../../config.mjs" +export const console = config.console +export const email = `mailto:${config.email}` + +OpenCode Go to tania subskrypcja za **10 USD miesięcznie**, która zapewnia niezawodny dostęp do popularnych otwartych modeli kodowania. + +:::note +OpenCode Go jest obecnie w fazie beta. +::: + +Go działa jak każdy inny dostawca w OpenCode. Subskrybujesz OpenCode Go i otrzymujesz swój klucz API. Jest to **całkowicie opcjonalne** i nie musisz z tego korzystać, aby używać OpenCode. + +Jest przeznaczony głównie dla użytkowników międzynarodowych, z modelami hostowanymi w USA, UE i Singapurze dla stabilnego dostępu globalnego. + +--- + +## Tło + +Otwarte modele stały się naprawdę dobre. Osiągają teraz wydajność zbliżoną do modeli komercyjnych w zadaniach związanych z kodowaniem. A ponieważ wielu dostawców może je obsługiwać konkurencyjnie, są zazwyczaj znacznie tańsze. + +Jednak uzyskanie niezawodnego dostępu o niskim opóźnieniu może być trudne. Dostawcy różnią się jakością i dostępnością. + +:::tip +Przetestowaliśmy wybraną grupę modeli i dostawców, którzy dobrze współpracują z OpenCode. +::: + +Aby to naprawić, zrobiliśmy kilka rzeczy: + +1. Przetestowaliśmy wybraną grupę otwartych modeli i rozmawialiśmy z ich zespołami o tym, jak najlepiej je uruchamiać. +2. Następnie współpracowaliśmy z kilkoma dostawcami, aby upewnić się, że są one obsługiwane poprawnie. +3. Na koniec przeprowadziliśmy testy porównawcze kombinacji modelu/dostawcy i stworzyliśmy listę, którą z czystym sumieniem polecamy. + +OpenCode Go daje dostęp do tych modeli za **10 USD miesięcznie**. + +--- + +## Jak to działa + +OpenCode Go działa jak każdy inny dostawca w OpenCode. + +1. Logujesz się do **<a href={console}>OpenCode Zen</a>**, subskrybujesz Go i kopiujesz swój klucz API. +2. Uruchamiasz polecenie `/connect` w TUI, wybierasz `OpenCode Go` i wklejasz swój klucz API. +3. Uruchom `/models` w TUI, aby zobaczyć listę modeli dostępnych przez Go. + +:::note +Tylko jeden członek na obszar roboczy może subskrybować OpenCode Go. +::: + +Obecna lista modeli obejmuje: + +- **GLM-5** +- **Kimi K2.5** +- **MiniMax M2.5** + +Lista modeli może ulec zmianie w miarę testowania i dodawania nowych. + +--- + +## Limity użycia + +OpenCode Go obejmuje następujące limity: + +- **Limit 5-godzinny** — zużycie o wartości 12 USD +- **Limit tygodniowy** — zużycie o wartości 30 USD +- **Limit miesięczny** — zużycie o wartości 60 USD + +Limity są definiowane w wartości dolarowej. Oznacza to, że rzeczywista liczba żądań zależy od używanego modelu. Tańsze modele, takie jak MiniMax M2.5, pozwalają na więcej żądań, podczas gdy droższe modele, takie jak GLM-5, na mniej. + +Poniższa tabela przedstawia szacunkową liczbę żądań w oparciu o typowe wzorce użytkowania Go: + +| | GLM-5 | Kimi K2.5 | MiniMax M2.5 | +| ------------------- | ----- | --------- | ------------ | +| żądania na 5 godzin | 1 150 | 1 850 | 30 000 | +| żądania na tydzień | 2 880 | 4 630 | 75 000 | +| żądania na miesiąc | 5 750 | 9 250 | 150 000 | + +Szacunki opierają się na zaobserwowanych średnich wzorcach żądań: + +- GLM-5 — 700 wejściowych, 52 000 zbuforowanych, 150 wyjściowych tokenów na żądanie +- Kimi K2.5 — 870 wejściowych, 55 000 zbuforowanych, 200 wyjściowych tokenów na żądanie +- MiniMax M2.5 — 300 wejściowych, 55 000 zbuforowanych, 125 wyjściowych tokenów na żądanie + +Możesz śledzić swoje bieżące zużycie w **<a href={console}>konsoli</a>**. + +:::tip +Jeśli osiągniesz limit użycia, możesz kontynuować korzystanie z darmowych modeli. +::: + +Limity użycia mogą ulec zmianie, gdy będziemy uczyć się na podstawie wczesnego użytkowania i opinii. + +--- + +### Cennik + +OpenCode Go to plan subskrypcji za **10 USD miesięcznie**. Poniżej znajdują się ceny **za 1 mln tokenów**. + +| Model | Wejście | Wyjście | Odczyt cache | +| ------------ | ------- | ------- | ------------ | +| GLM-5 | 1,00 $ | 3,20 $ | 0,20 $ | +| Kimi K2.5 | 0,60 $ | 3,00 $ | 0,10 $ | +| MiniMax M2.5 | 0,30 $ | 1,20 $ | 0,03 $ | + +--- + +### Użycie poza limitami + +Jeśli posiadasz również środki na swoim saldzie Zen, możesz włączyć opcję **Use balance** (Użyj salda) w konsoli. Po włączeniu, Go przełączy się na twoje saldo Zen po osiągnięciu limitów użycia, zamiast blokować żądania. + +--- + +## Punkty końcowe + +Możesz również uzyskać dostęp do modeli Go poprzez następujące punkty końcowe API. + +| Model | Identyfikator modelu | Endpoint | Pakiet AI SDK | +| ------------ | -------------------- | ------------------------------------------------ | --------------------------- | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | + +[Identyfikator modelu](/docs/config/#models) w twojej konfiguracji OpenCode używa formatu `opencode-go/<model-id>`. Na przykład dla Kimi K2.5 użyłbyś `opencode-go/kimi-k2.5` w swojej konfiguracji. + +--- + +## Prywatność + +Plan jest przeznaczony głównie dla użytkowników międzynarodowych, z modelami hostowanymi w USA, UE i Singapurze dla stabilnego dostępu globalnego. + +<a href={email}>Skontaktuj się z nami</a>, jeśli masz jakiekolwiek pytania. + +--- + +## Cele + +Stworzyliśmy OpenCode Go, aby: + +1. Uczynić kodowanie z AI **dostępnym** dla większej liczby osób dzięki taniej subskrypcji. +2. Zapewnić **niezawodny** dostęp do najlepszych otwartych modeli kodowania. +3. Wyselekcjonować modele, które są **przetestowane i sprawdzone** pod kątem użycia z agentami kodującymi. +4. Nie wprowadzać **żadnych blokad (lock-in)**, pozwalając na korzystanie z dowolnego innego dostawcy w OpenCode. diff --git a/packages/web/src/content/docs/pl/keybinds.mdx b/packages/web/src/content/docs/pl/keybinds.mdx index f4995600da..4744ffc783 100644 --- a/packages/web/src/content/docs/pl/keybinds.mdx +++ b/packages/web/src/content/docs/pl/keybinds.mdx @@ -3,11 +3,11 @@ title: Skróty klawiszowe description: Dostosuj swoje skróty klawiszowe. --- -opencode zawiera listę skrótów klawiszowych, które można zastosować poprzez opencode. +OpenCode zawiera listę skrótów klawiszowych, które można dostosować za pomocą `tui.json`. -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "keybinds": { "leader": "ctrl+x", "app_exit": "ctrl+c,ctrl+d,<leader>q", @@ -28,6 +28,7 @@ opencode zawiera listę skrótów klawiszowych, które można zastosować poprze "session_unshare": "none", "session_interrupt": "escape", "session_compact": "<leader>c", + "session_child_first": "<leader>down", "session_child_cycle": "<leader>right", "session_child_cycle_reverse": "<leader>left", "session_parent": "<leader>up", @@ -117,11 +118,11 @@ Nie musisz mieć klawisza wiodącego do skrótów klawiszowych, ale zalecamy to ## Wyłącz powiązanie klawiszy -Możesz podłączyć powiązanie klawiszy, dodając klucz do swojej konfiguracji z wartością „none”. +Możesz wyłączyć skrót klawiszowy, dodając klucz do `tui.json` z wartością "none". -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "keybinds": { "session_compact": "none" } diff --git a/packages/web/src/content/docs/pl/lsp.mdx b/packages/web/src/content/docs/pl/lsp.mdx index 8430bd9ca9..ec2edec430 100644 --- a/packages/web/src/content/docs/pl/lsp.mdx +++ b/packages/web/src/content/docs/pl/lsp.mdx @@ -27,6 +27,7 @@ OpenCode posiada kilka wbudowanych serwerów LSP dla następujących języków: | gopls | .go | Dostępne polecenie `go` | | hls | .hs, .lhs | Dostępne polecenie `haskell-language-server-wrapper` | | jdtls | .java | Zainstalowany `Java SDK (version 21+)` | +| julials | .jl | Zainstalowane `julia` i `LanguageServer.jl` | | kotlin-ls | .kt, .kts | Automatyczna instalacja dla Kotlin | | lua-ls | .lua | Automatyczna instalacja dla Lua | | nixd | .nix | Dostępne polecenie `nixd` | diff --git a/packages/web/src/content/docs/pl/plugins.mdx b/packages/web/src/content/docs/pl/plugins.mdx index e91900ad27..510c8a22e4 100644 --- a/packages/web/src/content/docs/pl/plugins.mdx +++ b/packages/web/src/content/docs/pl/plugins.mdx @@ -9,7 +9,7 @@ Aby znaleźć się z przykładami, przejrzyj [wtyczki](/docs/ecosystem#plugins) --- -## użyj wtyczki +## Użyj wtyczki Istnieją dwa sposoby ładowania wtyczek. @@ -51,7 +51,7 @@ Przeglądaj dostępną wtyczkę w [ekosystemie](/docs/ecosystem#plugins). --- -### Załaduj zamówienie +### Kolejność ładowania Wtyczki są ładowane ze wszystkich źródeł, a wszystkie hooki napisane po kolei. Kolejność ładowania do: @@ -310,7 +310,7 @@ Twoje narzędzie będzie dostępne dla otwartego kodu wraz z narzędziami użytk --- -### Wycięcie lasu +### Logowanie użyj `client.app.log()` zamiast `console.log` do rejestracji strukturalnego: diff --git a/packages/web/src/content/docs/pl/providers.mdx b/packages/web/src/content/docs/pl/providers.mdx index 58f824764e..fa50901103 100644 --- a/packages/web/src/content/docs/pl/providers.mdx +++ b/packages/web/src/content/docs/pl/providers.mdx @@ -57,7 +57,38 @@ przetestowane i zweryfikowane, aby dobrze współpracować z opencode. [Dowiedz Jeśli jesteś nowy, zalecamy rozpoczęcie od OpenCode Zen. ::: -1. Uruchom polecenie `/connect` w TUI, wybierz opencode i przejdź do [opencode.ai/auth](https://opencode.ai/auth). +1. Uruchom polecenie `/connect` w TUI, wybierz `OpenCode Zen` i przejdź do [opencode.ai/auth](https://opencode.ai/zen). + + ```txt + /connect + ``` + +2. Zaloguj się, dodaj szczegóły rozliczeniowe i skopiuj klucz API. + +3. Wklej swój klucz API. + + ```txt + ┌ API key + │ + │ + └ enter + ``` + +4. Uruchom `/models` w TUI, aby zobaczyć listę zalecanych przez nas modeli. + + ```txt + /models + ``` + +Działa jak każdy inny dostawca w opencode i jest całkowicie opcjonalny w użyciu. + +--- + +## OpenCode Go + +OpenCode Go to tani plan subskrypcji, który zapewnia niezawodny dostęp do popularnych modeli open coding dostarczanych przez zespół opencode, które zostały przetestowane i zweryfikowane pod kątem dobrej współpracy z opencode. + +1. Uruchom polecenie `/connect` w TUI, wybierz `OpenCode Go` i przejdź do [opencode.ai/auth](https://opencode.ai/zen). ```txt /connect @@ -470,7 +501,7 @@ Cloudflare AI Gateway umożliwia dostęp do modeli z OpenAI, Anthropic, Workers └ enter ``` - Or set it as an environment variable. + Lub ustaw go jako zmienną środowiskową. ```bash title="~/.bash_profile" export CLOUDFLARE_API_TOKEN=your-api-token @@ -834,11 +865,11 @@ Aby używać Google Vertex AI z opencode: 2. Ustaw wymagane zmienne środowiskowe: - `GOOGLE_CLOUD_PROJECT`: identyfikator Twojego projektu Google Cloud - `VERTEX_LOCATION` (opcjonalnie): region Vertex AI (domyślnie `global`) - - Authentication (choose one): + - Uwierzytelnianie (wybierz jedno): - `GOOGLE_APPLICATION_CREDENTIALS`: Ścieżka do pliku klucza JSON konta usługi - Uwierzytelnij się za pomocą interfejsu CLI gcloud: `gcloud auth application-default login` - Set them while running opencode. + Ustaw je podczas uruchamiania opencode. ```bash GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account.json GOOGLE_CLOUD_PROJECT=your-project-id opencode @@ -1479,6 +1510,39 @@ SAP AI Core zapewnia dostęp do ponad 40 modeli z OpenAI, Anthropic, Google, Ama --- +### STACKIT + +STACKIT AI Model Serving zapewnia w pełni zarządzane suwerenne środowisko hostingu dla modeli AI, koncentrując się na LLM, takich jak Llama, Mistral i Qwen, z maksymalną suwerennością danych na infrastrukturze europejskiej. + +1. Przejdź do [portalu STACKIT](https://portal.stackit.cloud), przejdź do **AI Model Serving**, i utwórz token autoryzacyjny dla swojego projektu. + + :::tip + Musisz posiadać konto klienta STACKIT, konto użytkownika i projekt przed utworzeniem tokenów autoryzacyjnych. + ::: + +2. Uruchom polecenie `/connect` i wyszukaj **STACKIT**. + + ```txt + /connect + ``` + +3. Wprowadź swój token autoryzacyjny STACKIT AI Model Serving. + + ```txt + ┌ API key + │ + │ + └ enter + ``` + +4. Uruchom polecenie `/models`, aby wybrać jeden z dostępnych modeli, np. _Qwen3-VL 235B_ lub _Llama 3.3 70B_. + + ```txt + /models + ``` + +--- + ### OVHcloud AI Endpoints 1. Przejdź do [panelu OVHcloud](https://ovh.com/manager). Przejdź do sekcji `Public Cloud`, `AI & Machine Learning` > `AI Endpoints` i na karcie `API Keys` kliknij **Utwórz nowy klucz API**. diff --git a/packages/web/src/content/docs/pl/sdk.mdx b/packages/web/src/content/docs/pl/sdk.mdx index 3236e38c29..40099713ef 100644 --- a/packages/web/src/content/docs/pl/sdk.mdx +++ b/packages/web/src/content/docs/pl/sdk.mdx @@ -117,6 +117,78 @@ try { --- +## Ustrukturyzowane Dane Wyjściowe + +Możesz zażądać ustrukturyzowanych danych wyjściowych JSON od modelu, określając `format` za pomocą schematu JSON. Model użyje narzędzia `StructuredOutput`, aby zwrócić zweryfikowany kod JSON pasujący do Twojego schematu. + +### Podstawowe użycie + +```typescript +const result = await client.session.prompt({ + path: { id: sessionId }, + body: { + parts: [{ type: "text", text: "Research Anthropic and provide company info" }], + format: { + type: "json_schema", + schema: { + type: "object", + properties: { + company: { type: "string", description: "Company name" }, + founded: { type: "number", description: "Year founded" }, + products: { + type: "array", + items: { type: "string" }, + description: "Main products", + }, + }, + required: ["company", "founded"], + }, + }, + }, +}) + +// Access the structured output +console.log(result.data.info.structured_output) +// { company: "Anthropic", founded: 2021, products: ["Claude", "Claude API"] } +``` + +### Typy formatu wyjściowego + +| Typ | Opis | +| ------------- | ------------------------------------------------------------------------- | +| `text` | Domyślny. Standardowa odpowiedź tekstowa (brak ustrukturyzowanych danych) | +| `json_schema` | Zwraca zweryfikowany JSON pasujący do dostarczonego schematu | + +### Format JSON Schema + +Używając `type: 'json_schema'`, podaj: + +| Pole | Typ | Opis | +| ------------ | --------------- | ------------------------------------------------------------ | +| `type` | `'json_schema'` | Wymagane. Określa tryb schematu JSON | +| `schema` | `object` | Wymagane. Obiekt JSON Schema definiujący strukturę wyjściową | +| `retryCount` | `number` | Opcjonalne. Liczba ponownych prób walidacji (domyślnie: 2) | + +### Obsługa błędów + +Jeśli model nie wygeneruje prawidłowych ustrukturyzowanych danych wyjściowych po wszystkich próbach, odpowiedź będzie zawierać `StructuredOutputError`: + +```typescript +if (result.data.info.error?.name === "StructuredOutputError") { + console.error("Failed to produce structured output:", result.data.info.error.message) + console.error("Attempts:", result.data.info.error.retries) +} +``` + +### Najlepsze praktyki + +1. **Podawaj jasne opisy** we właściwościach schematu, aby pomóc modelowi zrozumieć, jakie dane wyodrębnić +2. **Używaj `required`**, aby określić, które pola muszą być obecne +3. **Zachowaj schematy skoncentrowane** - złożone zagnieżdżone schematy mogą być trudniejsze dla modelu do poprawnego wypełnienia +4. **Ustaw odpowiedni `retryCount`** - zwiększ dla złożonych schematów, zmniejsz dla prostych + +--- + ## API Zestaw SDK udostępnia wszystkie interfejsy API serwera za pośrednictwem klienta bezpiecznego typu. diff --git a/packages/web/src/content/docs/pl/share.mdx b/packages/web/src/content/docs/pl/share.mdx index 463019295a..0389267b59 100644 --- a/packages/web/src/content/docs/pl/share.mdx +++ b/packages/web/src/content/docs/pl/share.mdx @@ -41,7 +41,7 @@ Aby jawnie ustawić tryb ręczny w [pliku konfiguracyjnym] (./config): ```json title="opencode.json" { - "$schema": "https://opncd.ai/config.json", + "$schema": "https://opencode.ai/config.json", "share": "manual" } ``` @@ -54,7 +54,7 @@ Możesz włączyć automatyczne udostępnianie dla wszystkich nowych rozmów, us ```json title="opencode.json" { - "$schema": "https://opncd.ai/config.json", + "$schema": "https://opencode.ai/config.json", "share": "auto" } ``` @@ -69,7 +69,7 @@ Możesz całkowicie wyłączyć udostępnianie, ustawiając opcję `share` na `" ```json title="opencode.json" { - "$schema": "https://opncd.ai/config.json", + "$schema": "https://opencode.ai/config.json", "share": "disabled" } ``` diff --git a/packages/web/src/content/docs/pl/skills.mdx b/packages/web/src/content/docs/pl/skills.mdx index 9262d87e66..8dbb730120 100644 --- a/packages/web/src/content/docs/pl/skills.mdx +++ b/packages/web/src/content/docs/pl/skills.mdx @@ -141,8 +141,8 @@ Kontroluj, do których umiejętności agenci mogą uzyskać dostęp, używając | Permission | Behavior | | ---------- | ------------------------------------------------------ | -| `allow` | Skill loads immediately | -| `deny` | Skill hidden from agent, access rejected | +| `allow` | Umiejętność ładuje się natychmiast | +| `deny` | Umiejętność ukryta przed agentem, dostęp odrzucony | | `ask` | Użytkownik proszony o zatwierdzenie przed załadowaniem | Wzorce obsługują symbole wieloznaczne: `internal-*` odpowiada `internal-docs`, `internal-tools` itd. diff --git a/packages/web/src/content/docs/pl/themes.mdx b/packages/web/src/content/docs/pl/themes.mdx index d4272e2c9b..80a7808351 100644 --- a/packages/web/src/content/docs/pl/themes.mdx +++ b/packages/web/src/content/docs/pl/themes.mdx @@ -53,19 +53,19 @@ Motyw `system` został zaprojektowany tak, aby automatycznie dostosowywał się Motyw systemu przeznaczony jest dla użytkowników, którzy: -- Want opencode to match their terminal's appearance -- Użyj niestandardowych schematów kolorów terminali -- Prefer a consistent look across all terminal applications +- Chcą, aby OpenCode pasował do wyglądu ich terminala +- Używają niestandardowych schematów kolorów terminala +- Preferują spójny wygląd we wszystkich aplikacjach terminalowych --- ## Używanie motywu -Możesz wybrać motyw, wywołując opcję wyboru motywu za pomocą polecenia `/theme`. Możesz też określić to w [config](/docs/config). +Możesz wybrać motyw, wywołując opcję wyboru motywu za pomocą polecenia `/theme`. Możesz też określić to w `tui.json`. -```json title="opencode.json" {3} +```json title="tui.json" {3} { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "theme": "tokyonight" } ``` diff --git a/packages/web/src/content/docs/pl/tui.mdx b/packages/web/src/content/docs/pl/tui.mdx index 6d693eb9e6..2d983cf84b 100644 --- a/packages/web/src/content/docs/pl/tui.mdx +++ b/packages/web/src/content/docs/pl/tui.mdx @@ -355,24 +355,34 @@ Niektórzy edytory potrzebują argumentów wiersza poleceń, aby działać w try ## Skonfiguruj -Możesz dostosować zachowanie TUI za pomocą pliku konfiguracyjnego opencode. +Możesz dostosować zachowanie TUI za pomocą pliku `tui.json` (lub `tui.jsonc`). -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", - "tui": { - "scroll_speed": 3, - "scroll_acceleration": { - "enabled": true - } - } + "$schema": "https://opencode.ai/tui.json", + "theme": "opencode", + "keybinds": { + "leader": "ctrl+x" + }, + "scroll_speed": 3, + "scroll_acceleration": { + "enabled": true + }, + "diff_style": "auto" } ``` +Jest to oddzielny plik od `opencode.json`, który konfiguruje zachowanie serwera/runtime. + ### Opcje -- `scroll_acceleration` — Włącz przyspieszenie przewijania w stylu macOS, aby zapewnić płynne, naturalne przewijanie. Po włączeniu prędkość przewijania wzrasta wraz z szybkimi gestami przewijania i pozostaje precyzyjna w przypadku wolniejszych ruchów. **To ustawienie ma pierwszeństwo przed `scroll_speed` i zastępuje je, gdy jest włączone.** -- `scroll_speed` - Kontroluje szybkość przewijania TUI podczas korzystania z poleceń przewijania (minimum: `1`). Wartość domyślna to `3`. **Uwaga: jest to ignorowane, jeśli `scroll_acceleration.enabled` jest ustawione na `true`.** +- `theme` - Ustawia motyw interfejsu. [Dowiedz się więcej](/docs/themes). +- `keybinds` - Dostosowuje skróty klawiszowe. [Dowiedz się więcej](/docs/keybinds). +- `scroll_acceleration.enabled` — Włącz przyspieszenie przewijania w stylu macOS, aby zapewnić płynne, naturalne przewijanie. Po włączeniu prędkość przewijania wzrasta wraz z szybkimi gestami przewijania i pozostaje precyzyjna w przypadku wolniejszych ruchów. **To ustawienie ma pierwszeństwo przed `scroll_speed` i zastępuje je, gdy jest włączone.** +- `scroll_speed` - Kontroluje szybkość przewijania TUI podczas korzystania z poleceń przewijania (minimum: `0.001`, obsługuje wartości dziesiętne). Wartość domyślna to `3`. **Uwaga: jest to ignorowane, jeśli `scroll_acceleration.enabled` jest ustawione na `true`.** +- `diff_style` - Steruje renderowaniem różnic. `"auto"` dostosowuje się do szerokości terminala, `"stacked"` zawsze pokazuje układ jednokolumnowy. + +Użyj `OPENCODE_TUI_CONFIG`, aby załadować niestandardową ścieżkę konfiguracji TUI. --- diff --git a/packages/web/src/content/docs/pl/zen.mdx b/packages/web/src/content/docs/pl/zen.mdx index 6d5d8c0bd7..ddb7d2ff15 100644 --- a/packages/web/src/content/docs/pl/zen.mdx +++ b/packages/web/src/content/docs/pl/zen.mdx @@ -1,21 +1,21 @@ --- title: Zen -description: Wyselekcjonowana lista modeli dostarczonych przez opencode. +description: Wyselekcjonowana lista modeli dostarczonych przez OpenCode. --- import config from "../../../../config.mjs" export const console = config.console export const email = `mailto:${config.email}` -OpenCode Zen to lista przetestowanych i zweryfikowanych modeli udostępniona przez zespół opencode. +OpenCode Zen to lista przetestowanych i zweryfikowanych modeli udostępniona przez zespół OpenCode. :::note -OpenCode Zen is currently in beta. +OpenCode Zen jest obecnie w wersji beta. ::: -Zen działa jak każdy inny dostawca opencode. Logujesz się do OpenCode Zen i dostajesz -Twój klucz API. Jest **całkowicie opcjonalny** i nie musisz go używać, aby z niego korzystać -opencode. +Zen działa jak każdy inny dostawca w OpenCode. Logujesz się do OpenCode Zen i otrzymujesz +swój klucz API. Jest to **całkowicie opcjonalne** i nie musisz tego używać, aby korzystać z +OpenCode. --- @@ -23,23 +23,23 @@ opencode. Istnieje ogromna liczba modeli, ale tylko kilka z nich działa dobrze jako agenci kodujący. Dodatkowo większość dostawców jest -skonfigurowana bardzo różnie; więc otrzymujesz zupełnie inną wydajność i jakość. +skonfigurowana bardzo różnie, więc otrzymujesz bardzo różną wydajność i jakość. :::tip -Przetestowaliśmy wybraną grupę modeli i dostawców, którzy dobrze współpracują z opencode. +Przetestowaliśmy wybraną grupę modeli i dostawców, którzy dobrze współpracują z OpenCode. ::: -Jeśli więc używasz modelu za pośrednictwem czegoś takiego jak OpenRouter, nigdy nie będzie to możliwe +Jeśli więc używasz modelu za pośrednictwem czegoś takiego jak OpenRouter, nigdy nie możesz być pewien, czy otrzymujesz najlepszą wersję modelu, jaki chcesz. Aby to naprawić, zrobiliśmy kilka rzeczy: -1. Przetestowaliśmy wybraną grupę modeli i rozmawialiśmy z ich zespołami o tym, jak to zrobić - najlepiej je uruchom. +1. Przetestowaliśmy wybraną grupę modeli i rozmawialiśmy z ich zespołami o tym, jak + najlepiej je uruchamiać. 2. Następnie współpracowaliśmy z kilkoma dostawcami, aby upewnić się, że są one obsługiwane - correctly. -3. Na koniec porównaliśmy kombinację modelu/dostawcy i otrzymaliśmy wynik - z listą, którą z przyjemnością polecamy. + poprawnie. +3. Na koniec sprawdziliśmy wydajność kombinacji modelu/dostawcy i stworzyliśmy + listę, którą z czystym sumieniem polecamy. OpenCode Zen to brama AI, która zapewnia dostęp do tych modeli. @@ -47,14 +47,14 @@ OpenCode Zen to brama AI, która zapewnia dostęp do tych modeli. ## Jak to działa -OpenCode Zen działa jak każdy inny dostawca opencode. +OpenCode Zen działa jak każdy inny dostawca w OpenCode. -1. Logujesz się do **<a href={console}>OpenCode Zen</a>**, dodajesz swoje rozliczenia - szczegóły i skopiuj klucz API. +1. Logujesz się do **<a href={console}>OpenCode Zen</a>**, dodajesz dane rozliczeniowe + i kopiujesz swój klucz API. 2. Uruchamiasz polecenie `/connect` w TUI, wybierasz OpenCode Zen i wklejasz klucz API. 3. Uruchom `/models` w TUI, aby zobaczyć listę zalecanych przez nas modeli. -Opłata jest pobierana za każde żądanie i możesz dodać kredyty do swojego konta. +Opłata jest pobierana za każde żądanie i możesz dodać środki do swojego konta. --- @@ -62,8 +62,10 @@ Opłata jest pobierana za każde żądanie i możesz dodać kredyty do swojego k Dostęp do naszych modeli można również uzyskać za pośrednictwem następujących punktów końcowych API. -| Modelka | Identyfikator modelu | Punkt końcowy | Pakiet SDK AI | +| Model | Identyfikator modelu | Punkt końcowy | Pakiet SDK AI | | ------------------ | -------------------- | -------------------------------------------------- | --------------------------- | +| GPT 5.4 | gpt-5.4 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| GPT 5.3 Codex | gpt-5.3-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.2 | gpt-5.2 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.2 Codex | gpt-5.2-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.1 | gpt-5.1 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | @@ -73,30 +75,32 @@ Dostęp do naszych modeli można również uzyskać za pośrednictwem następuj | GPT 5 | gpt-5 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5 Codex | gpt-5-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5 Nano | gpt-5-nano | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| Claude Opus 4.6 | claude-opus-4-6 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Opus 4.5 | claude-opus-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Opus 4.1 | claude-opus-4-1 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Sonnet 4.6 | claude-sonnet-4-6 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Sonnet 4.5 | claude-sonnet-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Sonnet 4 | claude-sonnet-4 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Haiku 4.5 | claude-haiku-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Haiku 3.5 | claude-3-5-haiku | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| Claude Opus 4.6 | claude-opus-4-6 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| Claude Opus 4.5 | claude-opus-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| Claude Opus 4.1 | claude-opus-4-1 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Gemini 3.1 Pro | gemini-3.1-pro | `https://opencode.ai/zen/v1/models/gemini-3.1-pro` | `@ai-sdk/google` | | Gemini 3 Pro | gemini-3-pro | `https://opencode.ai/zen/v1/models/gemini-3-pro` | `@ai-sdk/google` | | Gemini 3 Flash | gemini-3-flash | `https://opencode.ai/zen/v1/models/gemini-3-flash` | `@ai-sdk/google` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.5 Free | minimax-m2.5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.1 | minimax-m2.1 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.1 Free | minimax-m2.1-free | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| GLM 5 | glm-5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | GLM 4.7 | glm-4.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM 4.7 Free | glm-4.7-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | GLM 4.6 | glm-4.6 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 Free | kimi-k2.5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2 Thinking | kimi-k2-thinking | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2 | kimi-k2 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Qwen3 Coder 480B | qwen3-coder | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Big Pickle | big-pickle | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -[Identyfikator modelu](/docs/config/#models) w konfiguracji opencode -używa formatu `opencode/<model-id>`. Na przykład w przypadku Kodeksu GPT 5.2 zrobiłbyś to -użyj `opencode/gpt-5.2-codex` w swojej konfiguracji. +[Identyfikator modelu](/docs/config/#models) w konfiguracji OpenCode +używa formatu `opencode/<model-id>`. Na przykład w przypadku GPT 5.2 Codex użyłbyś +`opencode/gpt-5.2-codex` w swojej konfiguracji. --- @@ -114,32 +118,38 @@ https://opencode.ai/zen/v1/models Wspieramy model pay-as-you-go. Poniżej znajdują się ceny **za 1M tokenów**. -| Modelka | Wejście | Wyjście | Odczyt w pamięci podręcznej | Zapis w pamięci podręcznej | +| Model | Wejście | Wyjście | Odczyt w pamięci podręcznej | Zapis w pamięci podręcznej | | --------------------------------- | ------- | ------- | --------------------------- | -------------------------- | | Big Pickle | Free | Free | Free | - | -| MiniMax M2.1 Free | Free | Free | Free | - | +| MiniMax M2.5 Free | Free | Free | Free | - | +| MiniMax M2.5 | $0.30 | $1.20 | $0.06 | $0.375 | | MiniMax M2.1 | $0.30 | $1.20 | $0.10 | - | -| GLM 4.7 Free | Free | Free | Free | - | +| GLM 5 | $1.00 | $3.20 | $0.20 | - | | GLM 4.7 | $0.60 | $2.20 | $0.10 | - | | GLM 4.6 | $0.60 | $2.20 | $0.10 | - | -| Kimi K2.5 Free | Free | Free | Free | - | -| Kimi K2.5 | $0.60 | $3.00 | $0.08 | - | +| Kimi K2.5 | $0.60 | $3.00 | $0.10 | - | | Kimi K2 Thinking | $0.40 | $2.50 | - | - | | Kimi K2 | $0.40 | $2.50 | - | - | | Qwen3 Coder 480B | $0.45 | $1.50 | - | - | +| Claude Opus 4.6 (≤ 200K tokens) | $5.00 | $25.00 | $0.50 | $6.25 | +| Claude Opus 4.6 (> 200K tokens) | $10.00 | $37.50 | $1.00 | $12.50 | +| Claude Opus 4.5 | $5.00 | $25.00 | $0.50 | $6.25 | +| Claude Opus 4.1 | $15.00 | $75.00 | $1.50 | $18.75 | +| Claude Sonnet 4.6 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 | +| Claude Sonnet 4.6 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 | | Claude Sonnet 4.5 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 | | Claude Sonnet 4.5 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 | | Claude Sonnet 4 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 | | Claude Sonnet 4 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 | | Claude Haiku 4.5 | $1.00 | $5.00 | $0.10 | $1.25 | | Claude Haiku 3.5 | $0.80 | $4.00 | $0.08 | $1.00 | -| Claude Opus 4.6 (≤ 200K tokens) | $5.00 | $25.00 | $0.50 | $6.25 | -| Claude Opus 4.6 (> 200K tokens) | $10.00 | $37.50 | $1.00 | $12.50 | -| Claude Opus 4.5 | $5.00 | $25.00 | $0.50 | $6.25 | -| Claude Opus 4.1 | $15.00 | $75.00 | $1.50 | $18.75 | +| Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | +| Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | | Gemini 3 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | +| GPT 5.4 | $2.50 | $15.00 | $0.25 | - | +| GPT 5.3 Codex | $1.75 | $14.00 | $0.175 | - | | GPT 5.2 | $1.75 | $14.00 | $0.175 | - | | GPT 5.2 Codex | $1.75 | $14.00 | $0.175 | - | | GPT 5.1 | $1.07 | $8.50 | $0.107 | - | @@ -150,18 +160,16 @@ Wspieramy model pay-as-you-go. Poniżej znajdują się ceny **za 1M tokenów**. | GPT 5 Codex | $1.07 | $8.50 | $0.107 | - | | GPT 5 Nano | Free | Free | Free | - | -Możesz zauważyć _Claude Haiku 3.5_ w swojej historii użytkowania. To jest [model niskokosztowy](/docs/config/#models), który służy do generowania tytułów sesji. +Możesz zauważyć _Claude Haiku 3.5_ w swojej historii użytkowania. Jest to [tani model](/docs/config/#models), który jest używany do generowania tytułów Twoich sesji. :::note -Opłaty za karty kredytowe są przenoszone na koszt (4,4% + 0,30 USD za transakcję); nie pobieramy żadnych dodatkowych opłat. +Opłaty za karty kredytowe są przenoszone po kosztach (4,4% + 0,30 USD za transakcję); nie pobieramy nic poza tym. ::: Darmowe modele: -- GLM 4.7 Free jest dostępny na platformie opencode przez ograniczony czas. Zespół wykorzystuje ten czas na zbieranie opinii i ulepszanie modelu. -- Kimi K2.5 Free jest dostępny na opencode przez ograniczony czas. Zespół wykorzystuje ten czas na zbieranie opinii i ulepszanie modelu. -- MiniMax M2.1 Free jest dostępny na platformie opencode przez ograniczony czas. Zespół wykorzystuje ten czas na zbieranie opinii i ulepszanie modelu. -- Big Pickle to ukryty model, który jest bezpłatny w opencode przez ograniczony czas. Zespół wykorzystuje ten czas na zbieranie opinii i ulepszanie modelu. +- MiniMax M2.5 Free jest dostępny w OpenCode przez ograniczony czas. Zespół wykorzystuje ten czas na zbieranie opinii i ulepszanie modelu. +- Big Pickle to ukryty model, który jest bezpłatny w OpenCode przez ograniczony czas. Zespół wykorzystuje ten czas na zbieranie opinii i ulepszanie modelu. <a href={email}>Skontaktuj się z nami</a>, jeśli masz jakieś pytania. @@ -171,18 +179,31 @@ Darmowe modele: Jeśli Twoje saldo spadnie poniżej 5 USD, Zen automatycznie doładuje 20 USD. -Możesz zmienić kwotę automatycznego doładowania. Możesz także całkowicie wyłączyć automatyczne przeładowywanie. +Możesz zmienić kwotę automatycznego doładowania. Możesz także całkowicie wyłączyć automatyczne doładowanie. --- ### Limity miesięczne -Możesz także ustawić miesięczny limit wykorzystania dla całego obszaru roboczego i dla każdego z nich -członek Twojego zespołu. +Możesz także ustawić miesięczny limit użytkowania dla całego obszaru roboczego i dla każdego +członka Twojego zespołu. -Załóżmy na przykład, że ustawiłeś miesięczny limit użytkowania na 20 USD, Zen nie będzie z niego korzystał -ponad 20 dolarów miesięcznie. Ale jeśli masz włączone automatyczne przeładowywanie, Zen może się skończyć -obciąży Cię kwotą wyższą niż 20 USD, jeśli saldo spadnie poniżej 5 USD. +Na przykład, jeśli ustawisz miesięczny limit użytkowania na 20 USD, Zen nie zużyje +więcej niż 20 dolarów w miesiącu. Ale jeśli masz włączone automatyczne doładowanie, Zen może +obciążyć Cię kwotą wyższą niż 20 USD, jeśli saldo spadnie poniżej 5 USD. + +--- + +### Przestarzałe modele + +| Model | Data wycofania | +| ---------------- | -------------- | +| Qwen3 Coder 480B | 6 lutego 2026 | +| Kimi K2 Thinking | 6 marca 2026 | +| Kimi K2 | 6 marca 2026 | +| MiniMax M2.1 | 15 marca 2026 | +| GLM 4.7 | 15 marca 2026 | +| GLM 4.6 | 15 marca 2026 | --- @@ -191,25 +212,23 @@ obciąży Cię kwotą wyższą niż 20 USD, jeśli saldo spadnie poniżej 5 USD. Wszystkie nasze modele są hostowane w USA. Nasi dostawcy przestrzegają polityki zerowego przechowywania i nie wykorzystują Twoich danych do szkolenia modeli, z następującymi wyjątkami: - Big Pickle: W okresie bezpłatnym zebrane dane mogą zostać wykorzystane do udoskonalenia modelu. -- GLM 4.7 Bezpłatna: W okresie bezpłatnym zebrane dane mogą zostać wykorzystane do udoskonalenia modelu. -- Kimi K2.5 Free: W okresie bezpłatnym zebrane dane mogą zostać wykorzystane do udoskonalenia modelu. -- MiniMax M2.1 Free: W okresie bezpłatnym zebrane dane mogą zostać wykorzystane do udoskonalenia modelu. -- Interfejsy API OpenAI: żądania są przechowywane przez 30 dni zgodnie z [Zasadami dotyczącymi danych OpenAI](https://platform.openai.com/docs/guides/your-data). -- Interfejsy API Anthropic: żądania są przechowywane przez 30 dni zgodnie z [Zasadami dotyczącymi danych firmy Anthropic] (https://docs.anthropic.com/en/docs/claude-code/data-usage). +- MiniMax M2.5 Free: W okresie bezpłatnym zebrane dane mogą zostać wykorzystane do udoskonalenia modelu. +- API OpenAI: Żądania są przechowywane przez 30 dni zgodnie z [Zasadami dotyczącymi danych OpenAI](https://platform.openai.com/docs/guides/your-data). +- API Anthropic: Żądania są przechowywane przez 30 dni zgodnie z [Zasadami dotyczącymi danych Anthropic](https://docs.anthropic.com/en/docs/claude-code/data-usage). --- ## Dla zespołów -Zen świetnie sprawdza się także w zespołach. Możesz zapraszać członków zespołu, przypisywać role, zarządzać +Zen działa świetnie także dla zespołów. Możesz zapraszać członków zespołu, przypisywać role, dobierać modele, z których korzysta Twój zespół i nie tylko. :::note Obszary robocze są obecnie bezpłatne dla zespołów w ramach wersji beta. ::: -Zarządzanie obszarem roboczym jest obecnie bezpłatne dla zespołów w ramach wersji beta. Będziemy -wkrótce udostępnimy więcej szczegółów na temat cen. +Zarządzanie obszarem roboczym jest obecnie bezpłatne dla zespołów w ramach wersji beta. +Wkrótce udostępnimy więcej szczegółów na temat cen. --- @@ -217,8 +236,8 @@ wkrótce udostępnimy więcej szczegółów na temat cen. Możesz zapraszać członków zespołu do swojego obszaru roboczego i przypisywać role: -- **Administrator**: Zarządzaj modelami, członkami, kluczami API i rozliczeniami -- **Członek**: Zarządzaj tylko własnymi kluczami API +- **Admin**: Zarządzanie modelami, członkami, kluczami API i rozliczeniami +- **Członek**: Zarządzanie tylko własnymi kluczami API Administratorzy mogą także ustawić miesięczne limity wydatków dla każdego członka, aby utrzymać koszty pod kontrolą. @@ -229,7 +248,7 @@ Administratorzy mogą także ustawić miesięczne limity wydatków dla każdego Administratorzy mogą włączać i wyłączać określone modele w obszarze roboczym. Żądania skierowane do wyłączonego modelu zwrócą błąd. Jest to przydatne w przypadkach, gdy chcesz wyłączyć korzystanie z modelu, który -collects data. +zbiera dane. --- @@ -249,6 +268,6 @@ i chcesz go używać zamiast tego, który zapewnia Zen. Stworzyliśmy OpenCode Zen, aby: 1. **Testować** (Benchmark) najlepsze modele/dostawców dla agentów kodujących. -2. Miej dostęp do opcji **najwyższej jakości**, a nie obniżaj wydajności ani nie kieruj się do tańszych dostawców. -3. Przekaż wszelkie **obniżki cen**, sprzedając po kosztach; więc jedyną marżą jest pokrycie naszych opłat manipulacyjnych. -4. Nie **nie blokuj**, umożliwiając używanie go z dowolnym innym agentem kodującym. I zawsze pozwalaj na korzystanie z opencode dowolnego innego dostawcy. +2. Mieć dostęp do opcji **najwyższej jakości**, a nie obniżać wydajności ani nie kierować do tańszych dostawców. +3. Przekazywać wszelkie **obniżki cen**, sprzedając po kosztach; więc jedyną marżą jest pokrycie naszych opłat manipulacyjnych. +4. Nie **mieć blokady** (no lock-in), umożliwiając używanie go z dowolnym innym agentem kodującym. I zawsze pozwalać na korzystanie z dowolnego innego dostawcy w OpenCode. diff --git a/packages/web/src/content/docs/providers.mdx b/packages/web/src/content/docs/providers.mdx index db3bfeaeeb..34e3626499 100644 --- a/packages/web/src/content/docs/providers.mdx +++ b/packages/web/src/content/docs/providers.mdx @@ -57,7 +57,39 @@ tested and verified to work well with OpenCode. [Learn more](/docs/zen). If you are new, we recommend starting with OpenCode Zen. ::: -1. Run the `/connect` command in the TUI, select opencode, and head to [opencode.ai/auth](https://opencode.ai/auth). +1. Run the `/connect` command in the TUI, select `OpenCode Zen`, and head to [opencode.ai/auth](https://opencode.ai/zen). + + ```txt + /connect + ``` + +2. Sign in, add your billing details, and copy your API key. + +3. Paste your API key. + + ```txt + ┌ API key + │ + │ + └ enter + ``` + +4. Run `/models` in the TUI to see the list of models we recommend. + + ```txt + /models + ``` + +It works like any other provider in OpenCode and is completely optional to use. + +--- + +## OpenCode Go + +OpenCode Go is a low cost subscription plan that provides reliable access to popular open coding models provided by the OpenCode team that have been +tested and verified to work well with OpenCode. + +1. Run the `/connect` command in the TUI, select `OpenCode Go`, and head to [opencode.ai/auth](https://opencode.ai/zen). ```txt /connect diff --git a/packages/web/src/content/docs/pt-br/config.mdx b/packages/web/src/content/docs/pt-br/config.mdx index 405c537945..4684bb199e 100644 --- a/packages/web/src/content/docs/pt-br/config.mdx +++ b/packages/web/src/content/docs/pt-br/config.mdx @@ -14,10 +14,11 @@ O opencode suporta os formatos **JSON** e **JSONC** (JSON com Comentários). ```jsonc title="opencode.jsonc" { "$schema": "https://opencode.ai/config.json", - // Theme configuration - "theme": "opencode", "model": "anthropic/claude-sonnet-4-5", "autoupdate": true, + "server": { + "port": 4096, + }, } ``` @@ -34,7 +35,7 @@ Os arquivos de configuração são **mesclados**, não substituídos. Os arquivos de configuração são mesclados, não substituídos. As configurações das seguintes localizações de configuração são combinadas. Configurações posteriores substituem as anteriores apenas para chaves conflitantes. Configurações não conflitantes de todas as configurações são preservadas. -Por exemplo, se sua configuração global define `theme: "opencode"` e `autoupdate: true`, e sua configuração de projeto define `model: "anthropic/claude-sonnet-4-5"`, a configuração final incluirá as três configurações. +Por exemplo, se sua configuração global define `autoupdate: true` e sua configuração de projeto define `model: "anthropic/claude-sonnet-4-5"`, a configuração final incluirá as duas configurações. --- @@ -95,7 +96,9 @@ Você pode habilitar servidores específicos em sua configuração local: ### Global -Coloque sua configuração global do opencode em `~/.config/opencode/opencode.json`. Use a configuração global para preferências de usuário, como temas, provedores ou atalhos de teclado. +Coloque sua configuração global do opencode em `~/.config/opencode/opencode.json`. Use a configuração global para preferências de todo o usuário, como provedores, modelos e permissões. + +Para configurações específicas do TUI, use `~/.config/opencode/tui.json`. A configuração global substitui os padrões organizacionais remotos. @@ -105,6 +108,8 @@ A configuração global substitui os padrões organizacionais remotos. Adicione `opencode.json` na raiz do seu projeto. A configuração do projeto tem a maior precedência entre os arquivos de configuração padrão - ela substitui tanto as configurações globais quanto as remotas. +Para configurações específicas do TUI do projeto, adicione `tui.json` junto a ele. + :::tip Coloque a configuração específica do projeto na raiz do seu projeto. ::: @@ -143,7 +148,9 @@ O diretório personalizado é carregado após a configuração global e os diret ## Esquema -O arquivo de configuração tem um esquema que está definido em [**`opencode.ai/config.json`**](https://opencode.ai/config.json). +O esquema de configuração do servidor/tempo de execução é definido em [**`opencode.ai/config.json`**](https://opencode.ai/config.json). + +A configuração do TUI usa [**`opencode.ai/tui.json`**](https://opencode.ai/tui.json). Seu editor deve ser capaz de validar e autocompletar com base no esquema. @@ -151,28 +158,24 @@ Seu editor deve ser capaz de validar e autocompletar com base no esquema. ### TUI -Você pode configurar as configurações específicas do TUI através da opção `tui`. +Use um arquivo `tui.json` (ou `tui.jsonc`) dedicado para configurações específicas do TUI. -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", - "tui": { - "scroll_speed": 3, - "scroll_acceleration": { - "enabled": true - }, - "diff_style": "auto" - } + "$schema": "https://opencode.ai/tui.json", + "scroll_speed": 3, + "scroll_acceleration": { + "enabled": true + }, + "diff_style": "auto" } ``` -Opções disponíveis: +Use `OPENCODE_TUI_CONFIG` para apontar para um arquivo de configuração TUI personalizado. -- `scroll_acceleration.enabled` - Habilitar aceleração de rolagem estilo macOS. **Tem precedência sobre `scroll_speed`.** -- `scroll_speed` - Multiplicador de velocidade de rolagem personalizada (padrão: `3`, mínimo: `1`). Ignorado se `scroll_acceleration.enabled` for `true`. -- `diff_style` - Controlar a renderização de diffs. `"auto"` se adapta à largura do terminal, `"stacked"` sempre mostra uma coluna única. +Chaves legadas `theme`, `keybinds` e `tui` em `opencode.json` estão obsoletas e são migradas automaticamente quando possível. -[Saiba mais sobre o uso do TUI aqui](/docs/tui). +[Saiba mais sobre a configuração do TUI aqui](/docs/tui#configure). --- @@ -298,12 +301,12 @@ Tokens Bearer (`AWS_BEARER_TOKEN_BEDROCK` ou `/connect`) têm precedência sobre ### Temas -Você pode configurar o tema que deseja usar em sua configuração do opencode através da opção `theme`. +Defina seu tema de interface em `tui.json`. -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", - "theme": "" + "$schema": "https://opencode.ai/tui.json", + "theme": "tokyonight" } ``` @@ -403,11 +406,11 @@ Você também pode definir comandos usando arquivos markdown em `~/.config/openc ### Atalhos de teclado -Você pode personalizar seus atalhos de teclado através da opção `keybinds`. +Personalize atalhos de teclado em `tui.json`. -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "keybinds": {} } ``` @@ -487,13 +490,15 @@ Você pode controlar o comportamento de compactação de contexto através da op "$schema": "https://opencode.ai/config.json", "compaction": { "auto": true, - "prune": true + "prune": true, + "reserved": 10000 } } ``` - `auto` - Compactar automaticamente a sessão quando o contexto estiver cheio (padrão: `true`). - `prune` - Remover saídas antigas de ferramentas para economizar tokens (padrão: `true`). +- `reserved` - Buffer de tokens para compactação. Deixa janela suficiente para evitar estouro durante a compactação --- @@ -673,6 +678,7 @@ Os caminhos dos arquivos podem ser: - Relativos ao diretório do arquivo de configuração - Ou caminhos absolutos começando com `/` ou `~` +- Esses são úteis para: diff --git a/packages/web/src/content/docs/pt-br/custom-tools.mdx b/packages/web/src/content/docs/pt-br/custom-tools.mdx index 43749200f8..515b8985a0 100644 --- a/packages/web/src/content/docs/pt-br/custom-tools.mdx +++ b/packages/web/src/content/docs/pt-br/custom-tools.mdx @@ -79,6 +79,32 @@ Isso cria duas ferramentas: `math_add` e `math_multiply`. --- +#### Colisões de nome com ferramentas integradas + +Ferramentas personalizadas são chaveadas pelo nome da ferramenta. Se uma ferramenta personalizada usar o mesmo nome que uma ferramenta integrada, a ferramenta personalizada tem precedência. + +Por exemplo, este arquivo substitui a ferramenta `bash` integrada: + +```ts title=".opencode/tools/bash.ts" +import { tool } from "@opencode-ai/plugin" + +export default tool({ + description: "Restricted bash wrapper", + args: { + command: tool.schema.string(), + }, + async execute(args) { + return `blocked: ${args.command}` + }, +}) +``` + +:::note +Prefira nomes únicos, a menos que você queira intencionalmente substituir uma ferramenta integrada. Se você quiser desabilitar uma ferramenta integrada, mas não substituí-la, use [permissões](/docs/permissions). +::: + +--- + ### Argumentos Você pode usar `tool.schema`, que é apenas [Zod](https://zod.dev), para definir tipos de argumentos. @@ -126,7 +152,7 @@ export default tool({ }) ``` -Use `context.directory` para o diretório de trabalho da sessão. +Use `context.directory` para o diretório de trabalho da sessão. Use `context.worktree` para a raiz do worktree do git. --- diff --git a/packages/web/src/content/docs/pt-br/ecosystem.mdx b/packages/web/src/content/docs/pt-br/ecosystem.mdx index ac5d354441..1d4d0bac11 100644 --- a/packages/web/src/content/docs/pt-br/ecosystem.mdx +++ b/packages/web/src/content/docs/pt-br/ecosystem.mdx @@ -1,12 +1,12 @@ --- title: Ecossistema -description: Projetos e integrações construídos com o opencode. +description: Projetos e integrações construídos com o OpenCode. --- -Uma coleção de projetos da comunidade construídos sobre o opencode. +Uma coleção de projetos da comunidade construídos sobre o OpenCode. :::note -Quer adicionar seu projeto relacionado ao opencode a esta lista? Envie um PR. +Quer adicionar seu projeto relacionado ao OpenCode a esta lista? Envie um PR. ::: Você também pode conferir [awesome-opencode](https://github.com/awesome-opencode/awesome-opencode) e [opencode.cafe](https://opencode.cafe), uma comunidade que agrega o ecossistema e a comunidade. @@ -15,38 +15,40 @@ Você também pode conferir [awesome-opencode](https://github.com/awesome-openco ## Plugins -| Nome | Descrição | -| --------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | -| [opencode-daytona](https://github.com/jamesmurdza/daytona/blob/main/guides/typescript/opencode/README.md) | Execute automaticamente sessões do opencode em sandboxes isoladas do Daytona com sincronização git e pré-visualizações ao vivo | -| [opencode-helicone-session](https://github.com/H2Shami/opencode-helicone-session) | Injete automaticamente cabeçalhos de sessão Helicone para agrupamento de requisições | -| [opencode-type-inject](https://github.com/nick-vi/opencode-type-inject) | Auto-injetar tipos TypeScript/Svelte em leituras de arquivos com ferramentas de busca | -| [opencode-openai-codex-auth](https://github.com/numman-ali/opencode-openai-codex-auth) | Use sua assinatura ChatGPT Plus/Pro em vez de créditos de API | -| [opencode-gemini-auth](https://github.com/jenslys/opencode-gemini-auth) | Use seu plano Gemini existente em vez de cobrança de API | -| [opencode-antigravity-auth](https://github.com/NoeFabris/opencode-antigravity-auth) | Use os modelos gratuitos do Antigravity em vez de cobrança de API | -| [opencode-devcontainers](https://github.com/athal7/opencode-devcontainers) | Isolamento de devcontainer multi-branch com clones rasos e portas atribuídas automaticamente | -| [opencode-google-antigravity-auth](https://github.com/shekohex/opencode-google-antigravity-auth) | Plugin Google Antigravity OAuth, com suporte para Google Search e manuseio de API mais robusto | -| [opencode-dynamic-context-pruning](https://github.com/Tarquinen/opencode-dynamic-context-pruning) | Otimize o uso de tokens podando saídas de ferramentas obsoletas | -| [opencode-websearch-cited](https://github.com/ghoulr/opencode-websearch-cited.git) | Adicione suporte nativo de pesquisa na web para provedores suportados com estilo fundamentado no Google | -| [opencode-pty](https://github.com/shekohex/opencode-pty.git) | Permite que agentes de IA executem processos em segundo plano em um PTY, enviando entrada interativa para eles. | -| [opencode-shell-strategy](https://github.com/JRedeker/opencode-shell-strategy) | Instruções para comandos de shell não interativos - evita travamentos de operações dependentes de TTY | -| [opencode-wakatime](https://github.com/angristan/opencode-wakatime) | Acompanhe o uso do opencode com Wakatime | -| [opencode-md-table-formatter](https://github.com/franlol/opencode-md-table-formatter/tree/main) | Limpe tabelas markdown produzidas por LLMs | -| [opencode-morph-fast-apply](https://github.com/JRedeker/opencode-morph-fast-apply) | Edição de código 10x mais rápida com a API Morph Fast Apply e marcadores de edição preguiçosos | -| [oh-my-opencode](https://github.com/code-yeongyu/oh-my-opencode) | Agentes em segundo plano, ferramentas LSP/AST/MCP pré-construídas, agentes curados, compatível com Claude Code | -| [opencode-notificator](https://github.com/panta82/opencode-notificator) | Notificações de desktop e alertas sonoros para sessões do opencode | -| [opencode-notifier](https://github.com/mohak34/opencode-notifier) | Notificações de desktop e alertas sonoros para eventos de permissão, conclusão e erro | -| [opencode-zellij-namer](https://github.com/24601/opencode-zellij-namer) | Nomeação automática de sessões Zellij com suporte de IA com base no contexto do opencode | -| [opencode-skillful](https://github.com/zenobi-us/opencode-skillful) | Permite que agentes do opencode carreguem prompts sob demanda com descoberta e injeção de habilidades | -| [opencode-supermemory](https://github.com/supermemoryai/opencode-supermemory) | Memória persistente entre sessões usando Supermemory | -| [@plannotator/opencode](https://github.com/backnotprop/plannotator/tree/main/apps/opencode-plugin) | Revisão de plano interativa com anotação visual e compartilhamento privado/offline | -| [@openspoon/subtask2](https://github.com/spoons-and-mirrors/subtask2) | Estenda opencode /commands em um poderoso sistema de orquestração com controle de fluxo granular | -| [opencode-scheduler](https://github.com/different-ai/opencode-scheduler) | Agende trabalhos recorrentes usando launchd (Mac) ou systemd (Linux) com sintaxe cron | -| [micode](https://github.com/vtemian/micode) | Fluxo de trabalho Estruturado Brainstorm → Planejar → Implementar com continuidade de sessão | -| [octto](https://github.com/vtemian/octto) | UI interativa do navegador para brainstorming de IA com formulários de múltiplas perguntas | -| [opencode-background-agents](https://github.com/kdcokenny/opencode-background-agents) | Agentes em segundo plano estilo Claude Code com delegação assíncrona e persistência de contexto | -| [opencode-notify](https://github.com/kdcokenny/opencode-notify) | Notificações nativas do OS para opencode – saiba quando as tarefas são concluídas | -| [opencode-workspace](https://github.com/kdcokenny/opencode-workspace) | Conjunto de orquestração multi-agente – 16 componentes, uma instalação | -| [opencode-worktree](https://github.com/kdcokenny/opencode-worktree) | Worktrees git sem atrito para opencode | +| Nome | Descrição | +| -------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | +| [opencode-daytona](https://github.com/daytonaio/daytona/tree/main/libs/opencode-plugin) | Execute automaticamente sessões do OpenCode em sandboxes isoladas do Daytona com sincronização git e pré-visualizações ao vivo | +| [opencode-helicone-session](https://github.com/H2Shami/opencode-helicone-session) | Injete automaticamente cabeçalhos de sessão Helicone para agrupamento de requisições | +| [opencode-type-inject](https://github.com/nick-vi/opencode-type-inject) | Auto-injetar tipos TypeScript/Svelte em leituras de arquivos com ferramentas de busca | +| [opencode-openai-codex-auth](https://github.com/numman-ali/opencode-openai-codex-auth) | Use sua assinatura ChatGPT Plus/Pro em vez de créditos de API | +| [opencode-gemini-auth](https://github.com/jenslys/opencode-gemini-auth) | Use seu plano Gemini existente em vez de cobrança de API | +| [opencode-antigravity-auth](https://github.com/NoeFabris/opencode-antigravity-auth) | Use os modelos gratuitos do Antigravity em vez de cobrança de API | +| [opencode-devcontainers](https://github.com/athal7/opencode-devcontainers) | Isolamento de devcontainer multi-branch com clones rasos e portas atribuídas automaticamente | +| [opencode-google-antigravity-auth](https://github.com/shekohex/opencode-google-antigravity-auth) | Plugin Google Antigravity OAuth, com suporte para Google Search e manuseio de API mais robusto | +| [opencode-dynamic-context-pruning](https://github.com/Tarquinen/opencode-dynamic-context-pruning) | Otimize o uso de tokens podando saídas de ferramentas obsoletas | +| [opencode-vibeguard](https://github.com/inkdust2021/opencode-vibeguard) | Oculte segredos/PII em marcadores estilo VibeGuard antes de chamadas LLM; restaure localmente | +| [opencode-websearch-cited](https://github.com/ghoulr/opencode-websearch-cited.git) | Adicione suporte nativo de pesquisa na web para provedores suportados com estilo fundamentado no Google | +| [opencode-pty](https://github.com/shekohex/opencode-pty.git) | Permite que agentes de IA executem processos em segundo plano em um PTY, enviando entrada interativa para eles. | +| [opencode-shell-strategy](https://github.com/JRedeker/opencode-shell-strategy) | Instruções para comandos de shell não interativos - evita travamentos de operações dependentes de TTY | +| [opencode-wakatime](https://github.com/angristan/opencode-wakatime) | Acompanhe o uso do OpenCode com Wakatime | +| [opencode-md-table-formatter](https://github.com/franlol/opencode-md-table-formatter/tree/main) | Limpe tabelas markdown produzidas por LLMs | +| [opencode-morph-fast-apply](https://github.com/JRedeker/opencode-morph-fast-apply) | Edição de código 10x mais rápida com a API Morph Fast Apply e marcadores de edição preguiçosos | +| [oh-my-opencode](https://github.com/code-yeongyu/oh-my-opencode) | Agentes em segundo plano, ferramentas LSP/AST/MCP pré-construídas, agentes curados, compatível com Claude Code | +| [opencode-notificator](https://github.com/panta82/opencode-notificator) | Notificações de desktop e alertas sonoros para sessões do OpenCode | +| [opencode-notifier](https://github.com/mohak34/opencode-notifier) | Notificações de desktop e alertas sonoros para eventos de permissão, conclusão e erro | +| [opencode-zellij-namer](https://github.com/24601/opencode-zellij-namer) | Nomeação automática de sessões Zellij com suporte de IA com base no contexto do OpenCode | +| [opencode-skillful](https://github.com/zenobi-us/opencode-skillful) | Permite que agentes do OpenCode carreguem prompts sob demanda com descoberta e injeção de habilidades | +| [opencode-supermemory](https://github.com/supermemoryai/opencode-supermemory) | Memória persistente entre sessões usando Supermemory | +| [@plannotator/opencode](https://github.com/backnotprop/plannotator/tree/main/apps/opencode-plugin) | Revisão de plano interativa com anotação visual e compartilhamento privado/offline | +| [@openspoon/subtask2](https://github.com/spoons-and-mirrors/subtask2) | Estenda opencode /commands em um poderoso sistema de orquestração com controle de fluxo granular | +| [opencode-scheduler](https://github.com/different-ai/opencode-scheduler) | Agende trabalhos recorrentes usando launchd (Mac) ou systemd (Linux) com sintaxe cron | +| [micode](https://github.com/vtemian/micode) | Fluxo de trabalho Estruturado Brainstorm → Planejar → Implementar com continuidade de sessão | +| [octto](https://github.com/vtemian/octto) | UI interativa do navegador para brainstorming de IA com formulários de múltiplas perguntas | +| [opencode-background-agents](https://github.com/kdcokenny/opencode-background-agents) | Agentes em segundo plano estilo Claude Code com delegação assíncrona e persistência de contexto | +| [opencode-notify](https://github.com/kdcokenny/opencode-notify) | Notificações nativas do OS para OpenCode – saiba quando as tarefas são concluídas | +| [opencode-workspace](https://github.com/kdcokenny/opencode-workspace) | Conjunto de orquestração multi-agente – 16 componentes, uma instalação | +| [opencode-worktree](https://github.com/kdcokenny/opencode-worktree) | Worktrees git sem atrito para OpenCode | +| [opencode-sentry-monitor](https://github.com/stolinski/opencode-sentry-monitor) | Rastreie e depure seus agentes de IA com o Sentry AI Monitoring | --- @@ -54,17 +56,17 @@ Você também pode conferir [awesome-opencode](https://github.com/awesome-openco | Nome | Descrição | | ------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------- | -| [kimaki](https://github.com/remorses/kimaki) | Bot do Discord para controlar sessões do opencode, construído sobre o SDK | +| [kimaki](https://github.com/remorses/kimaki) | Bot do Discord para controlar sessões do OpenCode, construído sobre o SDK | | [opencode.nvim](https://github.com/NickvanDyke/opencode.nvim) | Plugin Neovim para prompts cientes do editor, construído sobre a API | -| [portal](https://github.com/hosenur/portal) | UI web mobile-first para opencode sobre Tailscale/VPN | -| [opencode plugin template](https://github.com/zenobi-us/opencode-plugin-template/) | Template para construir plugins do opencode | -| [opencode.nvim](https://github.com/sudo-tee/opencode.nvim) | Frontend Neovim para opencode - um agente de codificação IA baseado em terminal | -| [ai-sdk-provider-opencode-sdk](https://github.com/ben-vargas/ai-sdk-provider-opencode-sdk) | Provedor Vercel AI SDK para usar opencode via @opencode-ai/sdk | -| [OpenChamber](https://github.com/btriapitsyn/openchamber) | Aplicativo Web / Desktop e Extensão do VS Code para opencode | -| [OpenCode-Obsidian](https://github.com/mtymek/opencode-obsidian) | Plugin Obsidian que incorpora opencode na UI do Obsidian | -| [OpenWork](https://github.com/different-ai/openwork) | Uma alternativa de código aberto ao Claude Cowork, alimentada pelo opencode | -| [ocx](https://github.com/kdcokenny/ocx) | Gerenciador de extensões opencode com perfis portáteis e isolados. | -| [CodeNomad](https://github.com/NeuralNomadsAI/CodeNomad) | Aplicativo Desktop, Web, Mobile e Cliente Remoto para opencode | +| [portal](https://github.com/hosenur/portal) | UI web mobile-first para OpenCode sobre Tailscale/VPN | +| [opencode plugin template](https://github.com/zenobi-us/opencode-plugin-template/) | Template para construir plugins do OpenCode | +| [opencode.nvim](https://github.com/sudo-tee/opencode.nvim) | Frontend Neovim para OpenCode - um agente de codificação IA baseado em terminal | +| [ai-sdk-provider-opencode-sdk](https://github.com/ben-vargas/ai-sdk-provider-opencode-sdk) | Provedor Vercel AI SDK para usar OpenCode via @opencode-ai/sdk | +| [OpenChamber](https://github.com/btriapitsyn/openchamber) | Aplicativo Web / Desktop e Extensão do VS Code para OpenCode | +| [OpenCode-Obsidian](https://github.com/mtymek/opencode-obsidian) | Plugin Obsidian que incorpora OpenCode na UI do Obsidian | +| [OpenWork](https://github.com/different-ai/openwork) | Uma alternativa de código aberto ao Claude Cowork, alimentada pelo OpenCode | +| [ocx](https://github.com/kdcokenny/ocx) | Gerenciador de extensões OpenCode com perfis portáteis e isolados. | +| [CodeNomad](https://github.com/NeuralNomadsAI/CodeNomad) | Aplicativo Desktop, Web, Mobile e Cliente Remoto para OpenCode | --- diff --git a/packages/web/src/content/docs/pt-br/go.mdx b/packages/web/src/content/docs/pt-br/go.mdx new file mode 100644 index 0000000000..ee72ed49cb --- /dev/null +++ b/packages/web/src/content/docs/pt-br/go.mdx @@ -0,0 +1,145 @@ +--- +title: Go +description: Assinatura de baixo custo para modelos de codificação abertos. +--- + +import config from "../../../../config.mjs" +export const console = config.console +export const email = `mailto:${config.email}` + +O OpenCode Go é uma assinatura de baixo custo de **$10/mês** que oferece acesso confiável a modelos de codificação abertos populares. + +:::note +O OpenCode Go está atualmente em beta. +::: + +O Go funciona como qualquer outro provedor no OpenCode. Você assina o OpenCode Go e obtém sua chave de API. É **totalmente opcional** e você não precisa usá-lo para usar o OpenCode. + +Ele é projetado principalmente para usuários internacionais, com modelos hospedados nos EUA, UE e Singapura para acesso global estável. + +--- + +## Contexto + +Modelos abertos ficaram realmente bons. Eles agora alcançam desempenho próximo aos modelos proprietários para tarefas de codificação. E como muitos provedores podem servi-los competitivamente, eles geralmente são muito mais baratos. + +No entanto, obter acesso confiável e de baixa latência a eles pode ser difícil. Os provedores variam em qualidade e disponibilidade. + +:::tip +Testamos um grupo selecionado de modelos e provedores que funcionam bem com o OpenCode. +::: + +Para corrigir isso, fizemos algumas coisas: + +1. Testamos um grupo selecionado de modelos abertos e conversamos com suas equipes sobre a melhor forma de executá-los. +2. Trabalhamos com alguns provedores para garantir que eles estivessem sendo servidos corretamente. +3. Finalmente, fizemos benchmarks da combinação modelo/provedor e chegamos a uma lista que nos sentimos bem em recomendar. + +O OpenCode Go oferece acesso a esses modelos por **$10/mês**. + +--- + +## Como funciona + +O OpenCode Go funciona como qualquer outro provedor no OpenCode. + +1. Você faz login no **<a href={console}>OpenCode Zen</a>**, assina o Go e copia sua chave de API. +2. Você executa o comando `/connect` na TUI, seleciona `OpenCode Go` e cola sua chave de API. +3. Execute `/models` na TUI para ver a lista de modelos disponíveis através do Go. + +:::note +Apenas um membro por workspace pode assinar o OpenCode Go. +::: + +A lista atual de modelos inclui: + +- **GLM-5** +- **Kimi K2.5** +- **MiniMax M2.5** + +A lista de modelos pode mudar conforme testamos e adicionamos novos. + +--- + +## Limites de uso + +O OpenCode Go inclui os seguintes limites: + +- **Limite de 5 horas** — $12 de uso +- **Limite semanal** — $30 de uso +- **Limite mensal** — $60 de uso + +Os limites são definidos em valor monetário. Isso significa que sua contagem real de requisições depende do modelo que você usa. Modelos mais baratos como o MiniMax M2.5 permitem mais requisições, enquanto modelos de custo mais alto como o GLM-5 permitem menos. + +A tabela abaixo fornece uma estimativa de contagem de requisições baseada em padrões típicos de uso do Go: + +| | GLM-5 | Kimi K2.5 | MiniMax M2.5 | +| ----------------------- | ----- | --------- | ------------ | +| requisições por 5 horas | 1.150 | 1.850 | 30.000 | +| requisições por semana | 2.880 | 4.630 | 75.000 | +| requisições por mês | 5.750 | 9.250 | 150.000 | + +As estimativas são baseadas em padrões médios de requisição observados: + +- GLM-5 — 700 tokens de entrada, 52.000 em cache, 150 tokens de saída por requisição +- Kimi K2.5 — 870 tokens de entrada, 55.000 em cache, 200 tokens de saída por requisição +- MiniMax M2.5 — 300 tokens de entrada, 55.000 em cache, 125 tokens de saída por requisição + +Você pode acompanhar seu uso atual no **<a href={console}>console</a>**. + +:::tip +Se você atingir o limite de uso, pode continuar usando os modelos gratuitos. +::: + +Os limites de uso podem mudar conforme aprendemos com o uso inicial e feedback. + +--- + +### Preços + +O OpenCode Go é um plano de assinatura de **$10/mês**. Abaixo estão os preços **por 1M de tokens**. + +| Modelo | Entrada | Saída | Leitura em Cache | +| ------------ | ------- | ----- | ---------------- | +| GLM-5 | $1.00 | $3.20 | $0.20 | +| Kimi K2.5 | $0.60 | $3.00 | $0.10 | +| MiniMax M2.5 | $0.30 | $1.20 | $0.03 | + +--- + +### Uso além dos limites + +Se você também tiver créditos em seu saldo Zen, pode ativar a opção **Use balance** (Usar saldo) no console. Quando ativada, o Go recorrerá ao seu saldo Zen depois que você atingir seus limites de uso, em vez de bloquear as requisições. + +--- + +## Endpoints + +Você também pode acessar os modelos Go através dos seguintes endpoints de API. + +| Modelo | ID do Modelo | Endpoint | Pacote AI SDK | +| ------------ | ------------ | ------------------------------------------------ | --------------------------- | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | + +O [model id](/docs/config/#models) (ID do modelo) na sua configuração do OpenCode usa o formato `opencode-go/<model-id>`. Por exemplo, para o Kimi K2.5, você usaria `opencode-go/kimi-k2.5` na sua configuração. + +--- + +## Privacidade + +O plano é projetado principalmente para usuários internacionais, com modelos hospedados nos EUA, UE e Singapura para acesso global estável. + +<a href={email}>Entre em contato conosco</a> se tiver alguma dúvida. + +--- + +## Objetivos + +Criamos o OpenCode Go para: + +1. Tornar a IA de codificação **acessível** a mais pessoas com uma assinatura de baixo custo. +2. Fornecer acesso **confiável** aos melhores modelos de codificação abertos. +3. Curar modelos que são **testados e avaliados** para uso em agentes de codificação. +4. Não ter **nenhum bloqueio (lock-in)**, permitindo que você use qualquer outro provedor com o OpenCode também. diff --git a/packages/web/src/content/docs/pt-br/keybinds.mdx b/packages/web/src/content/docs/pt-br/keybinds.mdx index b4da4471aa..6c7fcd208e 100644 --- a/packages/web/src/content/docs/pt-br/keybinds.mdx +++ b/packages/web/src/content/docs/pt-br/keybinds.mdx @@ -3,11 +3,11 @@ title: Atalhos de Teclado description: Personalize seus atalhos de teclado. --- -O opencode tem uma lista de atalhos de teclado que você pode personalizar através da configuração do opencode. +O opencode tem uma lista de atalhos de teclado que você pode personalizar através de `tui.json`. -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "keybinds": { "leader": "ctrl+x", "app_exit": "ctrl+c,ctrl+d,<leader>q", @@ -28,6 +28,7 @@ O opencode tem uma lista de atalhos de teclado que você pode personalizar atrav "session_unshare": "none", "session_interrupt": "escape", "session_compact": "<leader>c", + "session_child_first": "<leader>down", "session_child_cycle": "<leader>right", "session_child_cycle_reverse": "<leader>left", "session_parent": "<leader>up", @@ -119,9 +120,9 @@ Você não precisa usar uma tecla líder para seus atalhos, mas recomendamos que Você pode desativar um atalho adicionando a tecla à sua configuração com um valor de "none". -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "keybinds": { "session_compact": "none" } diff --git a/packages/web/src/content/docs/pt-br/lsp.mdx b/packages/web/src/content/docs/pt-br/lsp.mdx index 6baf1813b3..cd8937b244 100644 --- a/packages/web/src/content/docs/pt-br/lsp.mdx +++ b/packages/web/src/content/docs/pt-br/lsp.mdx @@ -27,6 +27,7 @@ O opencode vem com vários servidores LSP integrados para linguagens populares: | gopls | .go | Comando `go` disponível | | hls | .hs, .lhs | Comando `haskell-language-server-wrapper` disponível | | jdtls | .java | `Java SDK (version 21+)` instalado | +| julials | .jl | `julia` e `LanguageServer.jl` instalados | | kotlin-ls | .kt, .kts | Instala automaticamente para projetos Kotlin | | lua-ls | .lua | Instala automaticamente para projetos Lua | | nixd | .nix | Comando `nixd` disponível | diff --git a/packages/web/src/content/docs/pt-br/plugins.mdx b/packages/web/src/content/docs/pt-br/plugins.mdx index bcf8f379bc..54c5b1ffac 100644 --- a/packages/web/src/content/docs/pt-br/plugins.mdx +++ b/packages/web/src/content/docs/pt-br/plugins.mdx @@ -307,6 +307,10 @@ O helper `tool` cria uma ferramenta personalizada que o opencode pode chamar. El Suas ferramentas personalizadas estarão disponíveis para o opencode junto com as ferramentas integradas. +:::note +Se uma ferramenta de plugin usar o mesmo nome que uma ferramenta integrada, a ferramenta de plugin tem precedência. +::: + --- ### Registro diff --git a/packages/web/src/content/docs/pt-br/providers.mdx b/packages/web/src/content/docs/pt-br/providers.mdx index 43f2e385f1..2ef2ebdc00 100644 --- a/packages/web/src/content/docs/pt-br/providers.mdx +++ b/packages/web/src/content/docs/pt-br/providers.mdx @@ -54,7 +54,39 @@ OpenCode Zen é uma lista de modelos fornecidos pela equipe do opencode que fora Se você é novo, recomendamos começar com o OpenCode Zen. ::: -1. Execute o comando `/connect` no TUI, selecione opencode e acesse [opencode.ai/auth](https://opencode.ai/auth). +1. Execute o comando `/connect` no TUI, selecione `OpenCode Zen` e acesse [opencode.ai/zen](https://opencode.ai/zen). + + ```txt + /connect + ``` + +2. Faça login, adicione seus dados de cobrança e copie sua chave da API. + +3. Cole sua chave da API. + + ```txt + ┌ API key + │ + │ + └ enter + ``` + +4. Execute `/models` no TUI para ver a lista de modelos que recomendamos. + + ```txt + /models + ``` + +Funciona como qualquer outro provedor no opencode e é completamente opcional. + +--- + +## OpenCode Go + +OpenCode Go é um plano de assinatura de baixo custo que fornece acesso confiável a modelos de codificação abertos populares fornecidos pela equipe do opencode que foram +testados e verificados para funcionar bem com o opencode. + +1. Execute o comando `/connect` no TUI, selecione `OpenCode Go` e acesse [opencode.ai/zen](https://opencode.ai/zen). ```txt /connect @@ -130,6 +162,8 @@ Para usar o Amazon Bedrock com o opencode: 2. **Configure a autenticação** usando um dos seguintes métodos: + *** + #### Variáveis de Ambiente (Início Rápido) Defina uma dessas variáveis de ambiente ao executar o opencode: @@ -152,6 +186,8 @@ Para usar o Amazon Bedrock com o opencode: export AWS_REGION=us-east-1 ``` + *** + #### Arquivo de Configuração (Recomendado) Para configuração específica do projeto ou persistente, use `opencode.json`: @@ -179,6 +215,8 @@ Para usar o Amazon Bedrock com o opencode: As opções do arquivo de configuração têm precedência sobre as variáveis de ambiente. ::: + *** + #### Avançado: Endpoints VPC Se você estiver usando endpoints VPC para Bedrock: @@ -202,12 +240,16 @@ Para usar o Amazon Bedrock com o opencode: A opção `endpoint` é um alias para a opção genérica `baseURL`, usando terminologia específica da AWS. Se tanto `endpoint` quanto `baseURL` forem especificados, `endpoint` tem precedência. ::: + *** + #### Métodos de Autenticação - **`AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY`**: Crie um usuário IAM e gere chaves de acesso no Console da AWS - **`AWS_PROFILE`**: Use perfis nomeados de `~/.aws/credentials`. Primeiro configure com `aws configure --profile my-profile` ou `aws sso login` - **`AWS_BEARER_TOKEN_BEDROCK`**: Gere chaves de API de longo prazo no console do Amazon Bedrock - **`AWS_WEB_IDENTITY_TOKEN_FILE` / `AWS_ROLE_ARN`**: Para EKS IRSA (IAM Roles for Service Accounts) ou outros ambientes Kubernetes com federação OIDC. Essas variáveis de ambiente são injetadas automaticamente pelo Kubernetes ao usar anotações de conta de serviço. + *** + #### Precedência de Autenticação O Amazon Bedrock usa a seguinte prioridade de autenticação: @@ -225,7 +267,8 @@ Para usar o Amazon Bedrock com o opencode: ``` :::note -Para perfis de inferência personalizados, use o nome do modelo e do provedor na chave e defina a propriedade `id` para o arn. Isso garante o cache correto: +Para perfis de inferência personalizados, use o nome do modelo e do provedor na chave e defina a propriedade `id` para o arn. Isso garante o cache correto. +::: ```json title="opencode.json" { @@ -243,8 +286,6 @@ Para perfis de inferência personalizados, use o nome do modelo e do provedor na } ``` -::: - --- ### Anthropic @@ -784,8 +825,6 @@ Para usar sua assinatura do GitHub Copilot com o opencode: :::note Alguns modelos podem precisar de uma [assinatura Pro+](https://github.com/features/copilot/plans) para usar. - -Alguns modelos precisam ser habilitados manualmente nas suas [configurações do GitHub Copilot](https://docs.github.com/en/copilot/how-tos/use-ai-models/configure-access-to-ai-models#setup-for-individual-use). ::: 1. Execute o comando `/connect` e procure por GitHub Copilot. @@ -803,7 +842,8 @@ Alguns modelos precisam ser habilitados manualmente nas suas [configurações do │ │ Digite o código: 8F43-6FCF │ - └ Aguardando autorização... + │ Aguardando autorização... + └ ``` 3. Agora execute o comando `/models` para selecionar o modelo que você deseja. @@ -1309,6 +1349,7 @@ Recomendamos se inscrever para [ChatGPT Plus ou Pro](https://chatgpt.com/pricing │ │ ChatGPT Plus/Pro │ Inserir manualmente a chave de API + │ └ ``` @@ -1472,6 +1513,39 @@ SAP AI Core fornece acesso a mais de 40 modelos do OpenAI, Anthropic, Google, Am --- +### STACKIT + +O STACKIT AI Model Serving fornece um ambiente de hospedagem soberano totalmente gerenciado para modelos de IA, com foco em LLMs como Llama, Mistral e Qwen, com máxima soberania de dados na infraestrutura europeia. + +1. Vá para o [Portal STACKIT](https://portal.stackit.cloud), navegue até **AI Model Serving** e crie um token de autenticação para o seu projeto. + + :::tip + Você precisa de uma conta de cliente STACKIT, conta de usuário e projeto antes de criar tokens de autenticação. + ::: + +2. Execute o comando `/connect` e procure por **STACKIT**. + + ```txt + /connect + ``` + +3. Insira seu token de autenticação do STACKIT AI Model Serving. + + ```txt + ┌ API key + │ + │ + └ enter + ``` + +4. Execute o comando `/models` para selecionar entre os modelos disponíveis, como _Qwen3-VL 235B_ ou _Llama 3.3 70B_. + + ```txt + /models + ``` + +--- + ### OVHcloud AI Endpoints 1. Acesse o [painel OVHcloud](https://ovh.com/manager). Navegue até a seção `Public Cloud`, `AI & Machine Learning` > `AI Endpoints` e na aba `API Keys`, clique em **Criar uma nova chave da API**. @@ -1751,10 +1825,9 @@ Você pode usar qualquer provedor compatível com OpenAI com o opencode. A maior ┌ Adicionar credencial │ - ▲ Isso armazena apenas uma credencial para myprovider - você precisará configurá-lo no opencode.json, verifique a documentação para exemplos. - │ - ◇ Digite sua chave de API - │ sk-... + ◆ Select provider + │ ... + │ ● Other └ ``` @@ -1765,10 +1838,8 @@ Você pode usar qualquer provedor compatível com OpenAI com o opencode. A maior ┌ Adicionar credencial │ - ▲ Isso armazena apenas uma credencial para myprovider - você precisará configurá-lo no opencode.json, verifique a documentação para exemplos. - │ - ◇ Digite sua chave de API - │ sk-... + ◇ Enter provider id + │ myprovider └ ``` @@ -1808,8 +1879,6 @@ Você pode usar qualquer provedor compatível com OpenAI com o opencode. A maior } } } - } - } } } ``` @@ -1856,18 +1925,6 @@ Aqui está um exemplo definindo as opções `apiKey`, `headers` e `limit` do mod } } } - } - }, - "models": { - "my-model-name": { - "name": "Nome de Exibição do Meu Modelo", - "limit": { - "context": 200000, - "output": 65536 - } - } - } - } } } ``` diff --git a/packages/web/src/content/docs/pt-br/sdk.mdx b/packages/web/src/content/docs/pt-br/sdk.mdx index 672b852f6b..7fd765e4c1 100644 --- a/packages/web/src/content/docs/pt-br/sdk.mdx +++ b/packages/web/src/content/docs/pt-br/sdk.mdx @@ -117,6 +117,78 @@ try { --- +## Saída Estruturada + +Você pode solicitar uma saída JSON estruturada do modelo especificando um `format` com um esquema JSON. O modelo usará uma ferramenta `StructuredOutput` para retornar um JSON validado correspondente ao seu esquema. + +### Uso Básico + +```typescript +const result = await client.session.prompt({ + path: { id: sessionId }, + body: { + parts: [{ type: "text", text: "Research Anthropic and provide company info" }], + format: { + type: "json_schema", + schema: { + type: "object", + properties: { + company: { type: "string", description: "Company name" }, + founded: { type: "number", description: "Year founded" }, + products: { + type: "array", + items: { type: "string" }, + description: "Main products", + }, + }, + required: ["company", "founded"], + }, + }, + }, +}) + +// Acessar a saída estruturada +console.log(result.data.info.structured_output) +// { company: "Anthropic", founded: 2021, products: ["Claude", "Claude API"] } +``` + +### Tipos de Formato de Saída + +| Tipo | Descrição | +| ------------- | --------------------------------------------------------- | +| `text` | Padrão. Resposta de texto padrão (sem saída estruturada) | +| `json_schema` | Retorna JSON validado correspondente ao esquema fornecido | + +### Formato do Esquema JSON + +Ao usar `type: 'json_schema'`, forneça: + +| Campo | Tipo | Descrição | +| ------------ | --------------- | -------------------------------------------------------------- | +| `type` | `'json_schema'` | Obrigatório. Especifica o modo de esquema JSON | +| `schema` | `object` | Obrigatório. Objeto JSON Schema definindo a estrutura de saída | +| `retryCount` | `number` | Opcional. Número de tentativas de validação (padrão: 2) | + +### Tratamento de Erros + +Se o modelo falhar em produzir uma saída estruturada válida após todas as tentativas, a resposta incluirá um `StructuredOutputError`: + +```typescript +if (result.data.info.error?.name === "StructuredOutputError") { + console.error("Failed to produce structured output:", result.data.info.error.message) + console.error("Attempts:", result.data.info.error.retries) +} +``` + +### Melhores Práticas + +1. **Forneça descrições claras** nas propriedades do seu esquema para ajudar o modelo a entender quais dados extrair +2. **Use `required`** para especificar quais campos devem estar presentes +3. **Mantenha os esquemas focados** - esquemas aninhados complexos podem ser mais difíceis para o modelo preencher corretamente +4. **Defina um `retryCount` apropriado** - aumente para esquemas complexos, diminua para os simples + +--- + ## APIs O SDK expõe todas as APIs do servidor através de um cliente seguro em tipos. @@ -226,27 +298,27 @@ const { providers, default: defaults } = await client.config.providers() ### Sessões -| Método | Descrição | Notas | -| ---------------------------------------------------------- | ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | -| `session.list()` | Listar sessões | Retorna <a href={typesUrl}><code>Session[]</code></a> | -| `session.get({ path })` | Obter sessão | Retorna <a href={typesUrl}><code>Session</code></a> | -| `session.children({ path })` | Listar sessões filhas | Retorna <a href={typesUrl}><code>Session[]</code></a> | -| `session.create({ body })` | Criar sessão | Retorna <a href={typesUrl}><code>Session</code></a> | -| `session.delete({ path })` | Deletar sessão | Retorna `boolean` | -| `session.update({ path, body })` | Atualizar propriedades da sessão | Retorna <a href={typesUrl}><code>Session</code></a> | -| `session.init({ path, body })` | Analisar app e criar `AGENTS.md` | Retorna `boolean` | -| `session.abort({ path })` | Abortar uma sessão em execução | Retorna `boolean` | -| `session.share({ path })` | Compartilhar sessão | Retorna <a href={typesUrl}><code>Session</code></a> | -| `session.unshare({ path })` | Descompartilhar sessão | Retorna <a href={typesUrl}><code>Session</code></a> | -| `session.summarize({ path, body })` | Resumir sessão | Retorna `boolean` | -| `session.messages({ path })` | Listar mensagens em uma sessão | Retorna `{ info: `<a href={typesUrl}><code>Message</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}[]` | -| `session.message({ path })` | Obter detalhes da mensagem | Retorna `{ info: `<a href={typesUrl}><code>Message</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}` | -| `session.prompt({ path, body })` | Enviar mensagem de prompt | `body.noReply: true` retorna UserMessage (apenas contexto). O padrão retorna <a href={typesUrl}><code>AssistantMessage</code></a> com resposta da AI | -| `session.command({ path, body })` | Enviar comando para a sessão | Retorna `{ info: `<a href={typesUrl}><code>AssistantMessage</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}` | -| `session.shell({ path, body })` | Executar um comando shell | Retorna <a href={typesUrl}><code>AssistantMessage</code></a> | -| `session.revert({ path, body })` | Reverter uma mensagem | Retorna <a href={typesUrl}><code>Session</code></a> | -| `session.unrevert({ path })` | Restaurar mensagens revertidas | Retorna <a href={typesUrl}><code>Session</code></a> | -| `postSessionByIdPermissionsByPermissionId({ path, body })` | Responder a um pedido de permissão | Retorna `boolean` | +| Método | Descrição | Notas | +| ---------------------------------------------------------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `session.list()` | Listar sessões | Retorna <a href={typesUrl}><code>Session[]</code></a> | +| `session.get({ path })` | Obter sessão | Retorna <a href={typesUrl}><code>Session</code></a> | +| `session.children({ path })` | Listar sessões filhas | Retorna <a href={typesUrl}><code>Session[]</code></a> | +| `session.create({ body })` | Criar sessão | Retorna <a href={typesUrl}><code>Session</code></a> | +| `session.delete({ path })` | Deletar sessão | Retorna `boolean` | +| `session.update({ path, body })` | Atualizar propriedades da sessão | Retorna <a href={typesUrl}><code>Session</code></a> | +| `session.init({ path, body })` | Analisar app e criar `AGENTS.md` | Retorna `boolean` | +| `session.abort({ path })` | Abortar uma sessão em execução | Retorna `boolean` | +| `session.share({ path })` | Compartilhar sessão | Retorna <a href={typesUrl}><code>Session</code></a> | +| `session.unshare({ path })` | Descompartilhar sessão | Retorna <a href={typesUrl}><code>Session</code></a> | +| `session.summarize({ path, body })` | Resumir sessão | Retorna `boolean` | +| `session.messages({ path })` | Listar mensagens em uma sessão | Retorna `{ info: `<a href={typesUrl}><code>Message</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}[]` | +| `session.message({ path })` | Obter detalhes da mensagem | Retorna `{ info: `<a href={typesUrl}><code>Message</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}` | +| `session.prompt({ path, body })` | Enviar mensagem de prompt | `body.noReply: true` retorna UserMessage (apenas contexto). O padrão retorna <a href={typesUrl}><code>AssistantMessage</code></a> com resposta da AI. Suporta `body.outputFormat` para [saída estruturada](#saída-estruturada) | +| `session.command({ path, body })` | Enviar comando para a sessão | Retorna `{ info: `<a href={typesUrl}><code>AssistantMessage</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}` | +| `session.shell({ path, body })` | Executar um comando shell | Retorna <a href={typesUrl}><code>AssistantMessage</code></a> | +| `session.revert({ path, body })` | Reverter uma mensagem | Retorna <a href={typesUrl}><code>Session</code></a> | +| `session.unrevert({ path })` | Restaurar mensagens revertidas | Retorna <a href={typesUrl}><code>Session</code></a> | +| `postSessionByIdPermissionsByPermissionId({ path, body })` | Responder a um pedido de permissão | Retorna `boolean` | --- diff --git a/packages/web/src/content/docs/pt-br/share.mdx b/packages/web/src/content/docs/pt-br/share.mdx index 5aa0439d06..166226d6dc 100644 --- a/packages/web/src/content/docs/pt-br/share.mdx +++ b/packages/web/src/content/docs/pt-br/share.mdx @@ -41,7 +41,7 @@ Para definir explicitamente o modo manual em seu [arquivo de configuração](/do ```json title="opencode.json" { - "$schema": "https://opncd.ai/config.json", + "$schema": "https://opencode.ai/config.json", "share": "manual" } ``` @@ -54,7 +54,7 @@ Você pode habilitar o compartilhamento automático para todas as novas conversa ```json title="opencode.json" { - "$schema": "https://opncd.ai/config.json", + "$schema": "https://opencode.ai/config.json", "share": "auto" } ``` @@ -69,7 +69,7 @@ Você pode desativar o compartilhamento completamente definindo a opção `share ```json title="opencode.json" { - "$schema": "https://opncd.ai/config.json", + "$schema": "https://opencode.ai/config.json", "share": "disabled" } ``` diff --git a/packages/web/src/content/docs/pt-br/themes.mdx b/packages/web/src/content/docs/pt-br/themes.mdx index a1a5083cb8..5706d6e836 100644 --- a/packages/web/src/content/docs/pt-br/themes.mdx +++ b/packages/web/src/content/docs/pt-br/themes.mdx @@ -61,11 +61,11 @@ O tema do sistema é para usuários que: ## Usando um tema -Você pode selecionar um tema chamando a seleção de tema com o comando `/theme`. Ou você pode especificá-lo em sua [configuração](/docs/config). +Você pode selecionar um tema chamando a seleção de tema com o comando `/theme`. Ou você pode especificá-lo em `tui.json`. -```json title="opencode.json" {3} +```json title="tui.json" {3} { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "theme": "tokyonight" } ``` diff --git a/packages/web/src/content/docs/pt-br/tui.mdx b/packages/web/src/content/docs/pt-br/tui.mdx index 17b9c7de0b..67de2138b6 100644 --- a/packages/web/src/content/docs/pt-br/tui.mdx +++ b/packages/web/src/content/docs/pt-br/tui.mdx @@ -234,7 +234,7 @@ Compartilhe a sessão atual. [Saiba mais](/docs/share). Liste os temas disponíveis. ```bash frame="none" -/theme +/themes ``` **Atalho:** `ctrl+x t` @@ -352,24 +352,34 @@ Alguns editores precisam de argumentos de linha de comando para rodar em modo bl ## Configuração -Você pode personalizar o comportamento do TUI através do seu arquivo de configuração do opencode. +Você pode personalizar o comportamento do TUI através de `tui.json` (ou `tui.jsonc`). -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", - "tui": { - "scroll_speed": 3, - "scroll_acceleration": { - "enabled": true - } - } + "$schema": "https://opencode.ai/tui.json", + "theme": "opencode", + "keybinds": { + "leader": "ctrl+x" + }, + "scroll_speed": 3, + "scroll_acceleration": { + "enabled": true + }, + "diff_style": "auto" } ``` +Isso é separado do `opencode.json`, que configura o comportamento do servidor/runtime. + ### Opções -- `scroll_acceleration` - Ative a aceleração de rolagem no estilo macOS para uma rolagem suave e natural. Quando ativado, a velocidade de rolagem aumenta com gestos de rolagem rápidos e permanece precisa para movimentos mais lentos. **Esta configuração tem precedência sobre `scroll_speed` e a substitui quando ativada.** -- `scroll_speed` - Controla quão rápido o TUI rola ao usar comandos de rolagem (mínimo: `1`). O padrão é `3`. **Nota: Isso é ignorado se `scroll_acceleration.enabled` estiver definido como `true`.** +- `theme` - Define o tema da sua interface. [Saiba mais](/docs/themes). +- `keybinds` - Personaliza atalhos de teclado. [Saiba mais](/docs/keybinds). +- `scroll_acceleration.enabled` - Ative a aceleração de rolagem no estilo macOS para uma rolagem suave e natural. Quando ativado, a velocidade de rolagem aumenta com gestos de rolagem rápidos e permanece precisa para movimentos mais lentos. **Esta configuração tem precedência sobre `scroll_speed` e a substitui quando ativada.** +- `scroll_speed` - Controla quão rápido o TUI rola ao usar comandos de rolagem (mínimo: `0.001`, suporta valores decimais). O padrão é `3`. **Nota: Isso é ignorado se `scroll_acceleration.enabled` estiver definido como `true`.** +- `diff_style` - Controla a renderização de diffs. `"auto"` se adapta à largura do terminal, `"stacked"` sempre mostra um layout de coluna única. + +Use `OPENCODE_TUI_CONFIG` para carregar um caminho de configuração TUI personalizado. --- diff --git a/packages/web/src/content/docs/pt-br/zen.mdx b/packages/web/src/content/docs/pt-br/zen.mdx index 203f0b3f9d..1ed92cbd78 100644 --- a/packages/web/src/content/docs/pt-br/zen.mdx +++ b/packages/web/src/content/docs/pt-br/zen.mdx @@ -1,19 +1,19 @@ --- title: Zen -description: Lista selecionada de modelos fornecidos pelo opencode. +description: Lista selecionada de modelos fornecidos pelo OpenCode. --- import config from "../../../../config.mjs" export const console = config.console export const email = `mailto:${config.email}` -O OpenCode Zen é uma lista de modelos testados e verificados fornecidos pela equipe do opencode. +O OpenCode Zen é uma lista de modelos testados e verificados fornecidos pela equipe do OpenCode. :::note O OpenCode Zen está atualmente em beta. ::: -O Zen funciona como qualquer outro provedor no opencode. Você faz login no OpenCode Zen e obtém sua chave de API. É **completamente opcional** e você não precisa usá-lo para utilizar o opencode. +O Zen funciona como qualquer outro provedor no OpenCode. Você faz login no OpenCode Zen e obtém sua chave de API. É **completamente opcional** e você não precisa usá-lo para utilizar o OpenCode. --- @@ -22,7 +22,7 @@ O Zen funciona como qualquer outro provedor no opencode. Você faz login no Open Existe um grande número de modelos disponíveis, mas apenas alguns desses modelos funcionam bem como agentes de codificação. Além disso, a maioria dos provedores é configurada de maneira muito diferente; portanto, você obtém desempenhos e qualidades muito diferentes. :::tip -Testamos um grupo selecionado de modelos e provedores que funcionam bem com o opencode. +Testamos um grupo selecionado de modelos e provedores que funcionam bem com o OpenCode. ::: Portanto, se você estiver usando um modelo através de algo como OpenRouter, você nunca pode ter certeza se está obtendo a melhor versão do modelo que deseja. @@ -39,7 +39,7 @@ O OpenCode Zen é um gateway de IA que lhe dá acesso a esses modelos. ## Como funciona -O OpenCode Zen funciona como qualquer outro provedor no opencode. +O OpenCode Zen funciona como qualquer outro provedor no OpenCode. 1. Você faz login no **<a href={console}>OpenCode Zen</a>**, adiciona seus dados de cobrança e copia sua chave de API. 2. Você executa o comando `/connect` no TUI, seleciona OpenCode Zen e cola sua chave de API. @@ -55,6 +55,8 @@ Você também pode acessar nossos modelos através dos seguintes endpoints da AP | Modelo | ID do Modelo | Endpoint | Pacote AI SDK | | ------------------ | ------------------ | -------------------------------------------------- | --------------------------- | +| GPT 5.4 | gpt-5.4 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| GPT 5.3 Codex | gpt-5.3-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.2 | gpt-5.2 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.2 Codex | gpt-5.2-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.1 | gpt-5.1 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | @@ -64,28 +66,30 @@ Você também pode acessar nossos modelos através dos seguintes endpoints da AP | GPT 5 | gpt-5 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5 Codex | gpt-5-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5 Nano | gpt-5-nano | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| Claude Opus 4.6 | claude-opus-4-6 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Opus 4.5 | claude-opus-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Opus 4.1 | claude-opus-4-1 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Sonnet 4.6 | claude-sonnet-4-6 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Sonnet 4.5 | claude-sonnet-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Sonnet 4 | claude-sonnet-4 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Haiku 4.5 | claude-haiku-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Haiku 3.5 | claude-3-5-haiku | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| Claude Opus 4.6 | claude-opus-4-6 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| Claude Opus 4.5 | claude-opus-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| Claude Opus 4.1 | claude-opus-4-1 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Gemini 3.1 Pro | gemini-3.1-pro | `https://opencode.ai/zen/v1/models/gemini-3.1-pro` | `@ai-sdk/google` | | Gemini 3 Pro | gemini-3-pro | `https://opencode.ai/zen/v1/models/gemini-3-pro` | `@ai-sdk/google` | | Gemini 3 Flash | gemini-3-flash | `https://opencode.ai/zen/v1/models/gemini-3-flash` | `@ai-sdk/google` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.5 Free | minimax-m2.5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.1 | minimax-m2.1 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.1 Free | minimax-m2.1-free | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| GLM 5 | glm-5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | GLM 4.7 | glm-4.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM 4.7 Free | glm-4.7-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | GLM 4.6 | glm-4.6 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 Free | kimi-k2.5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2 Thinking | kimi-k2-thinking | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2 | kimi-k2 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Qwen3 Coder 480B | qwen3-coder | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Big Pickle | big-pickle | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -O [id do modelo](/docs/config/#models) na sua configuração do opencode usa o formato `opencode/<model-id>`. Por exemplo, para GPT 5.2 Codex, você usaria `opencode/gpt-5.2-codex` na sua configuração. +O [id do modelo](/docs/config/#models) na sua configuração do OpenCode usa o formato `opencode/<model-id>`. Por exemplo, para GPT 5.2 Codex, você usaria `opencode/gpt-5.2-codex` na sua configuração. --- @@ -106,29 +110,35 @@ Nós suportamos um modelo de pagamento conforme o uso. Abaixo estão os preços | Modelo | Entrada | Saída | Leitura em Cache | Escrita em Cache | | --------------------------------- | ------- | ------ | ---------------- | ---------------- | | Big Pickle | Grátis | Grátis | Grátis | - | -| MiniMax M2.1 Free | Grátis | Grátis | Grátis | - | +| MiniMax M2.5 Free | Grátis | Grátis | Grátis | - | +| MiniMax M2.5 | $0.30 | $1.20 | $0.06 | - | | MiniMax M2.1 | $0.30 | $1.20 | $0.10 | - | -| GLM 4.7 Free | Grátis | Grátis | Grátis | - | +| GLM 5 | $1.00 | $3.20 | $0.20 | - | | GLM 4.7 | $0.60 | $2.20 | $0.10 | - | | GLM 4.6 | $0.60 | $2.20 | $0.10 | - | -| Kimi K2.5 Free | Grátis | Grátis | Grátis | - | | Kimi K2.5 | $0.60 | $3.00 | $0.08 | - | | Kimi K2 Thinking | $0.40 | $2.50 | - | - | | Kimi K2 | $0.40 | $2.50 | - | - | | Qwen3 Coder 480B | $0.45 | $1.50 | - | - | +| Claude Opus 4.6 (≤ 200K tokens) | $5.00 | $25.00 | $0.50 | $6.25 | +| Claude Opus 4.6 (> 200K tokens) | $10.00 | $37.50 | $1.00 | $12.50 | +| Claude Opus 4.5 | $5.00 | $25.00 | $0.50 | $6.25 | +| Claude Opus 4.1 | $15.00 | $75.00 | $1.50 | $18.75 | +| Claude Sonnet 4.6 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 | +| Claude Sonnet 4.6 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 | | Claude Sonnet 4.5 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 | | Claude Sonnet 4.5 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 | | Claude Sonnet 4 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 | | Claude Sonnet 4 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 | | Claude Haiku 4.5 | $1.00 | $5.00 | $0.10 | $1.25 | | Claude Haiku 3.5 | $0.80 | $4.00 | $0.08 | $1.00 | -| Claude Opus 4.6 (≤ 200K tokens) | $5.00 | $25.00 | $0.50 | $6.25 | -| Claude Opus 4.6 (> 200K tokens) | $10.00 | $37.50 | $1.00 | $12.50 | -| Claude Opus 4.5 | $5.00 | $25.00 | $0.50 | $6.25 | -| Claude Opus 4.1 | $15.00 | $75.00 | $1.50 | $18.75 | +| Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | +| Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | | Gemini 3 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | +| GPT 5.4 | $2.50 | $15.00 | $0.25 | - | +| GPT 5.3 Codex | $1.75 | $14.00 | $0.175 | - | | GPT 5.2 | $1.75 | $14.00 | $0.175 | - | | GPT 5.2 Codex | $1.75 | $14.00 | $0.175 | - | | GPT 5.1 | $1.07 | $8.50 | $0.107 | - | @@ -147,10 +157,8 @@ As taxas de cartão de crédito são repassadas ao custo (4,4% + $0,30 por trans Os modelos gratuitos: -- GLM 4.7 Free está disponível no opencode por tempo limitado. A equipe está usando esse tempo para coletar feedback e melhorar o modelo. -- Kimi K2.5 Free está disponível no opencode por tempo limitado. A equipe está usando esse tempo para coletar feedback e melhorar o modelo. -- MiniMax M2.1 Free está disponível no opencode por tempo limitado. A equipe está usando esse tempo para coletar feedback e melhorar o modelo. -- Big Pickle é um modelo oculto que está gratuito no opencode por tempo limitado. A equipe está usando esse tempo para coletar feedback e melhorar o modelo. +- MiniMax M2.5 Free está disponível no OpenCode por tempo limitado. A equipe está usando esse tempo para coletar feedback e melhorar o modelo. +- Big Pickle é um modelo oculto que está gratuito no OpenCode por tempo limitado. A equipe está usando esse tempo para coletar feedback e melhorar o modelo. <a href={email}>Entre em contato conosco</a> se você tiver alguma dúvida. @@ -172,14 +180,25 @@ Por exemplo, digamos que você defina um limite de uso mensal de $20, o Zen não --- +### Modelos obsoletos + +| Modelo | Data de descontinuação | +| ---------------- | ---------------------- | +| Qwen3 Coder 480B | 6 de fev. de 2026 | +| Kimi K2 Thinking | 6 de mar. de 2026 | +| Kimi K2 | 6 de mar. de 2026 | +| MiniMax M2.1 | 15 de mar. de 2026 | +| GLM 4.7 | 15 de mar. de 2026 | +| GLM 4.6 | 15 de mar. de 2026 | + +--- + ## Privacidade Todos os nossos modelos estão hospedados nos EUA. Nossos provedores seguem uma política de zero retenção e não usam seus dados para treinamento de modelos, com as seguintes exceções: - Big Pickle: Durante seu período gratuito, os dados coletados podem ser usados para melhorar o modelo. -- GLM 4.7 Free: Durante seu período gratuito, os dados coletados podem ser usados para melhorar o modelo. -- Kimi K2.5 Free: Durante seu período gratuito, os dados coletados podem ser usados para melhorar o modelo. -- MiniMax M2.1 Free: Durante seu período gratuito, os dados coletados podem ser usados para melhorar o modelo. +- MiniMax M2.5 Free: Durante seu período gratuito, os dados coletados podem ser usados para melhorar o modelo. - APIs da OpenAI: As solicitações são retidas por 30 dias de acordo com as [Políticas de Dados da OpenAI](https://platform.openai.com/docs/guides/your-data). - APIs da Anthropic: As solicitações são retidas por 30 dias de acordo com as [Políticas de Dados da Anthropic](https://docs.anthropic.com/en/docs/claude-code/data-usage). @@ -233,4 +252,4 @@ Criamos o OpenCode Zen para: 1. **Benchmark** os melhores modelos/provedores para agentes de codificação. 2. Ter acesso às opções de **mais alta qualidade** e não degradar o desempenho ou redirecionar para provedores mais baratos. 3. Repassar quaisquer **reduções de preço** vendendo ao custo; assim, a única margem é para cobrir nossas taxas de processamento. -4. Não ter **vinculação** permitindo que você o use com qualquer outro agente de codificação. E sempre permitir que você use qualquer outro provedor com o opencode também. +4. Não ter **vinculação** permitindo que você o use com qualquer outro agente de codificação. E sempre permitir que você use qualquer outro provedor com o OpenCode também. diff --git a/packages/web/src/content/docs/ru/cli.mdx b/packages/web/src/content/docs/ru/cli.mdx index 1a1003a63a..5fa85a18fc 100644 --- a/packages/web/src/content/docs/ru/cli.mdx +++ b/packages/web/src/content/docs/ru/cli.mdx @@ -558,6 +558,7 @@ opencode можно настроить с помощью переменных с | `OPENCODE_AUTO_SHARE` | логическое значение | Автоматически делиться сеансами | | `OPENCODE_GIT_BASH_PATH` | строка | Путь к исполняемому файлу Git Bash в Windows | | `OPENCODE_CONFIG` | строка | Путь к файлу конфигурации | +| `OPENCODE_TUI_CONFIG` | строка | Путь к файлу конфигурации TUI | | `OPENCODE_CONFIG_DIR` | строка | Путь к каталогу конфигурации | | `OPENCODE_CONFIG_CONTENT` | строка | Встроенное содержимое конфигурации json | | `OPENCODE_DISABLE_AUTOUPDATE` | логическое значение | Отключить автоматическую проверку обновлений | diff --git a/packages/web/src/content/docs/ru/config.mdx b/packages/web/src/content/docs/ru/config.mdx index 14af31cfd7..5d91dc5e01 100644 --- a/packages/web/src/content/docs/ru/config.mdx +++ b/packages/web/src/content/docs/ru/config.mdx @@ -97,6 +97,8 @@ opencode поддерживает форматы **JSON** и **JSONC** (JSON с Поместите глобальную конфигурацию opencode в `~/.config/opencode/opencode.json`. Используйте глобальную конфигурацию для общепользовательских настроек, таких как темы, поставщики или привязки клавиш. +Для настроек, специфичных для TUI, используйте `~/.config/opencode/tui.json`. + Глобальная конфигурация переопределяет настройки по умолчанию для удаленной организации. --- @@ -105,6 +107,8 @@ opencode поддерживает форматы **JSON** и **JSONC** (JSON с Добавьте `opencode.json` в корень вашего проекта. Конфигурация проекта имеет наивысший приоритет среди стандартных файлов конфигурации — она переопределяет как глобальные, так и удаленные конфигурации. +Для настроек TUI, специфичных для проекта, добавьте `tui.json` рядом с ним. + :::tip Поместите конфигурацию конкретного проекта в корень вашего проекта. ::: @@ -145,34 +149,32 @@ opencode run "Hello world" Файл конфигурации имеет схему, определенную в [**`opencode.ai/config.json`**](https://opencode.ai/config.json). +Конфигурация TUI использует [**`opencode.ai/tui.json`**](https://opencode.ai/tui.json). + Ваш редактор должен иметь возможность проверять и автозаполнять данные на основе схемы. --- ### TUI -Вы можете настроить параметры TUI с помощью опции `tui`. +Используйте специальный файл `tui.json` (или `tui.jsonc`) для настроек, специфичных для TUI. -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", - "tui": { - "scroll_speed": 3, - "scroll_acceleration": { - "enabled": true - }, - "diff_style": "auto" - } + "$schema": "https://opencode.ai/tui.json", + "scroll_speed": 3, + "scroll_acceleration": { + "enabled": true + }, + "diff_style": "auto" } ``` -Доступные варианты: +Используйте `OPENCODE_TUI_CONFIG`, чтобы указать на пользовательский файл конфигурации TUI. -- `scroll_acceleration.enabled` — включить ускорение прокрутки в стиле MacOS. **Имеет приоритет над `scroll_speed`.** -- `scroll_speed` — пользовательский множитель скорости прокрутки (по умолчанию: `3`, минимум: `1`). Игнорируется, если `scroll_acceleration.enabled` равен `true`. -- `diff_style` — управление рендерингом различий. `"auto"` адаптируется к ширине terminal, `"stacked"` всегда отображает один столбец. +Устаревшие ключи `theme`, `keybinds` и `tui` в `opencode.json` устарели и автоматически переносятся, когда это возможно. -[Подробнее об использовании TUI можно узнать здесь](/docs/tui). +[Подробнее об использовании TUI можно узнать здесь](/docs/tui#configure). --- @@ -298,12 +300,12 @@ Amazon Bedrock поддерживает конфигурацию, специфи ### theme -Вы можете настроить тему, которую хотите использовать, в конфигурации opencode с помощью опции `theme`. +Установите тему пользовательского интерфейса в `tui.json`. -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", - "theme": "" + "$schema": "https://opencode.ai/tui.json", + "theme": "tokyonight" } ``` @@ -403,11 +405,11 @@ Amazon Bedrock поддерживает конфигурацию, специфи ### Сочетания клавиш -Вы можете настроить привязки клавиш с помощью опции `keybinds`. +Настройте привязки клавиш в `tui.json`. -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "keybinds": {} } ``` @@ -487,13 +489,15 @@ opencode автоматически загрузит все новые обно "$schema": "https://opencode.ai/config.json", "compaction": { "auto": true, - "prune": true + "prune": true, + "reserved": 10000 } } ``` - `auto` — автоматически сжимать сеанс при заполнении контекста (по умолчанию: `true`). - `prune` — удалить старые выходные данные инструмента для сохранения токенов (по умолчанию: `true`). +- `reserved` — Буфер токенов для сжатия. Оставляет достаточное окно, чтобы избежать переполнения во время сжатия. --- diff --git a/packages/web/src/content/docs/ru/ecosystem.mdx b/packages/web/src/content/docs/ru/ecosystem.mdx index a278043611..e0068ead2c 100644 --- a/packages/web/src/content/docs/ru/ecosystem.mdx +++ b/packages/web/src/content/docs/ru/ecosystem.mdx @@ -1,12 +1,12 @@ --- title: Экосистема -description: Проекты и интеграции, созданные с помощью opencode. +description: Проекты и интеграции, созданные с помощью OpenCode. --- -Коллекция проектов сообщества, построенных на opencode. +Коллекция проектов сообщества, построенных на OpenCode. :::note -Хотите добавить свой проект, связанный с opencode, в этот список? Разместите PR. +Хотите добавить свой проект, связанный с OpenCode, в этот список? Разместите PR. ::: Вы также можете посетить [awesome-opencode](https://github.com/awesome-opencode/awesome-opencode) и [opencode.cafe](https://opencode.cafe) — хаб, объединяющий экосистему и сообщество. @@ -15,61 +15,64 @@ description: Проекты и интеграции, созданные с по ## Плагины -| Имя | Описание | -| --------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | -| [opencode-daytona](https://github.com/jamesmurdza/daytona/blob/main/guides/typescript/opencode/README.md) | Автоматически запускайте сеансы opencode в изолированных песочницах Daytona с синхронизацией git и предварительным просмотром в реальном времени. | -| [opencode-helicone-session](https://github.com/H2Shami/opencode-helicone-session) | Автоматически внедрять заголовки сеансов Helicone для группировки запросов. | -| [opencode-type-inject](https://github.com/nick-vi/opencode-type-inject) | Автоматическое внедрение типов TypeScript/Svelte в файлы, считываемые с помощью инструментов поиска. | -| [opencode-openai-codex-auth](https://github.com/numman-ali/opencode-openai-codex-auth) | Используйте подписку ChatGPT Plus/Pro вместо кредитов API. | -| [opencode-gemini-auth](https://github.com/jenslys/opencode-gemini-auth) | Используйте существующий план Gemini вместо выставления счетов через API. | -| [opencode-antigravity-auth](https://github.com/NoeFabris/opencode-antigravity-auth) | Используйте бесплатные модели Antigravity вместо выставления счетов через API. | -| [opencode-devcontainers](https://github.com/athal7/opencode-devcontainers) | Многоветвевая изоляция контейнеров разработки с мелкими клонами и автоматическим назначением портов. | -| [opencode-google-antigravity-auth](https://github.com/shekohex/opencode-google-antigravity-auth) | Плагин Google Antigravity OAuth с поддержкой поиска Google и более надежной обработкой API. | -| [opencode-dynamic-context-pruning](https://github.com/Tarquinen/opencode-dynamic-context-pruning) | Оптимизируйте использование токенов за счет сокращения выходных данных устаревших инструментов. | -| [opencode-websearch-cited](https://github.com/ghoulr/opencode-websearch-cited.git) | Добавьте встроенную поддержку веб-поиска для поддерживаемых поставщиков в стиле Google. | -| [opencode-pty](https://github.com/shekohex/opencode-pty.git) | Позволяет агентам ИИ запускать фоновые процессы в PTY и отправлять им интерактивные данные. | -| [opencode-shell-strategy](https://github.com/JRedeker/opencode-shell-strategy) | Инструкции для неинтерактивных shell-команд — предотвращают зависания из-за операций, зависящих от TTY. | -| [opencode-wakatime](https://github.com/angristan/opencode-wakatime) | Отслеживайте использование opencode с помощью Wakatime | -| [opencode-md-table-formatter](https://github.com/franlol/opencode-md-table-formatter/tree/main) | Очистка таблиц Markdown, созданных LLM | -| [opencode-morph-fast-apply](https://github.com/JRedeker/opencode-morph-fast-apply) | Редактирование кода в 10 раз быстрее с помощью API Morph Fast Apply и маркеров отложенного редактирования. | -| [oh-my-opencode](https://github.com/code-yeongyu/oh-my-opencode) | Фоновые агенты, встроенные инструменты LSP/AST/MCP, курируемые агенты, совместимость с Claude Code | -| [opencode-notificator](https://github.com/panta82/opencode-notificator) | Уведомления на рабочем столе и звуковые оповещения для сеансов opencode | -| [opencode-notifier](https://github.com/mohak34/opencode-notifier) | Уведомления на рабочем столе и звуковые оповещения о разрешениях, завершении и событиях ошибок. | -| [opencode-zellij-namer](https://github.com/24601/opencode-zellij-namer) | Автоматическое именование сеансов Zellij на основе искусственного интеллекта на основе контекста opencode. | -| [opencode-skillful](https://github.com/zenobi-us/opencode-skillful) | Разрешить агентам opencode отложенную загрузку подсказок по требованию с обнаружением и внедрением навыков. | -| [opencode-supermemory](https://github.com/supermemoryai/opencode-supermemory) | Постоянная память между сеансами с использованием Supermemory | -| [@plannotator/opencode](https://github.com/backnotprop/plannotator/tree/main/apps/opencode-plugin) | Интерактивный обзор плана с визуальными аннотациями и возможностью совместного использования в частном или автономном режиме. | -| [@openspoon/subtask2](https://github.com/spoons-and-mirrors/subtask2) | Расширьте opencode/команды до мощной системы оркестровки с детальным управлением потоком данных. | -| [opencode-scheduler](https://github.com/different-ai/opencode-scheduler) | Планируйте повторяющиеся задания с помощью launchd (Mac) или systemd (Linux) с синтаксисом cron. | -| [micode](https://github.com/vtemian/micode) | Структурированный мозговой штурм → План → Реализация рабочего процесса с непрерывностью сеанса | -| [octto](https://github.com/vtemian/octto) | Интерактивный пользовательский интерфейс браузера для мозгового штурма с помощью искусственного интеллекта с формами из нескольких вопросов | -| [opencode-background-agents](https://github.com/kdcokenny/opencode-background-agents) | Фоновые агенты в стиле Claude Code с асинхронным делегированием и сохранением контекста. | -| [opencode-notify](https://github.com/kdcokenny/opencode-notify) | Встроенные уведомления ОС для opencode — узнайте, когда задачи завершены | -| [opencode-workspace](https://github.com/kdcokenny/opencode-workspace) | Комплексный пакет многоагентной оркестровки — 16 компонентов, одна установка | -| [opencode-worktree](https://github.com/kdcokenny/opencode-worktree) | Рабочие деревья git с нулевым трением для opencode | +| Имя | Описание | +| -------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | +| [opencode-daytona](https://github.com/daytonaio/daytona/tree/main/libs/opencode-plugin) | Автоматически запускайте сеансы OpenCode в изолированных песочницах Daytona с синхронизацией git и предварительным просмотром в реальном времени | +| [opencode-helicone-session](https://github.com/H2Shami/opencode-helicone-session) | Автоматически внедрять заголовки сеансов Helicone для группировки запросов | +| [opencode-type-inject](https://github.com/nick-vi/opencode-type-inject) | Автоматическое внедрение типов TypeScript/Svelte в файлы, считываемые с помощью инструментов поиска | +| [opencode-openai-codex-auth](https://github.com/numman-ali/opencode-openai-codex-auth) | Используйте подписку ChatGPT Plus/Pro вместо кредитов API | +| [opencode-gemini-auth](https://github.com/jenslys/opencode-gemini-auth) | Используйте существующий план Gemini вместо выставления счетов через API | +| [opencode-antigravity-auth](https://github.com/NoeFabris/opencode-antigravity-auth) | Используйте бесплатные модели Antigravity вместо выставления счетов через API | +| [opencode-devcontainers](https://github.com/athal7/opencode-devcontainers) | Многоветвевая изоляция контейнеров разработки с мелкими клонами и автоматическим назначением портов | +| [opencode-google-antigravity-auth](https://github.com/shekohex/opencode-google-antigravity-auth) | Плагин Google Antigravity OAuth с поддержкой поиска Google и более надежной обработкой API | +| [opencode-dynamic-context-pruning](https://github.com/Tarquinen/opencode-dynamic-context-pruning) | Оптимизируйте использование токенов за счет сокращения выходных данных устаревших инструментов | +| [opencode-vibeguard](https://github.com/inkdust2021/opencode-vibeguard) | Скрывайте секреты/PII, заменяя их плейсхолдерами в стиле VibeGuard перед отправкой в LLM; восстанавливайте локально | +| [opencode-websearch-cited](https://github.com/ghoulr/opencode-websearch-cited.git) | Добавьте встроенную поддержку веб-поиска для поддерживаемых поставщиков в стиле Google | +| [opencode-pty](https://github.com/shekohex/opencode-pty.git) | Позволяет агентам ИИ запускать фоновые процессы в PTY и отправлять им интерактивные данные | +| [opencode-shell-strategy](https://github.com/JRedeker/opencode-shell-strategy) | Инструкции для неинтерактивных shell-команд — предотвращают зависания из-за операций, зависящих от TTY | +| [opencode-wakatime](https://github.com/angristan/opencode-wakatime) | Отслеживайте использование OpenCode с помощью Wakatime | +| [opencode-md-table-formatter](https://github.com/franlol/opencode-md-table-formatter/tree/main) | Очистка таблиц Markdown, созданных LLM | +| [opencode-morph-fast-apply](https://github.com/JRedeker/opencode-morph-fast-apply) | Редактирование кода в 10 раз быстрее с помощью API Morph Fast Apply и маркеров отложенного редактирования | +| [oh-my-opencode](https://github.com/code-yeongyu/oh-my-opencode) | Фоновые агенты, встроенные инструменты LSP/AST/MCP, курируемые агенты, совместимость с Claude Code | +| [opencode-notificator](https://github.com/panta82/opencode-notificator) | Уведомления на рабочем столе и звуковые оповещения для сеансов OpenCode | +| [opencode-notifier](https://github.com/mohak34/opencode-notifier) | Уведомления на рабочем столе и звуковые оповещения о разрешениях, завершении и событиях ошибок | +| [opencode-zellij-namer](https://github.com/24601/opencode-zellij-namer) | Автоматическое именование сеансов Zellij на основе искусственного интеллекта на основе контекста OpenCode | +| [opencode-skillful](https://github.com/zenobi-us/opencode-skillful) | Разрешить агентам OpenCode отложенную загрузку подсказок по требованию с обнаружением и внедрением навыков | +| [opencode-supermemory](https://github.com/supermemoryai/opencode-supermemory) | Постоянная память между сеансами с использованием Supermemory | +| [@plannotator/opencode](https://github.com/backnotprop/plannotator/tree/main/apps/opencode-plugin) | Интерактивный обзор плана с визуальными аннотациями и возможностью совместного использования в частном или автономном режиме | +| [@openspoon/subtask2](https://github.com/spoons-and-mirrors/subtask2) | Расширьте opencode/команды до мощной системы оркестровки с детальным управлением потоком данных | +| [opencode-scheduler](https://github.com/different-ai/opencode-scheduler) | Планируйте повторяющиеся задания с помощью launchd (Mac) или systemd (Linux) с синтаксисом cron | +| [micode](https://github.com/vtemian/micode) | Структурированный мозговой штурм → План → Реализация рабочего процесса с непрерывностью сеанса | +| [octto](https://github.com/vtemian/octto) | Интерактивный пользовательский интерфейс браузера для мозгового штурма с помощью искусственного интеллекта с формами из нескольких вопросов | +| [opencode-background-agents](https://github.com/kdcokenny/opencode-background-agents) | Фоновые агенты в стиле Claude Code с асинхронным делегированием и сохранением контекста | +| [opencode-notify](https://github.com/kdcokenny/opencode-notify) | Встроенные уведомления ОС для OpenCode – узнайте, когда задачи завершены | +| [opencode-workspace](https://github.com/kdcokenny/opencode-workspace) | Комплексный пакет многоагентной оркестровки — 16 компонентов, одна установка | +| [opencode-worktree](https://github.com/kdcokenny/opencode-worktree) | Рабочие деревья git с нулевым трением для OpenCode | +| [opencode-sentry-monitor](https://github.com/stolinski/opencode-sentry-monitor) | Отслеживайте и отлаживайте ваших ИИ-агентов с помощью Sentry AI Monitoring | --- ## Проекты -| Имя | Описание | -| ------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------- | -| [opencode.nvim](https://github.com/NickvanDyke/opencode.nvim) | Плагин Neovim для подсказок с поддержкой редактора, созданный на основе API | -| [portal](https://github.com/hosenur/portal) | Мобильный веб-интерфейс для opencode через Tailscale/VPN | -| [opencode plugin template](https://github.com/zenobi-us/opencode-plugin-template/) | Шаблон для создания плагинов opencode | -| [opencode.nvim](https://github.com/sudo-tee/opencode.nvim) | Интерфейс Neovim для opencode — агент кодирования искусственного интеллекта на базе terminal | -| [ai-sdk-provider-opencode-sdk](https://github.com/ben-vargas/ai-sdk-provider-opencode-sdk) | Поставщик Vercel AI SDK для использования opencode через @opencode-ai/sdk | -| [OpenChamber](https://github.com/btriapitsyn/openchamber) | Веб-приложение или настольное приложение и расширение VS Code для opencode | -| [OpenCode-Obsidian](https://github.com/mtymek/opencode-obsidian) | Плагин Obsidian, встраивающий opencode в пользовательский интерфейс Obsidian. | -| [OpenWork](https://github.com/different-ai/openwork) | Альтернатива Claude Cowork с открытым исходным кодом на базе opencode. | -| [ocx](https://github.com/kdcokenny/ocx) | Менеджер расширений opencode с переносимыми изолированными профилями. | -| [CodeNomad](https://github.com/NeuralNomadsAI/CodeNomad) | Настольное, веб-, мобильное и удаленное клиентское приложение для opencode | +| Имя | Описание | +| ------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------- | +| [kimaki](https://github.com/remorses/kimaki) | Discord-бот для управления сеансами OpenCode, созданный на базе SDK | +| [opencode.nvim](https://github.com/NickvanDyke/opencode.nvim) | Плагин Neovim для подсказок с поддержкой редактора, созданный на основе API | +| [portal](https://github.com/hosenur/portal) | Мобильный веб-интерфейс для OpenCode через Tailscale/VPN | +| [opencode plugin template](https://github.com/zenobi-us/opencode-plugin-template/) | Шаблон для создания плагинов OpenCode | +| [opencode.nvim](https://github.com/sudo-tee/opencode.nvim) | Интерфейс Neovim для OpenCode - агент кодирования искусственного интеллекта на базе терминала | +| [ai-sdk-provider-opencode-sdk](https://github.com/ben-vargas/ai-sdk-provider-opencode-sdk) | Поставщик Vercel AI SDK для использования OpenCode через @opencode-ai/sdk | +| [OpenChamber](https://github.com/btriapitsyn/openchamber) | Веб-приложение или настольное приложение и расширение VS Code для OpenCode | +| [OpenCode-Obsidian](https://github.com/mtymek/opencode-obsidian) | Плагин Obsidian, встраивающий OpenCode в пользовательский интерфейс Obsidian | +| [OpenWork](https://github.com/different-ai/openwork) | Альтернатива Claude Cowork с открытым исходным кодом на базе OpenCode | +| [ocx](https://github.com/kdcokenny/ocx) | Менеджер расширений OpenCode с переносимыми изолированными профилями | +| [CodeNomad](https://github.com/NeuralNomadsAI/CodeNomad) | Настольное, веб-, мобильное и удаленное клиентское приложение для OpenCode | --- ## Агенты -| Имя | Описание | -| ----------------------------------------------------------------- | -------------------------------------------------------------------------- | -| [Agentic](https://github.com/Cluster444/agentic) | Модульные ИИ-агенты и команды для структурированной разработки | -| [opencode-agents](https://github.com/darrenhinde/opencode-agents) | Конфигурации, подсказки, агенты и плагины для улучшения рабочих процессов. | +| Имя | Описание | +| ----------------------------------------------------------------- | ------------------------------------------------------------------------- | +| [Agentic](https://github.com/Cluster444/agentic) | Модульные ИИ-агенты и команды для структурированной разработки | +| [opencode-agents](https://github.com/darrenhinde/opencode-agents) | Конфигурации, подсказки, агенты и плагины для улучшения рабочих процессов | diff --git a/packages/web/src/content/docs/ru/go.mdx b/packages/web/src/content/docs/ru/go.mdx new file mode 100644 index 0000000000..17d1881f66 --- /dev/null +++ b/packages/web/src/content/docs/ru/go.mdx @@ -0,0 +1,145 @@ +--- +title: Go +description: Недорогая подписка на открытые модели для кодинга. +--- + +import config from "../../../../config.mjs" +export const console = config.console +export const email = `mailto:${config.email}` + +OpenCode Go — это недорогая подписка за **$10/месяц**, которая предоставляет надежный доступ к популярным открытым моделям для кодинга. + +:::note +OpenCode Go в настоящее время находится в бета-версии. +::: + +Go работает как любой другой провайдер в OpenCode. Вы подписываетесь на OpenCode Go и получаете свой API ключ. Это **полностью опционально**, и вам не нужно использовать его, чтобы пользоваться OpenCode. + +Он разработан в первую очередь для международных пользователей, с моделями, размещенными в США, ЕС и Сингапуре для стабильного глобального доступа. + +--- + +## Предыстория + +Открытые модели стали действительно хорошими. Теперь они достигают производительности, близкой к проприетарным моделям для задач кодинга. И поскольку многие провайдеры могут обслуживать их на конкурентной основе, они обычно намного дешевле. + +Однако получение надежного доступа к ним с низкой задержкой может быть сложным. Качество и доступность провайдеров варьируются. + +:::tip +Мы протестировали избранную группу моделей и провайдеров, которые хорошо работают с OpenCode. +::: + +Чтобы исправить это, мы сделали пару вещей: + +1. Мы протестировали избранную группу открытых моделей и поговорили с их командами о том, как лучше всего их запускать. +2. Затем мы работали с несколькими провайдерами, чтобы убедиться, что они обслуживаются правильно. +3. Наконец, мы провели бенчмаркинг комбинации модели/провайдера и составили список, который мы можем смело рекомендовать. + +OpenCode Go дает вам доступ к этим моделям за **$10/месяц**. + +--- + +## Как это работает + +OpenCode Go работает как любой другой провайдер в OpenCode. + +1. Вы входите в **<a href={console}>OpenCode Zen</a>**, подписываетесь на Go и копируете свой API ключ. +2. Вы запускаете команду `/connect` в TUI, выбираете `OpenCode Go` и вставляете свой API ключ. +3. Запустите `/models` в TUI, чтобы увидеть список моделей, доступных через Go. + +:::note +Только один участник рабочей области может подписаться на OpenCode Go. +::: + +Текущий список моделей включает: + +- **GLM-5** +- **Kimi K2.5** +- **MiniMax M2.5** + +Список моделей может меняться по мере того, как мы тестируем и добавляем новые. + +--- + +## Лимиты использования + +OpenCode Go включает следующие лимиты: + +- **5-часовой лимит** — $12 использования +- **Недельный лимит** — $30 использования +- **Месячный лимит** — $60 использования + +Лимиты определены в денежном выражении. Это означает, что ваше фактическое количество запросов зависит от модели, которую вы используете. Более дешевые модели, такие как MiniMax M2.5, позволяют делать больше запросов, в то время как более дорогие модели, такие как GLM-5, позволяют меньше. + +Таблица ниже предоставляет примерное количество запросов на основе типичных паттернов использования Go: + +| | GLM-5 | Kimi K2.5 | MiniMax M2.5 | +| ------------------- | ----- | --------- | ------------ | +| запросов за 5 часов | 1,150 | 1,850 | 30,000 | +| запросов в неделю | 2,880 | 4,630 | 75,000 | +| запросов в месяц | 5,750 | 9,250 | 150,000 | + +Оценки основаны на наблюдаемых средних паттернах запросов: + +- GLM-5 — 700 входных, 52,000 кэшированных, 150 выходных токенов на запрос +- Kimi K2.5 — 870 входных, 55,000 кэшированных, 200 выходных токенов на запрос +- MiniMax M2.5 — 300 входных, 55,000 кэшированных, 125 выходных токенов на запрос + +Вы можете отслеживать свое текущее использование в **<a href={console}>консоли</a>**. + +:::tip +Если вы достигнете лимита использования, вы можете продолжить использовать бесплатные модели. +::: + +Лимиты использования могут меняться по мере того, как мы учимся на раннем использовании и отзывах. + +--- + +### Ценообразование + +OpenCode Go — это план подписки за **$10/месяц**. Ниже приведены цены **за 1 млн токенов**. + +| Модель | Ввод | Вывод | Кэшированное чтение | +| ------------ | ----- | ----- | ------------------- | +| GLM-5 | $1.00 | $3.20 | $0.20 | +| Kimi K2.5 | $0.60 | $3.00 | $0.10 | +| MiniMax M2.5 | $0.30 | $1.20 | $0.03 | + +--- + +### Использование сверх лимитов + +Если у вас также есть кредиты на балансе Zen, вы можете включить опцию **Use balance** (Использовать баланс) в консоли. Когда она включена, Go переключится на ваш баланс Zen после того, как вы исчерпаете свои лимиты использования, вместо блокировки запросов. + +--- + +## Эндпоинты + +Вы также можете получить доступ к моделям Go через следующие API эндпоинты. + +| Модель | ID модели | Эндпоинт | Пакет AI SDK | +| ------------ | ------------ | ------------------------------------------------ | --------------------------- | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | + +[Model id](/docs/config/#models) в вашей конфигурации OpenCode использует формат `opencode-go/<model-id>`. Например, для Kimi K2.5 вы бы использовали `opencode-go/kimi-k2.5` в вашей конфигурации. + +--- + +## Конфиденциальность + +План разработан в первую очередь для международных пользователей, с моделями, размещенными в США, ЕС и Сингапуре для стабильного глобального доступа. + +<a href={email}>Свяжитесь с нами</a>, если у вас есть вопросы. + +--- + +## Цели + +Мы создали OpenCode Go, чтобы: + +1. Сделать ИИ-кодинг **доступным** большему количеству людей с недорогой подпиской. +2. Обеспечить **надежный** доступ к лучшим открытым моделям для кодинга. +3. Отобрать модели, которые **протестированы и проверены** для использования агентами кодинга. +4. Не иметь **привязки к поставщику** (no lock-in), позволяя вам использовать любого другого провайдера с OpenCode. diff --git a/packages/web/src/content/docs/ru/keybinds.mdx b/packages/web/src/content/docs/ru/keybinds.mdx index 67d191ea2c..bfd4bf0c24 100644 --- a/packages/web/src/content/docs/ru/keybinds.mdx +++ b/packages/web/src/content/docs/ru/keybinds.mdx @@ -3,11 +3,11 @@ title: Сочетания клавиш description: Настройте свои сочетания клавиш. --- -opencode имеет список сочетаний клавиш, которые вы можете настроить через конфигурацию opencode. +opencode имеет список сочетаний клавиш, которые вы можете настроить через `tui.json`. -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "keybinds": { "leader": "ctrl+x", "app_exit": "ctrl+c,ctrl+d,<leader>q", @@ -28,6 +28,7 @@ opencode имеет список сочетаний клавиш, которые "session_unshare": "none", "session_interrupt": "escape", "session_compact": "<leader>c", + "session_child_first": "<leader>down", "session_child_cycle": "<leader>right", "session_child_cycle_reverse": "<leader>left", "session_parent": "<leader>up", @@ -117,11 +118,11 @@ opencode использует клавишу `leader` для большинст ## Отключение привязки клавиш -Вы можете отключить привязку клавиш, добавив ключ в свою конфигурацию со значением «none». +Вы можете отключить привязку клавиш, добавив ключ в `tui.json` со значением «none». -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "keybinds": { "session_compact": "none" } diff --git a/packages/web/src/content/docs/ru/providers.mdx b/packages/web/src/content/docs/ru/providers.mdx index 5984c89f43..c36dfd9f78 100644 --- a/packages/web/src/content/docs/ru/providers.mdx +++ b/packages/web/src/content/docs/ru/providers.mdx @@ -57,7 +57,39 @@ OpenCode Zen — это список моделей, предоставленн Если вы новичок, мы рекомендуем начать с OpenCode Zen. ::: -1. Запустите команду `/connect` в TUI, выберите opencode и перейдите по адресу [opencode.ai/auth](https://opencode.ai/auth). +1. Запустите команду `/connect` в TUI, выберите `OpenCode Zen` и перейдите по адресу [opencode.ai/auth](https://opencode.ai/zen). + + ```txt + /connect + ``` + +2. Войдите в систему, добавьте свои платежные данные и скопируйте ключ API. + +3. Вставьте свой ключ API. + + ```txt + ┌ API key + │ + │ + └ enter + ``` + +4. Запустите `/models` в TUI, чтобы просмотреть список рекомендуемых нами моделей. + + ```txt + /models + ``` + +Он работает как любой другой поставщик в opencode и его использование совершенно необязательно. + +--- + +## OpenCode Go + +OpenCode Go — это недорогой план подписки, обеспечивающий надежный доступ к популярным открытым моделям кодирования, предоставляемым командой opencode, которые были +протестированы и проверены на хорошую работу с opencode. + +1. Запустите команду `/connect` в TUI, выберите `OpenCode Go` и перейдите по адресу [opencode.ai/auth](https://opencode.ai/zen). ```txt /connect @@ -1479,6 +1511,39 @@ SAP AI Core предоставляет доступ к более чем 40 мо --- +### STACKIT + +STACKIT AI Model Serving предоставляет полностью управляемую суверенную среду хостинга для моделей ИИ, ориентированную на LLM, таких как Llama, Mistral и Qwen, с максимальным суверенитетом данных в европейской инфраструктуре. + +1. Перейдите на [портал STACKIT](https://portal.stackit.cloud), перейдите в **AI Model Serving** и создайте токен аутентификации для своего проекта. + + :::tip + Вам необходима учетная запись клиента STACKIT, учетная запись пользователя и проект перед созданием токенов аутентификации. + ::: + +2. Запустите команду `/connect` и найдите **STACKIT**. + + ```txt + /connect + ``` + +3. Введите свой токен аутентификации STACKIT AI Model Serving. + + ```txt + ┌ API key + │ + │ + └ enter + ``` + +4. Запустите команду `/models`, чтобы выбрать одну из доступных моделей, например _Qwen3-VL 235B_ или _Llama 3.3 70B_. + + ```txt + /models + ``` + +--- + ### OVHcloud AI Endpoints 1. Перейдите к [OVHcloud Panel](https://ovh.com/manager). Перейдите в раздел `Public Cloud`, `AI & Machine Learning` > `AI Endpoints` и на вкладке `API Keys` нажмите **Создать новый ключ API**. diff --git a/packages/web/src/content/docs/ru/sdk.mdx b/packages/web/src/content/docs/ru/sdk.mdx index 1269d9fc08..0afdea1b6f 100644 --- a/packages/web/src/content/docs/ru/sdk.mdx +++ b/packages/web/src/content/docs/ru/sdk.mdx @@ -117,6 +117,78 @@ try { --- +## Структурированный вывод + +Вы можете запросить структурированный вывод JSON от модели, указав `format` со схемой JSON. Модель будет использовать инструмент `StructuredOutput` для возврата проверенного JSON, соответствующего вашей схеме. + +### Основное использование + +```typescript +const result = await client.session.prompt({ + path: { id: sessionId }, + body: { + parts: [{ type: "text", text: "Research Anthropic and provide company info" }], + format: { + type: "json_schema", + schema: { + type: "object", + properties: { + company: { type: "string", description: "Company name" }, + founded: { type: "number", description: "Year founded" }, + products: { + type: "array", + items: { type: "string" }, + description: "Main products", + }, + }, + required: ["company", "founded"], + }, + }, + }, +}) + +// Access the structured output +console.log(result.data.info.structured_output) +// { company: "Anthropic", founded: 2021, products: ["Claude", "Claude API"] } +``` + +### Типы форматов вывода + +| Тип | Описание | +| ------------- | ------------------------------------------------------------------------- | +| `text` | По умолчанию. Стандартный текстовый ответ (без структурированного вывода) | +| `json_schema` | Возвращает проверенный JSON, соответствующий предоставленной схеме | + +### Формат схемы JSON + +При использовании `type: 'json_schema'`, укажите: + +| Поле | Тип | Описание | +| ------------ | --------------- | ---------------------------------------------------------------------- | +| `type` | `'json_schema'` | Обязательно. Указывает режим схемы JSON | +| `schema` | `object` | Обязательно. Объект JSON Schema, определяющий структуру вывода | +| `retryCount` | `number` | Необязательно. Количество повторных попыток проверки (по умолчанию: 2) | + +### Обработка ошибок + +Если модель не может выдать действительный структурированный вывод после всех повторных попыток, ответ будет включать `StructuredOutputError`: + +```typescript +if (result.data.info.error?.name === "StructuredOutputError") { + console.error("Failed to produce structured output:", result.data.info.error.message) + console.error("Attempts:", result.data.info.error.retries) +} +``` + +### Лучшие практики + +1. **Предоставляйте четкие описания** в свойствах вашей схемы, чтобы помочь модели понять, какие данные извлекать +2. **Используйте `required`**, чтобы указать, какие поля должны присутствовать +3. **Делайте схемы сфокусированными** — сложные вложенные схемы могут быть труднее для правильного заполнения моделью +4. **Устанавливайте соответствующий `retryCount`** — увеличивайте для сложных схем, уменьшайте для простых + +--- + ## API SDK предоставляет все серверные API через типобезопасный клиент. @@ -226,27 +298,27 @@ const { providers, default: defaults } = await client.config.providers() ### Сессии -| Метод | Описание | Примечания | -| ---------------------------------------------------------- | ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | -| `session.list()` | List sessions | Returns <a href={typesUrl}><code>Session[]</code></a> | -| `session.get({ path })` | Get session | Returns <a href={typesUrl}><code>Session</code></a> | -| `session.children({ path })` | List child sessions | Returns <a href={typesUrl}><code>Session[]</code></a> | -| `session.create({ body })` | Create session | Returns <a href={typesUrl}><code>Session</code></a> | -| `session.delete({ path })` | Delete session | Returns `boolean` | -| `session.update({ path, body })` | Update session properties | Returns <a href={typesUrl}><code>Session</code></a> | -| `session.init({ path, body })` | Analyze app and create `AGENTS.md` | Returns `boolean` | -| `session.abort({ path })` | Abort a running session | Returns `boolean` | -| `session.share({ path })` | Share session | Returns <a href={typesUrl}><code>Session</code></a> | -| `session.unshare({ path })` | Unshare session | Returns <a href={typesUrl}><code>Session</code></a> | -| `session.summarize({ path, body })` | Summarize session | Returns `boolean` | -| `session.messages({ path })` | List messages in a session | Returns `{ info: `<a href={typesUrl}><code>Message</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}[]` | -| `session.message({ path })` | Get message details | Returns `{ info: `<a href={typesUrl}><code>Message</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}` | -| `session.prompt({ path, body })` | Send prompt message | `body.noReply: true` returns UserMessage (context only). Default returns <a href={typesUrl}><code>AssistantMessage</code></a> with AI response | -| `session.command({ path, body })` | Send command to session | Returns `{ info: `<a href={typesUrl}><code>AssistantMessage</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}` | -| `session.shell({ path, body })` | Run a shell command | Returns <a href={typesUrl}><code>AssistantMessage</code></a> | -| `session.revert({ path, body })` | Revert a message | Returns <a href={typesUrl}><code>Session</code></a> | -| `session.unrevert({ path })` | Restore reverted messages | Returns <a href={typesUrl}><code>Session</code></a> | -| `postSessionByIdPermissionsByPermissionId({ path, body })` | Respond to a permission request | Returns `boolean` | +| Метод | Описание | Примечания | +| ---------------------------------------------------------- | ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `session.list()` | List sessions | Returns <a href={typesUrl}><code>Session[]</code></a> | +| `session.get({ path })` | Get session | Returns <a href={typesUrl}><code>Session</code></a> | +| `session.children({ path })` | List child sessions | Returns <a href={typesUrl}><code>Session[]</code></a> | +| `session.create({ body })` | Create session | Returns <a href={typesUrl}><code>Session</code></a> | +| `session.delete({ path })` | Delete session | Returns `boolean` | +| `session.update({ path, body })` | Update session properties | Returns <a href={typesUrl}><code>Session</code></a> | +| `session.init({ path, body })` | Analyze app and create `AGENTS.md` | Returns `boolean` | +| `session.abort({ path })` | Abort a running session | Returns `boolean` | +| `session.share({ path })` | Share session | Returns <a href={typesUrl}><code>Session</code></a> | +| `session.unshare({ path })` | Unshare session | Returns <a href={typesUrl}><code>Session</code></a> | +| `session.summarize({ path, body })` | Summarize session | Returns `boolean` | +| `session.messages({ path })` | List messages in a session | Returns `{ info: `<a href={typesUrl}><code>Message</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}[]` | +| `session.message({ path })` | Get message details | Returns `{ info: `<a href={typesUrl}><code>Message</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}` | +| `session.prompt({ path, body })` | Send prompt message | `body.noReply: true` возвращает UserMessage (только контекст). По умолчанию возвращает <a href={typesUrl}><code>AssistantMessage</code></a> с ответом ИИ. Поддерживает `body.outputFormat` для [структурированного вывода](#структурированный-вывод) | +| `session.command({ path, body })` | Send command to session | Returns `{ info: `<a href={typesUrl}><code>AssistantMessage</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}` | +| `session.shell({ path, body })` | Run a shell command | Returns <a href={typesUrl}><code>AssistantMessage</code></a> | +| `session.revert({ path, body })` | Revert a message | Returns <a href={typesUrl}><code>Session</code></a> | +| `session.unrevert({ path })` | Restore reverted messages | Returns <a href={typesUrl}><code>Session</code></a> | +| `postSessionByIdPermissionsByPermissionId({ path, body })` | Respond to a permission request | Returns `boolean` | --- diff --git a/packages/web/src/content/docs/ru/server.mdx b/packages/web/src/content/docs/ru/server.mdx index 898789c29a..2356543dff 100644 --- a/packages/web/src/content/docs/ru/server.mdx +++ b/packages/web/src/content/docs/ru/server.mdx @@ -18,13 +18,13 @@ opencode serve [--port <number>] [--hostname <string>] [--cors <origin>] #### Параметры -| Флаг | Описание | По умолчанию | -| --------------- | ----------------------------------- | ---------------- | -| `--port` | Port to listen on | `4096` | -| `--hostname` | Hostname to listen on | `127.0.0.1` | -| `--mdns` | Enable mDNS discovery | `false` | -| `--mdns-domain` | Custom domain name for mDNS service | `opencode.local` | -| `--cors` | Additional browser origins to allow | `[]` | +| Флаг | Описание | По умолчанию | +| --------------- | ------------------------------------------- | ---------------- | +| `--port` | Порт для прослушивания | `4096` | +| `--hostname` | Имя хоста для прослушивания | `127.0.0.1` | +| `--mdns` | Включить обнаружение mDNS | `false` | +| `--mdns-domain` | Пользовательское доменное имя для mDNS | `opencode.local` | +| `--cors` | Разрешенные дополнительные источники (CORS) | `[]` | `--cors` можно передать несколько раз: @@ -89,10 +89,10 @@ For example, `http://localhost:4096/doc`. Use the spec to generate clients or in ### Глобальный -| Метод | Путь | Описание | Ответ | -| ----- | ---------------- | ------------------------------ | ------------------------------------ | -| `GET` | `/global/health` | Get server health and version | `{ healthy: true, version: string }` | -| `GET` | `/global/event` | Get global events (SSE stream) | Event stream | +| Метод | Путь | Описание | Ответ | +| ----- | ---------------- | --------------------------------------- | ------------------------------------ | +| `GET` | `/global/health` | Получить состояние и версию сервера | `{ healthy: true, version: string }` | +| `GET` | `/global/event` | Получить глобальные события (поток SSE) | Поток событий | --- @@ -100,105 +100,105 @@ For example, `http://localhost:4096/doc`. Use the spec to generate clients or in | Метод | Путь | Описание | Ответ | | ----- | ------------------ | ----------------------- | --------------------------------------------- | -| `GET` | `/project` | List all projects | <a href={typesUrl}><code>Project[]</code></a> | -| `GET` | `/project/current` | Get the current project | <a href={typesUrl}><code>Project</code></a> | +| `GET` | `/project` | Список всех проектов | <a href={typesUrl}><code>Project[]</code></a> | +| `GET` | `/project/current` | Получить текущий проект | <a href={typesUrl}><code>Project</code></a> | --- ### Путь и система контроля версий -| Метод | Путь | Описание | Ответ | -| ----- | ------- | ------------------------------------ | ------------------------------------------- | -| `GET` | `/path` | Get the current path | <a href={typesUrl}><code>Path</code></a> | -| `GET` | `/vcs` | Get VCS info for the current project | <a href={typesUrl}><code>VcsInfo</code></a> | +| Метод | Путь | Описание | Ответ | +| ----- | ------- | ---------------------------------------------- | ------------------------------------------- | +| `GET` | `/path` | Получить текущий путь | <a href={typesUrl}><code>Path</code></a> | +| `GET` | `/vcs` | Получить информацию о VCS для текущего проекта | <a href={typesUrl}><code>VcsInfo</code></a> | --- ### Экземпляр -| Метод | Путь | Описание | Ответ | -| ------ | ------------------- | ---------------------------- | --------- | -| `POST` | `/instance/dispose` | Dispose the current instance | `boolean` | +| Метод | Путь | Описание | Ответ | +| ------ | ------------------- | ------------------------- | --------- | +| `POST` | `/instance/dispose` | Удалить текущий экземпляр | `boolean` | --- ### Конфигурация -| Метод | Путь | Описание | Ответ | -| ------- | ------------------- | --------------------------------- | ---------------------------------------------------------------------------------------- | -| `GET` | `/config` | Get config info | <a href={typesUrl}><code>Config</code></a> | -| `PATCH` | `/config` | Update config | <a href={typesUrl}><code>Config</code></a> | -| `GET` | `/config/providers` | List providers and default models | `{ providers: `<a href={typesUrl}>Provider[]</a>`, default: { [key: string]: string } }` | +| Метод | Путь | Описание | Ответ | +| ------- | ------------------- | ----------------------------------------- | ---------------------------------------------------------------------------------------- | +| `GET` | `/config` | Получить информацию о конфигурации | <a href={typesUrl}><code>Config</code></a> | +| `PATCH` | `/config` | Обновить конфигурацию | <a href={typesUrl}><code>Config</code></a> | +| `GET` | `/config/providers` | Список провайдеров и моделей по умолчанию | `{ providers: `<a href={typesUrl}>Provider[]</a>`, default: { [key: string]: string } }` | --- ### Поставщик -| Метод | Путь | Описание | Ответ | -| ------ | -------------------------------- | ------------------------------------ | ----------------------------------------------------------------------------------- | -| `GET` | `/provider` | List all providers | `{ all: `<a href={typesUrl}>Provider[]</a>`, default: {...}, connected: string[] }` | -| `GET` | `/provider/auth` | Get provider authentication methods | `{ [providerID: string]: `<a href={typesUrl}>ProviderAuthMethod[]</a>` }` | -| `POST` | `/provider/{id}/oauth/authorize` | Authorize a provider using OAuth | <a href={typesUrl}><code>ProviderAuthAuthorization</code></a> | -| `POST` | `/provider/{id}/oauth/callback` | Handle OAuth callback for a provider | `boolean` | +| Метод | Путь | Описание | Ответ | +| ------ | -------------------------------- | ----------------------------------------- | ----------------------------------------------------------------------------------- | +| `GET` | `/provider` | Список всех провайдеров | `{ all: `<a href={typesUrl}>Provider[]</a>`, default: {...}, connected: string[] }` | +| `GET` | `/provider/auth` | Получить методы аутентификации провайдера | `{ [providerID: string]: `<a href={typesUrl}>ProviderAuthMethod[]</a>` }` | +| `POST` | `/provider/{id}/oauth/authorize` | Авторизация провайдера через OAuth | <a href={typesUrl}><code>ProviderAuthAuthorization</code></a> | +| `POST` | `/provider/{id}/oauth/callback` | Обработка callback OAuth для провайдера | `boolean` | --- ### Сессии -| Метод | Путь | Описание | Примечания | -| -------- | ---------------------------------------- | ------------------------------------- | ---------------------------------------------------------------------------------- | -| `GET` | `/session` | List all sessions | Returns <a href={typesUrl}><code>Session[]</code></a> | -| `POST` | `/session` | Create a new session | body: `{ parentID?, title? }`, returns <a href={typesUrl}><code>Session</code></a> | -| `GET` | `/session/status` | Get session status for all sessions | Returns `{ [sessionID: string]: `<a href={typesUrl}>SessionStatus</a>` }` | -| `GET` | `/session/:id` | Get session details | Returns <a href={typesUrl}><code>Session</code></a> | -| `DELETE` | `/session/:id` | Delete a session and all its data | Returns `boolean` | -| `PATCH` | `/session/:id` | Update session properties | body: `{ title? }`, returns <a href={typesUrl}><code>Session</code></a> | -| `GET` | `/session/:id/children` | Get a session's child sessions | Returns <a href={typesUrl}><code>Session[]</code></a> | -| `GET` | `/session/:id/todo` | Get the todo list for a session | Returns <a href={typesUrl}><code>Todo[]</code></a> | -| `POST` | `/session/:id/init` | Analyze app and create `AGENTS.md` | body: `{ messageID, providerID, modelID }`, returns `boolean` | -| `POST` | `/session/:id/fork` | Fork an existing session at a message | body: `{ messageID? }`, returns <a href={typesUrl}><code>Session</code></a> | -| `POST` | `/session/:id/abort` | Abort a running session | Returns `boolean` | -| `POST` | `/session/:id/share` | Share a session | Returns <a href={typesUrl}><code>Session</code></a> | -| `DELETE` | `/session/:id/share` | Unshare a session | Returns <a href={typesUrl}><code>Session</code></a> | -| `GET` | `/session/:id/diff` | Get the diff for this session | query: `messageID?`, returns <a href={typesUrl}><code>FileDiff[]</code></a> | -| `POST` | `/session/:id/summarize` | Summarize the session | body: `{ providerID, modelID }`, returns `boolean` | -| `POST` | `/session/:id/revert` | Revert a message | body: `{ messageID, partID? }`, returns `boolean` | -| `POST` | `/session/:id/unrevert` | Restore all reverted messages | Returns `boolean` | -| `POST` | `/session/:id/permissions/:permissionID` | Respond to a permission request | body: `{ response, remember? }`, returns `boolean` | +| Метод | Путь | Описание | Примечания | +| -------- | ---------------------------------------- | ---------------------------------------- | ------------------------------------------------------------------------------------- | +| `GET` | `/session` | Список всех сессий | Возвращает <a href={typesUrl}><code>Session[]</code></a> | +| `POST` | `/session` | Создать новую сессию | body: `{ parentID?, title? }`, возвращает <a href={typesUrl}><code>Session</code></a> | +| `GET` | `/session/status` | Получить статус всех сессий | Возвращает `{ [sessionID: string]: `<a href={typesUrl}>SessionStatus</a>` }` | +| `GET` | `/session/:id` | Получить детали сессии | Возвращает <a href={typesUrl}><code>Session</code></a> | +| `DELETE` | `/session/:id` | Удалить сессию и все её данные | Возвращает `boolean` | +| `PATCH` | `/session/:id` | Обновить свойства сессии | body: `{ title? }`, возвращает <a href={typesUrl}><code>Session</code></a> | +| `GET` | `/session/:id/children` | Получить дочерние сессии | Возвращает <a href={typesUrl}><code>Session[]</code></a> | +| `GET` | `/session/:id/todo` | Получить список задач для сессии | Возвращает <a href={typesUrl}><code>Todo[]</code></a> | +| `POST` | `/session/:id/init` | Анализ приложения и создание `AGENTS.md` | body: `{ messageID, providerID, modelID }`, возвращает `boolean` | +| `POST` | `/session/:id/fork` | Ответвление сессии от сообщения | body: `{ messageID? }`, возвращает <a href={typesUrl}><code>Session</code></a> | +| `POST` | `/session/:id/abort` | Прервать запущенную сессию | Возвращает `boolean` | +| `POST` | `/session/:id/share` | Поделиться сессией | Возвращает <a href={typesUrl}><code>Session</code></a> | +| `DELETE` | `/session/:id/share` | Отменить общий доступ к сессии | Возвращает <a href={typesUrl}><code>Session</code></a> | +| `GET` | `/session/:id/diff` | Получить diff для этой сессии | query: `messageID?`, возвращает <a href={typesUrl}><code>FileDiff[]</code></a> | +| `POST` | `/session/:id/summarize` | Суммировать сессию | body: `{ providerID, modelID }`, возвращает `boolean` | +| `POST` | `/session/:id/revert` | Отменить сообщение | body: `{ messageID, partID? }`, возвращает `boolean` | +| `POST` | `/session/:id/unrevert` | Восстановить все отмененные сообщения | Возвращает `boolean` | +| `POST` | `/session/:id/permissions/:permissionID` | Ответить на запрос разрешения | body: `{ response, remember? }`, возвращает `boolean` | --- ### Сообщения -| Метод | Путь | Описание | Примечания | -| ------ | --------------------------------- | --------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `GET` | `/session/:id/message` | List messages in a session | query: `limit?`, returns `{ info: `<a href={typesUrl}>Message</a>`, parts: `<a href={typesUrl}>Part[]</a>`}[]` | -| `POST` | `/session/:id/message` | Send a message and wait for response | body: `{ messageID?, model?, agent?, noReply?, system?, tools?, parts }`, returns `{ info: `<a href={typesUrl}>Message</a>`, parts: `<a href={typesUrl}>Part[]</a>`}` | -| `GET` | `/session/:id/message/:messageID` | Get message details | Returns `{ info: `<a href={typesUrl}>Message</a>`, parts: `<a href={typesUrl}>Part[]</a>`}` | -| `POST` | `/session/:id/prompt_async` | Send a message asynchronously (no wait) | body: same as `/session/:id/message`, returns `204 No Content` | -| `POST` | `/session/:id/command` | Execute a slash command | body: `{ messageID?, agent?, model?, command, arguments }`, returns `{ info: `<a href={typesUrl}>Message</a>`, parts: `<a href={typesUrl}>Part[]</a>`}` | -| `POST` | `/session/:id/shell` | Run a shell command | body: `{ agent, model?, command }`, returns `{ info: `<a href={typesUrl}>Message</a>`, parts: `<a href={typesUrl}>Part[]</a>`}` | +| Метод | Путь | Описание | Примечания | +| ------ | --------------------------------- | --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `GET` | `/session/:id/message` | Список сообщений в сессии | query: `limit?`, возвращает `{ info: `<a href={typesUrl}>Message</a>`, parts: `<a href={typesUrl}>Part[]</a>`}[]` | +| `POST` | `/session/:id/message` | Отправить сообщение и ждать ответа | body: `{ messageID?, model?, agent?, noReply?, system?, tools?, parts }`, возвращает `{ info: `<a href={typesUrl}>Message</a>`, parts: `<a href={typesUrl}>Part[]</a>`}` | +| `GET` | `/session/:id/message/:messageID` | Получить детали сообщения | Возвращает `{ info: `<a href={typesUrl}>Message</a>`, parts: `<a href={typesUrl}>Part[]</a>`}` | +| `POST` | `/session/:id/prompt_async` | Отправить сообщение асинхронно (без ожидания) | body: как в `/session/:id/message`, возвращает `204 No Content` | +| `POST` | `/session/:id/command` | Выполнить слэш-команду | body: `{ messageID?, agent?, model?, command, arguments }`, возвращает `{ info: `<a href={typesUrl}>Message</a>`, parts: `<a href={typesUrl}>Part[]</a>`}` | +| `POST` | `/session/:id/shell` | Запустить команду оболочки | body: `{ agent, model?, command }`, возвращает `{ info: `<a href={typesUrl}>Message</a>`, parts: `<a href={typesUrl}>Part[]</a>`}` | --- ### Команды -| Метод | Путь | Описание | Ответ | -| ----- | ---------- | ----------------- | --------------------------------------------- | -| `GET` | `/command` | List all commands | <a href={typesUrl}><code>Command[]</code></a> | +| Метод | Путь | Описание | Ответ | +| ----- | ---------- | ------------------ | --------------------------------------------- | +| `GET` | `/command` | Список всех команд | <a href={typesUrl}><code>Command[]</code></a> | --- ### Файлы -| Метод | Путь | Описание | Ответ | -| ----- | ------------------------ | ---------------------------------- | ------------------------------------------------------------------------------------------- | -| `GET` | `/find?pattern=<pat>` | Search for text in files | Array of match objects with `path`, `lines`, `line_number`, `absolute_offset`, `submatches` | -| `GET` | `/find/file?query=<q>` | Find files and directories by name | `string[]` (paths) | -| `GET` | `/find/symbol?query=<q>` | Find workspace symbols | <a href={typesUrl}><code>Symbol[]</code></a> | -| `GET` | `/file?path=<path>` | List files and directories | <a href={typesUrl}><code>FileNode[]</code></a> | -| `GET` | `/file/content?path=<p>` | Read a file | <a href={typesUrl}><code>FileContent</code></a> | -| `GET` | `/file/status` | Get status for tracked files | <a href={typesUrl}><code>File[]</code></a> | +| Метод | Путь | Описание | Ответ | +| ----- | ------------------------ | ------------------------------------ | -------------------------------------------------------------------------------------------- | +| `GET` | `/find?pattern=<pat>` | Поиск текста в файлах | Массив объектов совпадения с `path`, `lines`, `line_number`, `absolute_offset`, `submatches` | +| `GET` | `/find/file?query=<q>` | Поиск файлов и директорий по имени | `string[]` (пути) | +| `GET` | `/find/symbol?query=<q>` | Поиск символов рабочего пространства | <a href={typesUrl}><code>Symbol[]</code></a> | +| `GET` | `/file?path=<path>` | Список файлов и директорий | <a href={typesUrl}><code>FileNode[]</code></a> | +| `GET` | `/file/content?path=<p>` | Прочитать файл | <a href={typesUrl}><code>FileContent</code></a> | +| `GET` | `/file/status` | Получить статус отслеживаемых файлов | <a href={typesUrl}><code>File[]</code></a> | #### `/find/file` параметры запроса @@ -212,76 +212,76 @@ For example, `http://localhost:4096/doc`. Use the spec to generate clients or in ### Инструменты (Экспериментальные) -| Метод | Путь | Описание | Ответ | -| ----- | ------------------------------------------- | ---------------------------------------- | -------------------------------------------- | -| `GET` | `/experimental/tool/ids` | List all tool IDs | <a href={typesUrl}><code>ToolIDs</code></a> | -| `GET` | `/experimental/tool?provider=<p>&model=<m>` | List tools with JSON schemas for a model | <a href={typesUrl}><code>ToolList</code></a> | +| Метод | Путь | Описание | Ответ | +| ----- | ------------------------------------------- | ---------------------------------------------- | -------------------------------------------- | +| `GET` | `/experimental/tool/ids` | Список всех идентификаторов инструментов | <a href={typesUrl}><code>ToolIDs</code></a> | +| `GET` | `/experimental/tool?provider=<p>&model=<m>` | Список инструментов со схемами JSON для модели | <a href={typesUrl}><code>ToolList</code></a> | --- ### LSP, форматтеры и MCP -| Метод | Путь | Описание | Ответ | -| ------ | ------------ | -------------------------- | -------------------------------------------------------- | -| `GET` | `/lsp` | Get LSP server status | <a href={typesUrl}><code>LSPStatus[]</code></a> | -| `GET` | `/formatter` | Get formatter status | <a href={typesUrl}><code>FormatterStatus[]</code></a> | -| `GET` | `/mcp` | Get MCP server status | `{ [name: string]: `<a href={typesUrl}>MCPStatus</a>` }` | -| `POST` | `/mcp` | Add MCP server dynamically | body: `{ name, config }`, returns MCP status object | +| Метод | Путь | Описание | Ответ | +| ------ | ------------ | ------------------------------- | -------------------------------------------------------- | +| `GET` | `/lsp` | Получить статус сервера LSP | <a href={typesUrl}><code>LSPStatus[]</code></a> | +| `GET` | `/formatter` | Получить статус форматера | <a href={typesUrl}><code>FormatterStatus[]</code></a> | +| `GET` | `/mcp` | Получить статус сервера MCP | `{ [name: string]: `<a href={typesUrl}>MCPStatus</a>` }` | +| `POST` | `/mcp` | Добавить сервер MCP динамически | body: `{ name, config }`, возвращает статус объекта MCP | --- ### Агенты -| Метод | Путь | Описание | Ответ | -| ----- | -------- | ------------------------- | ------------------------------------------- | -| `GET` | `/agent` | List all available agents | <a href={typesUrl}><code>Agent[]</code></a> | +| Метод | Путь | Описание | Ответ | +| ----- | -------- | ----------------------------- | ------------------------------------------- | +| `GET` | `/agent` | Список всех доступных агентов | <a href={typesUrl}><code>Agent[]</code></a> | --- ### Ведение журнала -| Метод | Путь | Описание | Ответ | -| ------ | ------ | ------------------------------------------------------------ | --------- | -| `POST` | `/log` | Write log entry. Body: `{ service, level, message, extra? }` | `boolean` | +| Метод | Путь | Описание | Ответ | +| ------ | ------ | --------------------------------------------------------------------- | --------- | +| `POST` | `/log` | Записать запись в журнал. Body: `{ service, level, message, extra? }` | `boolean` | --- ### TUI -| Метод | Путь | Описание | Ответ | -| ------ | ----------------------- | ------------------------------------------- | ---------------------- | -| `POST` | `/tui/append-prompt` | Append text to the prompt | `boolean` | -| `POST` | `/tui/open-help` | Open the help dialog | `boolean` | -| `POST` | `/tui/open-sessions` | Open the session selector | `boolean` | -| `POST` | `/tui/open-themes` | Open the theme selector | `boolean` | -| `POST` | `/tui/open-models` | Open the model selector | `boolean` | -| `POST` | `/tui/submit-prompt` | Submit the current prompt | `boolean` | -| `POST` | `/tui/clear-prompt` | Clear the prompt | `boolean` | -| `POST` | `/tui/execute-command` | Execute a command (`{ command }`) | `boolean` | -| `POST` | `/tui/show-toast` | Show toast (`{ title?, message, variant }`) | `boolean` | -| `GET` | `/tui/control/next` | Wait for the next control request | Control request object | -| `POST` | `/tui/control/response` | Respond to a control request (`{ body }`) | `boolean` | +| Метод | Путь | Описание | Ответ | +| ------ | ----------------------- | ----------------------------------------------------- | ------------------------- | +| `POST` | `/tui/append-prompt` | Добавить текст в подсказку | `boolean` | +| `POST` | `/tui/open-help` | Открыть диалог помощи | `boolean` | +| `POST` | `/tui/open-sessions` | Открыть селектор сессий | `boolean` | +| `POST` | `/tui/open-themes` | Открыть селектор тем | `boolean` | +| `POST` | `/tui/open-models` | Открыть селектор моделей | `boolean` | +| `POST` | `/tui/submit-prompt` | Отправить текущую подсказку | `boolean` | +| `POST` | `/tui/clear-prompt` | Очистить подсказку | `boolean` | +| `POST` | `/tui/execute-command` | Выполнить команду (`{ command }`) | `boolean` | +| `POST` | `/tui/show-toast` | Показать уведомление (`{ title?, message, variant }`) | `boolean` | +| `GET` | `/tui/control/next` | Ожидание следующего запроса управления | Объект запроса управления | +| `POST` | `/tui/control/response` | Ответить на запрос управления (`{ body }`) | `boolean` | --- ### Авторизация -| Метод | Путь | Описание | Ответ | -| ----- | ----------- | --------------------------------------------------------------- | --------- | -| `PUT` | `/auth/:id` | Set authentication credentials. Body must match provider schema | `boolean` | +| Метод | Путь | Описание | Ответ | +| ----- | ----------- | -------------------------------------------------------------------------------------- | --------- | +| `PUT` | `/auth/:id` | Установить учетные данные аутентификации. Body должен соответствовать схеме провайдера | `boolean` | --- ### События -| Метод | Путь | Описание | Ответ | -| ----- | -------- | ----------------------------------------------------------------------------- | ------------------------- | -| `GET` | `/event` | Server-sent events stream. First event is `server.connected`, then bus events | Server-sent events stream | +| Метод | Путь | Описание | Ответ | +| ----- | -------- | --------------------------------------------------------------------------------------------- | ------------------------------------ | +| `GET` | `/event` | Поток событий, отправляемых сервером. Первое событие — `server.connected`, затем события шины | Поток событий, отправляемых сервером | --- ### Документы -| Метод | Путь | Описание | Ответ | -| ----- | ------ | ------------------------- | --------------------------- | -| `GET` | `/doc` | OpenAPI 3.1 specification | HTML page with OpenAPI spec | +| Метод | Путь | Описание | Ответ | +| ----- | ------ | ------------------------ | -------------------------------------- | +| `GET` | `/doc` | Спецификация OpenAPI 3.1 | HTML-страница со спецификацией OpenAPI | diff --git a/packages/web/src/content/docs/ru/share.mdx b/packages/web/src/content/docs/ru/share.mdx index c4df3b6a70..8982afb08d 100644 --- a/packages/web/src/content/docs/ru/share.mdx +++ b/packages/web/src/content/docs/ru/share.mdx @@ -41,7 +41,7 @@ opencode поддерживает три режима общего доступ ```json title="opencode.json" { - "$schema": "https://opncd.ai/config.json", + "$schema": "https://opencode.ai/config.json", "share": "manual" } ``` @@ -54,7 +54,7 @@ opencode поддерживает три режима общего доступ ```json title="opencode.json" { - "$schema": "https://opncd.ai/config.json", + "$schema": "https://opencode.ai/config.json", "share": "auto" } ``` @@ -69,7 +69,7 @@ opencode поддерживает три режима общего доступ ```json title="opencode.json" { - "$schema": "https://opncd.ai/config.json", + "$schema": "https://opencode.ai/config.json", "share": "disabled" } ``` diff --git a/packages/web/src/content/docs/ru/themes.mdx b/packages/web/src/content/docs/ru/themes.mdx index 2e5219e4c5..05ace2c7b8 100644 --- a/packages/web/src/content/docs/ru/themes.mdx +++ b/packages/web/src/content/docs/ru/themes.mdx @@ -61,11 +61,11 @@ opencode поставляется с несколькими встроенным ## Использование темы -Вы можете выбрать тему, вызвав выбор темы с помощью команды `/theme`. Или вы можете указать это в файле [config](/docs/config). +Вы можете выбрать тему, вызвав выбор темы с помощью команды `/theme`. Или вы можете указать это в файле [tui.json](/docs/config#tui). -```json title="opencode.json" {3} +```json title="tui.json" {3} { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "theme": "tokyonight" } ``` diff --git a/packages/web/src/content/docs/ru/tui.mdx b/packages/web/src/content/docs/ru/tui.mdx index 0134e29c48..1694908dba 100644 --- a/packages/web/src/content/docs/ru/tui.mdx +++ b/packages/web/src/content/docs/ru/tui.mdx @@ -355,24 +355,34 @@ How is auth handled in @packages/functions/src/api/index.ts? ## Настройка -Вы можете настроить поведение TUI через файл конфигурации opencode. +Вы можете настроить поведение TUI через `tui.json` (или `tui.jsonc`). -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", - "tui": { - "scroll_speed": 3, - "scroll_acceleration": { - "enabled": true - } - } + "$schema": "https://opencode.ai/tui.json", + "theme": "opencode", + "keybinds": { + "leader": "ctrl+x" + }, + "scroll_speed": 3, + "scroll_acceleration": { + "enabled": true + }, + "diff_style": "auto" } ``` +Это отдельный файл от `opencode.json`, который настраивает поведение сервера/выполнения. + ### Параметры -- `scroll_acceleration` — включите ускорение прокрутки в стиле macOS для плавной и естественной прокрутки. Если этот параметр включен, скорость прокрутки увеличивается при быстрой прокрутке и остается точной при более медленных движениях. **Этот параметр имеет приоритет над `scroll_speed` и переопределяет его, если он включен.** -- `scroll_speed` — контролирует скорость прокрутки TUI при использовании команд прокрутки (минимум: `1`). По умолчанию `3`. **Примечание. Это игнорируется, если для `scroll_acceleration.enabled` установлено значение `true`.** +- `theme` — Устанавливает тему пользовательского интерфейса. [Подробнее](/docs/themes). +- `keybinds` — Настраивает сочетания клавиш. [Подробнее](/docs/keybinds). +- `scroll_acceleration.enabled` — включите ускорение прокрутки в стиле macOS для плавной и естественной прокрутки. Если этот параметр включен, скорость прокрутки увеличивается при быстрой прокрутке и остается точной при более медленных движениях. **Этот параметр имеет приоритет над `scroll_speed` и переопределяет его, если он включен.** +- `scroll_speed` — контролирует скорость прокрутки TUI при использовании команд прокрутки (минимум: `0.001`, поддерживает десятичные значения). По умолчанию `3`. **Примечание. Это игнорируется, если для `scroll_acceleration.enabled` установлено значение `true`.** +- `diff_style` — Управляет отображением различий. `"auto"` адаптируется к ширине терминала, `"stacked"` всегда показывает одноколоночный макет. + +Используйте `OPENCODE_TUI_CONFIG` для загрузки пользовательского пути конфигурации TUI. --- diff --git a/packages/web/src/content/docs/ru/zen.mdx b/packages/web/src/content/docs/ru/zen.mdx index 3fe03a47fa..dff843d034 100644 --- a/packages/web/src/content/docs/ru/zen.mdx +++ b/packages/web/src/content/docs/ru/zen.mdx @@ -63,6 +63,8 @@ OpenCode Zen работает так же, как и любой другой п | Модель | Идентификатор модели | Конечная точка | Пакет AI SDK | | ------------------ | -------------------- | -------------------------------------------------- | --------------------------- | +| GPT 5.4 | gpt-5.4 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| GPT 5.3 Codex | gpt-5.3-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.2 | gpt-5.2 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.2 Codex | gpt-5.2-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.1 | gpt-5.1 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | @@ -72,13 +74,15 @@ OpenCode Zen работает так же, как и любой другой п | GPT 5 | gpt-5 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5 Codex | gpt-5-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5 Nano | gpt-5-nano | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| Claude Opus 4.6 | claude-opus-4-6 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Opus 4.5 | claude-opus-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Opus 4.1 | claude-opus-4-1 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Sonnet 4.6 | claude-sonnet-4-6 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Sonnet 4.5 | claude-sonnet-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Sonnet 4 | claude-sonnet-4 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Haiku 4.5 | claude-haiku-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Haiku 3.5 | claude-3-5-haiku | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| Claude Opus 4.6 | claude-opus-4-6 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| Claude Opus 4.5 | claude-opus-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| Claude Opus 4.1 | claude-opus-4-1 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Gemini 3.1 Pro | gemini-3.1-pro | `https://opencode.ai/zen/v1/models/gemini-3.1-pro` | `@ai-sdk/google` | | Gemini 3 Pro | gemini-3-pro | `https://opencode.ai/zen/v1/models/gemini-3-pro` | `@ai-sdk/google` | | Gemini 3 Flash | gemini-3-flash | `https://opencode.ai/zen/v1/models/gemini-3-flash` | `@ai-sdk/google` | | MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -86,10 +90,8 @@ OpenCode Zen работает так же, как и любой другой п | MiniMax M2.1 | minimax-m2.1 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | GLM 5 | glm-5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | GLM 4.7 | glm-4.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM 4.7 Free | glm-4.7-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | GLM 4.6 | glm-4.6 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 Free | kimi-k2.5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2 Thinking | kimi-k2-thinking | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2 | kimi-k2 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Qwen3 Coder 480B | qwen3-coder | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -123,27 +125,30 @@ https://opencode.ai/zen/v1/models | MiniMax M2.1 | $0.30 | $1.20 | $0.10 | - | | GLM 5 | $1.00 | $3.20 | $0.20 | - | | GLM 4.7 | $0.60 | $2.20 | $0.10 | - | -| GLM 4.7 | $0.60 | $2.20 | $0.10 | - | | GLM 4.6 | $0.60 | $2.20 | $0.10 | - | -| GLM 4.7 Free | Бесплатно | Бесплатно | Бесплатно | - | -| Kimi K2.5 Free | Бесплатно | Бесплатно | Бесплатно | - | | Kimi K2.5 | $0.60 | $3.00 | $0.08 | - | | Kimi K2 Thinking | $0.40 | $2.50 | - | - | | Kimi K2 | $0.40 | $2.50 | - | - | | Qwen3 Coder 480B | $0.45 | $1.50 | - | - | +| Claude Opus 4.6 (≤ 200 тыс. токенов) | $5.00 | $25.00 | $0.50 | $6.25 | +| Claude Opus 4.6 (> 200 тыс. токенов) | $10.00 | $37.50 | $1.00 | $12.50 | +| Claude Opus 4.5 | $5.00 | $25.00 | $0.50 | $6.25 | +| Claude Opus 4.1 | $15.00 | $75.00 | $1.50 | $18.75 | +| Claude Sonnet 4.6 (≤ 200 тыс. токенов) | $3.00 | $15.00 | $0.30 | $3.75 | +| Claude Sonnet 4.6 (> 200 тыс. токенов) | $6.00 | $22.50 | $0.60 | $7.50 | | Claude Sonnet 4.5 (≤ 200 тыс. токенов) | $3.00 | $15.00 | $0.30 | $3.75 | | Claude Sonnet 4.5 (> 200 тыс. токенов) | $6.00 | $22.50 | $0.60 | $7.50 | | Claude Sonnet 4 (≤ 200 тыс. токенов) | $3.00 | $15.00 | $0.30 | $3.75 | | Claude Sonnet 4 (> 200 тыс. токенов) | $6.00 | $22.50 | $0.60 | $7.50 | | Claude Haiku 4.5 | $1.00 | $5.00 | $0.10 | $1.25 | | Claude Haiku 3.5 | $0.80 | $4.00 | $0.08 | $1.00 | -| Claude Opus 4.6 (≤ 200 тыс. токенов) | $5.00 | $25.00 | $0.50 | $6.25 | -| Claude Opus 4.6 (> 200 тыс. токенов) | $10.00 | $37.50 | $1.00 | $12.50 | -| Claude Opus 4.5 | $5.00 | $25.00 | $0.50 | $6.25 | -| Claude Opus 4.1 | $15.00 | $75.00 | $1.50 | $18.75 | +| Gemini 3.1 Pro (≤ 200 тыс. токенов) | $2.00 | $12.00 | $0.20 | - | +| Gemini 3.1 Pro (> 200 тыс. токенов) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Pro (≤ 200 тыс. токенов) | $2.00 | $12.00 | $0.20 | - | | Gemini 3 Pro (> 200 тыс. токенов) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | +| GPT 5.4 | $2.50 | $15.00 | $0.25 | - | +| GPT 5.3 Codex | $1.75 | $14.00 | $0.175 | - | | GPT 5.2 | $1.75 | $14.00 | $0.175 | - | | GPT 5.2 Codex | $1.75 | $14.00 | $0.175 | - | | GPT 5.1 | $1.07 | $8.50 | $0.107 | - | @@ -162,7 +167,6 @@ https://opencode.ai/zen/v1/models Бесплатные модели: -- Kimi K2.5 Free доступен на OpenCode в течение ограниченного времени. Команда использует это время для сбора отзывов и улучшения модели. - MiniMax M2.5 Free доступен на OpenCode в течение ограниченного времени. Команда использует это время для сбора отзывов и улучшения модели. - Big Pickle — это стелс-модель, которая доступна бесплатно на OpenCode в течение ограниченного времени. Команда использует это время для сбора отзывов и улучшения модели. @@ -189,12 +193,24 @@ https://opencode.ai/zen/v1/models --- +### Устаревшие модели + +| Модель | Дата отключения | +| ---------------- | ---------------- | +| Qwen3 Coder 480B | 6 февр. 2026 г. | +| Kimi K2 Thinking | 6 марта 2026 г. | +| Kimi K2 | 6 марта 2026 г. | +| MiniMax M2.1 | 15 марта 2026 г. | +| GLM 4.7 | 15 марта 2026 г. | +| GLM 4.6 | 15 марта 2026 г. | + +--- + ## Конфиденциальность Все наши модели размещены в США. Наши поставщики придерживаются политики нулевого хранения и не используют ваши данные для обучения моделей, за следующими исключениями: - Big Pickle: во время бесплатного периода собранные данные могут быть использованы для улучшения модели. -- Kimi K2.5 Free: в течение бесплатного периода собранные данные могут использоваться для улучшения модели. - MiniMax M2.5 Free: в течение бесплатного периода собранные данные могут использоваться для улучшения модели. - API OpenAI: запросы хранятся в течение 30 дней в соответствии с [Политикой данных OpenAI](https://platform.openai.com/docs/guides/your-data). - API-интерфейсы Anthropic: запросы хранятся в течение 30 дней в соответствии с [Политикой данных Anthropic](https://docs.anthropic.com/en/docs/claude-code/data-usage). diff --git a/packages/web/src/content/docs/share.mdx b/packages/web/src/content/docs/share.mdx index 475ee08d04..b2c7933409 100644 --- a/packages/web/src/content/docs/share.mdx +++ b/packages/web/src/content/docs/share.mdx @@ -41,7 +41,7 @@ To explicitly set manual mode in your [config file](/docs/config): ```json title="opencode.json" { - "$schema": "https://opncd.ai/config.json", + "$schema": "https://opencode.ai/config.json", "share": "manual" } ``` @@ -54,7 +54,7 @@ You can enable automatic sharing for all new conversations by setting the `share ```json title="opencode.json" { - "$schema": "https://opncd.ai/config.json", + "$schema": "https://opencode.ai/config.json", "share": "auto" } ``` @@ -69,7 +69,7 @@ You can disable sharing entirely by setting the `share` option to `"disabled"` i ```json title="opencode.json" { - "$schema": "https://opncd.ai/config.json", + "$schema": "https://opencode.ai/config.json", "share": "disabled" } ``` diff --git a/packages/web/src/content/docs/th/cli.mdx b/packages/web/src/content/docs/th/cli.mdx index 60e3fac764..875f517fc2 100644 --- a/packages/web/src/content/docs/th/cli.mdx +++ b/packages/web/src/content/docs/th/cli.mdx @@ -559,6 +559,7 @@ OpenCode สามารถกำหนดค่าโดยใช้ตัว | `OPENCODE_AUTO_SHARE` | Boolean | แชร์เซสชันอัตโนมัติเมื่อสร้าง | | `OPENCODE_GIT_BASH_PATH` | String | เส้นทางไปยัง Git Bash บน Windows | | `OPENCODE_CONFIG` | String | เส้นทางไปยังไฟล์การกำหนดค่า | +| `OPENCODE_TUI_CONFIG` | String | เส้นทางไปยังไฟล์การกำหนดค่า TUI | | `OPENCODE_CONFIG_DIR` | String | เส้นทางไปยังไดเร็กทอรีการกำหนดค่า | | `OPENCODE_CONFIG_CONTENT` | String | เนื้อหาการกำหนดค่าแบบ inline JSON | | `OPENCODE_DISABLE_AUTOUPDATE` | Boolean | ปิดใช้งานการอัปเดตอัตโนมัติ | diff --git a/packages/web/src/content/docs/th/config.mdx b/packages/web/src/content/docs/th/config.mdx index 06836aca3b..c58469c77a 100644 --- a/packages/web/src/content/docs/th/config.mdx +++ b/packages/web/src/content/docs/th/config.mdx @@ -14,10 +14,11 @@ OpenCode รองรับทั้งรูปแบบ **JSON** และ **J ```jsonc title="opencode.jsonc" { "$schema": "https://opencode.ai/config.json", - // Theme configuration - "theme": "opencode", "model": "anthropic/claude-sonnet-4-5", "autoupdate": true, + "server": { + "port": 4096, + }, } ``` @@ -34,7 +35,7 @@ OpenCode รองรับทั้งรูปแบบ **JSON** และ **J ไฟล์การกำหนดค่าจะถูกรวมเข้าด้วยกัน โดยไม่มีการแทนที่ การตั้งค่าจากตำแหน่งการกำหนดค่าต่อไปนี้จะรวมกัน การกำหนดค่าในภายหลังจะแทนที่การกำหนดค่าก่อนหน้าสำหรับคีย์ที่ขัดแย้งกันเท่านั้น การตั้งค่าที่ไม่ขัดแย้งจากการกำหนดค่าทั้งหมดจะยังคงอยู่ -ตัวอย่างเช่น หากการกำหนดค่าส่วนกลางของคุณตั้งค่า `theme: "opencode"` และ `autoupdate: true` และการกำหนดค่าโปรเจ็กต์ของคุณตั้งค่า `model: "anthropic/claude-sonnet-4-5"` การกำหนดค่าสุดท้ายจะรวมการตั้งค่าทั้งสามรายการไว้ด้วย +ตัวอย่างเช่น หากการกำหนดค่าส่วนกลางของคุณตั้งค่า `autoupdate: true` และการกำหนดค่าโปรเจ็กต์ของคุณตั้งค่า `model: "anthropic/claude-sonnet-4-5"` การกำหนดค่าสุดท้ายจะรวมการตั้งค่าทั้งสองรายการไว้ด้วย --- @@ -95,7 +96,9 @@ OpenCode รองรับทั้งรูปแบบ **JSON** และ **J ### ทั่วโลก -วางการกำหนดค่า OpenCode ส่วนกลางของคุณใน `~/.config/opencode/opencode.json` ใช้การกำหนดค่าส่วนกลางสำหรับการตั้งค่าทั้งผู้ใช้ เช่น ธีม ผู้ให้บริการ หรือปุ่มลัด +วางการกำหนดค่า OpenCode ส่วนกลางของคุณใน `~/.config/opencode/opencode.json` ใช้การกำหนดค่าส่วนกลางสำหรับการตั้งค่าทั้งผู้ใช้ เช่น ผู้ให้บริการ รุ่น และสิทธิ์ + +สำหรับการตั้งค่าเฉพาะ TUI ให้ใช้ `~/.config/opencode/tui.json` การกำหนดค่าส่วนกลางจะแทนที่ค่าเริ่มต้นขององค์กรระยะไกล @@ -105,6 +108,8 @@ OpenCode รองรับทั้งรูปแบบ **JSON** และ **J เพิ่ม `opencode.json` ในรูทโปรเจ็กต์ของคุณ การกำหนดค่าโปรเจ็กต์มีความสำคัญสูงสุดในบรรดาไฟล์กำหนดค่ามาตรฐาน โดยจะแทนที่การกำหนดค่าทั้งส่วนกลางและระยะไกล +สำหรับการตั้งค่า TUI เฉพาะโครงการ ให้เพิ่ม `tui.json` ควบคู่ไปกับมัน + :::tip วางการกำหนดค่าเฉพาะโปรเจ็กต์ไว้ที่รากของโปรเจ็กต์ของคุณ ::: @@ -148,34 +153,32 @@ opencode run "Hello world" ไฟล์กำหนดค่ามีสคีมาที่กำหนดไว้ใน [**`opencode.ai/config.json`**](https://opencode.ai/config.json) +การกำหนดค่า TUI ใช้ [**`opencode.ai/tui.json`**](https://opencode.ai/tui.json) + ผู้แก้ไขของคุณควรสามารถตรวจสอบและเติมข้อความอัตโนมัติตามสคีมาได้ --- ### TUI -คุณสามารถกำหนดการตั้งค่าเฉพาะ TUI ผ่านตัวเลือก `tui` +ใช้ไฟล์ `tui.json` (หรือ `tui.jsonc`) เฉพาะสำหรับการตั้งค่าเฉพาะ TUI -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", - "tui": { - "scroll_speed": 3, - "scroll_acceleration": { - "enabled": true - }, - "diff_style": "auto" - } + "$schema": "https://opencode.ai/tui.json", + "scroll_speed": 3, + "scroll_acceleration": { + "enabled": true + }, + "diff_style": "auto" } ``` -ตัวเลือกที่มี: +ใช้ `OPENCODE_TUI_CONFIG` เพื่อชี้ไปยังไฟล์กำหนดค่า TUI ที่กำหนดเอง -- `scroll_acceleration.enabled` - ​​เปิดใช้งานการเร่งความเร็วการเลื่อนแบบ macOS **มีลำดับความสำคัญมากกว่า `scroll_speed`.** -- `scroll_speed` - ​​ตัวคูณความเร็วการเลื่อนแบบกำหนดเอง (ค่าเริ่มต้น: `3` ขั้นต่ำ: `1`) ไม่สนใจหาก `scroll_acceleration.enabled` คือ `true` -- `diff_style` - ​​ควบคุมการเรนเดอร์ต่าง `"auto"` ปรับให้เข้ากับความกว้างของ terminal `"stacked"` จะแสดงคอลัมน์เดียวเสมอ +คีย์ `theme`, `keybinds` และ `tui` แบบเดิมใน `opencode.json` เลิกใช้แล้วและจะถูกย้ายโดยอัตโนมัติเมื่อเป็นไปได้ -[เรียนรู้เพิ่มเติมเกี่ยวกับการใช้ TUI ที่นี่](/docs/tui) +[เรียนรู้เพิ่มเติมเกี่ยวกับการใช้ TUI ที่นี่](/docs/tui#configure) --- @@ -301,12 +304,12 @@ Bearer Token (`AWS_BEARER_TOKEN_BEDROCK` หรือ `/connect`) มีคว ### Themes -คุณสามารถกำหนดค่าธีมที่คุณต้องการใช้ในการกำหนดค่า OpenCode ของคุณได้ผ่านตัวเลือก `theme` +ตั้งค่าธีม UI ของคุณใน `tui.json` -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", - "theme": "" + "$schema": "https://opencode.ai/tui.json", + "theme": "tokyonight" } ``` @@ -406,11 +409,11 @@ Bearer Token (`AWS_BEARER_TOKEN_BEDROCK` หรือ `/connect`) มีคว ### คีย์ลัด -คุณสามารถปรับแต่งปุ่มลัดของคุณได้ผ่านตัวเลือก `keybinds` +ปรับแต่งปุ่มลัดใน `tui.json` -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "keybinds": {} } ``` @@ -490,13 +493,15 @@ OpenCode จะดาวน์โหลดการอัปเดตใหม "$schema": "https://opencode.ai/config.json", "compaction": { "auto": true, - "prune": true + "prune": true, + "reserved": 10000 } } ``` - `auto` - ​​กระชับเซสชันโดยอัตโนมัติเมื่อบริบทเต็ม (ค่าเริ่มต้น: `true`) - `prune` - ​​ลบเอาท์พุตเครื่องมือเก่าเพื่อบันทึก tokens (ค่าเริ่มต้น: `true`) +- `reserved` - บัฟเฟอร์โทเค็นสำหรับการบีบอัด ให้หน้าต่างเพียงพอเพื่อหลีกเลี่ยงการล้นระหว่างการบีบอัด --- diff --git a/packages/web/src/content/docs/th/custom-tools.mdx b/packages/web/src/content/docs/th/custom-tools.mdx index 28cd229cfd..c5e6385357 100644 --- a/packages/web/src/content/docs/th/custom-tools.mdx +++ b/packages/web/src/content/docs/th/custom-tools.mdx @@ -79,6 +79,32 @@ export const multiply = tool({ --- +#### ชื่อซ้ำกับเครื่องมือในตัว + +เครื่องมือแบบกำหนดเองจะถูกระบุด้วยชื่อเครื่องมือ หากเครื่องมือแบบกำหนดเองใช้ชื่อเดียวกับเครื่องมือในตัว เครื่องมือแบบกำหนดเองจะมีความสำคัญเหนือกว่า + +ตัวอย่างเช่น ไฟล์นี้จะแทนที่เครื่องมือ `bash` ในตัว: + +```ts title=".opencode/tools/bash.ts" +import { tool } from "@opencode-ai/plugin" + +export default tool({ + description: "Restricted bash wrapper", + args: { + command: tool.schema.string(), + }, + async execute(args) { + return `blocked: ${args.command}` + }, +}) +``` + +:::note +ชอบชื่อที่ไม่ซ้ำกันเว้นแต่คุณตั้งใจจะแทนที่เครื่องมือในตัว หากคุณต้องการปิดใช้งานเครื่องมือในตัวแต่ไม่ต้องการแทนที่ ให้ใช้ [permissions](/docs/permissions) +::: + +--- + ### ข้อโต้แย้ง คุณสามารถใช้ `tool.schema` ซึ่งก็คือ [Zod](https://zod.dev) เพื่อกำหนดประเภทอาร์กิวเมนต์ diff --git a/packages/web/src/content/docs/th/ecosystem.mdx b/packages/web/src/content/docs/th/ecosystem.mdx index f1630f9a2f..a1b7e90397 100644 --- a/packages/web/src/content/docs/th/ecosystem.mdx +++ b/packages/web/src/content/docs/th/ecosystem.mdx @@ -15,38 +15,40 @@ description: โปรเจ็กต์และการผสานรวม ## ปลั๊กอิน -| ชื่อ | คำอธิบาย | -| --------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | -| [opencode-daytona](https://github.com/jamesmurdza/daytona/blob/main/guides/typescript/opencode/README.md) | เรียกใช้เซสชัน OpenCode โดยอัตโนมัติในแซนด์บ็อกซ์ Daytona ที่แยกออกมาพร้อม git sync และการแสดงตัวอย่างแบบสด | -| [opencode-helicone-session](https://github.com/H2Shami/opencode-helicone-session) | แทรกส่วนหัวเซสชัน Helicone โดยอัตโนมัติสำหรับการจัดกลุ่มคำขอ | -| [opencode-type-inject](https://github.com/nick-vi/opencode-type-inject) | ฉีดประเภท TypeScript/Svelte ลงในไฟล์ที่อ่านโดยอัตโนมัติด้วยเครื่องมือค้นหา | -| [opencode-openai-codex-auth](https://github.com/numman-ali/opencode-openai-codex-auth) | ใช้การสมัครสมาชิก ChatGPT Plus/Pro แทนเครดิต API | -| [opencode-gemini-auth](https://github.com/jenslys/opencode-gemini-auth) | ใช้แผน Gemini ที่มีอยู่ของคุณแทนการเรียกเก็บเงิน API | -| [opencode-antigravity-auth](https://github.com/NoeFabris/opencode-antigravity-auth) | ใช้โมเดลฟรีของ Antigravity แทนการเรียกเก็บเงิน API | -| [opencode-devcontainers](https://github.com/athal7/opencode-devcontainers) | การแยกคอนเทนเนอร์ Devcontainer แบบหลายสาขาพร้อมโคลนแบบตื้นและพอร์ตที่กำหนดอัตโนมัติ | -| [opencode-google-antigravity-auth](https://github.com/shekohex/opencode-google-antigravity-auth) | ปลั๊กอิน Google Antigravity OAuth พร้อมรองรับ Google Search และการจัดการ API ที่แข็งแกร่งยิ่งขึ้น | -| [opencode-dynamic-context-pruning](https://github.com/Tarquinen/opencode-dynamic-context-pruning) | ปรับการใช้โทเค็นให้เหมาะสมโดยการตัดเอาท์พุตของเครื่องมือที่ล้าสมัย | -| [opencode-websearch-cited](https://github.com/ghoulr/opencode-websearch-cited.git) | เพิ่มการสนับสนุนการค้นหาเว็บแบบเนทีฟสำหรับผู้ให้บริการที่รองรับด้วยรูปแบบที่มีเหตุผลของ Google | -| [opencode-pty](https://github.com/shekohex/opencode-pty.git) | ช่วยให้ตัวแทน AI สามารถเรียกใช้กระบวนการเบื้องหลังใน PTY และส่งข้อมูลเชิงโต้ตอบให้พวกเขาได้ | -| [opencode-shell-strategy](https://github.com/JRedeker/opencode-shell-strategy) | คำแนะนำสำหรับคำสั่ง shell แบบไม่โต้ตอบ - ป้องกันการแฮงค์จากการดำเนินการที่ขึ้นอยู่กับ TTY | -| [opencode-wakatime](https://github.com/angristan/opencode-wakatime) | ติดตามการใช้งาน OpenCode ด้วย Wakatime | -| [opencode-md-table-formatter](https://github.com/franlol/opencode-md-table-formatter/tree/main) | ทำความสะอาดตาราง Markdown ที่ผลิตโดย LLM | -| [opencode-morph-fast-apply](https://github.com/JRedeker/opencode-morph-fast-apply) | การแก้ไขโค้ดเร็วขึ้น 10 เท่าด้วย Morph Fast Apply API และเครื่องหมายแก้ไขแบบ Lazy | -| [oh-my-opencode](https://github.com/code-yeongyu/oh-my-opencode) | ตัวแทนเบื้องหลัง, เครื่องมือ LSP/AST/MCP ที่สร้างไว้ล่วงหน้า, ตัวแทนที่ได้รับการดูแลจัดการ, เข้ากันได้กับ Claude Code | -| [opencode-notificator](https://github.com/panta82/opencode-notificator) | การแจ้งเตือนบนเดสก์ท็อปและเสียงเตือนสำหรับเซสชัน OpenCode | -| [opencode-notifier](https://github.com/mohak34/opencode-notifier) | การแจ้งเตือนบนเดสก์ท็อปและเสียงเตือนสำหรับการอนุญาต การดำเนินการเสร็จสิ้น และเหตุการณ์ข้อผิดพลาด | -| [opencode-zellij-namer](https://github.com/24601/opencode-zellij-namer) | การตั้งชื่อเซสชัน Zellij อัตโนมัติที่ขับเคลื่อนด้วย AI ตามบริบทของ OpenCode | -| [opencode-skillful](https://github.com/zenobi-us/opencode-skillful) | อนุญาตให้ตัวแทน OpenCode โหลดแบบ Lazy Load ตามความต้องการพร้อมการค้นพบทักษะและการแทรก | -| [opencode-supermemory](https://github.com/supermemoryai/opencode-supermemory) | หน่วยความจำถาวรตลอดเซสชันโดยใช้ Supermemory | -| [@plannotator/opencode](https://github.com/backnotprop/plannotator/tree/main/apps/opencode-plugin) | การตรวจสอบแผนเชิงโต้ตอบพร้อมคำอธิบายประกอบแบบภาพและการแชร์ส่วนตัว/offline | -| [@openspoon/subtask2](https://github.com/spoons-and-mirrors/subtask2) | ขยาย opencode /commands ไปสู่ระบบการประสานที่มีประสิทธิภาพพร้อมการควบคุมโฟลว์แบบละเอียด | -| [opencode-scheduler](https://github.com/different-ai/opencode-scheduler) | กำหนดเวลางานที่เกิดซ้ำโดยใช้ launchd (Mac) หรือ systemd (Linux) ด้วยไวยากรณ์ cron | -| [micode](https://github.com/vtemian/micode) | ระดมความคิดอย่างมีโครงสร้าง → วางแผน → นำเวิร์กโฟลว์ไปใช้ด้วยความต่อเนื่องของเซสชัน | -| [octto](https://github.com/vtemian/octto) | UI เบราว์เซอร์แบบโต้ตอบสำหรับการระดมความคิด AI ด้วยแบบฟอร์มคำถามหลายข้อ | -| [opencode-background-agents](https://github.com/kdcokenny/opencode-background-agents) | เอเจนต์พื้นหลังสไตล์ Claude Code พร้อมการมอบหมายแบบอะซิงก์และการคงอยู่ของบริบท | -| [opencode-notify](https://github.com/kdcokenny/opencode-notify) | การแจ้งเตือนระบบปฏิบัติการดั้งเดิมสำหรับ OpenCode – ทราบเมื่องานเสร็จสมบูรณ์ | -| [opencode-workspace](https://github.com/kdcokenny/opencode-workspace) | ชุดสายรัดประสานหลายเอเจนต์ที่ให้มา – ส่วนประกอบ 16 ชิ้น ติดตั้งเพียงครั้งเดียว | -| [opencode-worktree](https://github.com/kdcokenny/opencode-worktree) | เวิร์กทรีคอมไพล์ไร้แรงเสียดทานสำหรับ OpenCode | +| ชื่อ | คำอธิบาย | +| -------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | +| [opencode-daytona](https://github.com/daytonaio/daytona/tree/main/libs/opencode-plugin) | เรียกใช้เซสชัน OpenCode โดยอัตโนมัติในแซนด์บ็อกซ์ Daytona ที่แยกออกมาพร้อม git sync และการแสดงตัวอย่างแบบสด | +| [opencode-helicone-session](https://github.com/H2Shami/opencode-helicone-session) | แทรกส่วนหัวเซสชัน Helicone โดยอัตโนมัติสำหรับการจัดกลุ่มคำขอ | +| [opencode-type-inject](https://github.com/nick-vi/opencode-type-inject) | ฉีดประเภท TypeScript/Svelte ลงในไฟล์ที่อ่านโดยอัตโนมัติด้วยเครื่องมือค้นหา | +| [opencode-openai-codex-auth](https://github.com/numman-ali/opencode-openai-codex-auth) | ใช้การสมัครสมาชิก ChatGPT Plus/Pro แทนเครดิต API | +| [opencode-gemini-auth](https://github.com/jenslys/opencode-gemini-auth) | ใช้แผน Gemini ที่มีอยู่ของคุณแทนการเรียกเก็บเงิน API | +| [opencode-antigravity-auth](https://github.com/NoeFabris/opencode-antigravity-auth) | ใช้โมเดลฟรีของ Antigravity แทนการเรียกเก็บเงิน API | +| [opencode-devcontainers](https://github.com/athal7/opencode-devcontainers) | การแยกคอนเทนเนอร์ Devcontainer แบบหลายสาขาพร้อมโคลนแบบตื้นและพอร์ตที่กำหนดอัตโนมัติ | +| [opencode-google-antigravity-auth](https://github.com/shekohex/opencode-google-antigravity-auth) | ปลั๊กอิน Google Antigravity OAuth พร้อมรองรับ Google Search และการจัดการ API ที่แข็งแกร่งยิ่งขึ้น | +| [opencode-dynamic-context-pruning](https://github.com/Tarquinen/opencode-dynamic-context-pruning) | ปรับการใช้โทเค็นให้เหมาะสมโดยการตัดเอาท์พุตของเครื่องมือที่ล้าสมัย | +| [opencode-vibeguard](https://github.com/inkdust2021/opencode-vibeguard) | ปกปิดความลับ/PII เป็นตัวยึดตำแหน่งแบบ VibeGuard ก่อนการเรียก LLM และกู้คืนในเครื่อง | +| [opencode-websearch-cited](https://github.com/ghoulr/opencode-websearch-cited.git) | เพิ่มการสนับสนุนการค้นหาเว็บแบบเนทีฟสำหรับผู้ให้บริการที่รองรับด้วยรูปแบบที่มีเหตุผลของ Google | +| [opencode-pty](https://github.com/shekohex/opencode-pty.git) | ช่วยให้ตัวแทน AI สามารถเรียกใช้กระบวนการเบื้องหลังใน PTY และส่งข้อมูลเชิงโต้ตอบให้พวกเขาได้ | +| [opencode-shell-strategy](https://github.com/JRedeker/opencode-shell-strategy) | คำแนะนำสำหรับคำสั่ง shell แบบไม่โต้ตอบ - ป้องกันการแฮงค์จากการดำเนินการที่ขึ้นอยู่กับ TTY | +| [opencode-wakatime](https://github.com/angristan/opencode-wakatime) | ติดตามการใช้งาน OpenCode ด้วย Wakatime | +| [opencode-md-table-formatter](https://github.com/franlol/opencode-md-table-formatter/tree/main) | ทำความสะอาดตาราง Markdown ที่ผลิตโดย LLM | +| [opencode-morph-fast-apply](https://github.com/JRedeker/opencode-morph-fast-apply) | การแก้ไขโค้ดเร็วขึ้น 10 เท่าด้วย Morph Fast Apply API และเครื่องหมายแก้ไขแบบ Lazy | +| [oh-my-opencode](https://github.com/code-yeongyu/oh-my-opencode) | ตัวแทนเบื้องหลัง, เครื่องมือ LSP/AST/MCP ที่สร้างไว้ล่วงหน้า, ตัวแทนที่ได้รับการดูแลจัดการ, เข้ากันได้กับ Claude Code | +| [opencode-notificator](https://github.com/panta82/opencode-notificator) | การแจ้งเตือนบนเดสก์ท็อปและเสียงเตือนสำหรับเซสชัน OpenCode | +| [opencode-notifier](https://github.com/mohak34/opencode-notifier) | การแจ้งเตือนบนเดสก์ท็อปและเสียงเตือนสำหรับการอนุญาต การดำเนินการเสร็จสิ้น และเหตุการณ์ข้อผิดพลาด | +| [opencode-zellij-namer](https://github.com/24601/opencode-zellij-namer) | การตั้งชื่อเซสชัน Zellij อัตโนมัติที่ขับเคลื่อนด้วย AI ตามบริบทของ OpenCode | +| [opencode-skillful](https://github.com/zenobi-us/opencode-skillful) | อนุญาตให้ตัวแทน OpenCode โหลดแบบ Lazy Load ตามความต้องการพร้อมการค้นพบทักษะและการแทรก | +| [opencode-supermemory](https://github.com/supermemoryai/opencode-supermemory) | หน่วยความจำถาวรตลอดเซสชันโดยใช้ Supermemory | +| [@plannotator/opencode](https://github.com/backnotprop/plannotator/tree/main/apps/opencode-plugin) | การตรวจสอบแผนเชิงโต้ตอบพร้อมคำอธิบายประกอบแบบภาพและการแชร์ส่วนตัว/offline | +| [@openspoon/subtask2](https://github.com/spoons-and-mirrors/subtask2) | ขยาย opencode /commands ไปสู่ระบบการประสานที่มีประสิทธิภาพพร้อมการควบคุมโฟลว์แบบละเอียด | +| [opencode-scheduler](https://github.com/different-ai/opencode-scheduler) | กำหนดเวลางานที่เกิดซ้ำโดยใช้ launchd (Mac) หรือ systemd (Linux) ด้วยไวยากรณ์ cron | +| [micode](https://github.com/vtemian/micode) | ระดมความคิดอย่างมีโครงสร้าง → วางแผน → นำเวิร์กโฟลว์ไปใช้ด้วยความต่อเนื่องของเซสชัน | +| [octto](https://github.com/vtemian/octto) | UI เบราว์เซอร์แบบโต้ตอบสำหรับการระดมความคิด AI ด้วยแบบฟอร์มคำถามหลายข้อ | +| [opencode-background-agents](https://github.com/kdcokenny/opencode-background-agents) | เอเจนต์พื้นหลังสไตล์ Claude Code พร้อมการมอบหมายแบบอะซิงก์และการคงอยู่ของบริบท | +| [opencode-notify](https://github.com/kdcokenny/opencode-notify) | การแจ้งเตือนระบบปฏิบัติการดั้งเดิมสำหรับ OpenCode – ทราบเมื่องานเสร็จสมบูรณ์ | +| [opencode-workspace](https://github.com/kdcokenny/opencode-workspace) | ชุดสายรัดประสานหลายเอเจนต์ที่ให้มา – ส่วนประกอบ 16 ชิ้น ติดตั้งเพียงครั้งเดียว | +| [opencode-worktree](https://github.com/kdcokenny/opencode-worktree) | เวิร์กทรีคอมไพล์ไร้แรงเสียดทานสำหรับ OpenCode | +| [opencode-sentry-monitor](https://github.com/stolinski/opencode-sentry-monitor) | ติดตามและแก้ไขข้อบกพร่องเอเจนต์ AI ของคุณด้วย Sentry AI Monitoring | --- diff --git a/packages/web/src/content/docs/th/go.mdx b/packages/web/src/content/docs/th/go.mdx new file mode 100644 index 0000000000..7dcaf398a5 --- /dev/null +++ b/packages/web/src/content/docs/th/go.mdx @@ -0,0 +1,145 @@ +--- +title: Go +description: การสมัครสมาชิกราคาประหยัดสำหรับโมเดลการเขียนโค้ดแบบเปิด +--- + +import config from "../../../../config.mjs" +export const console = config.console +export const email = `mailto:${config.email}` + +OpenCode Go คือการสมัครสมาชิกราคาประหยัดเพียง **$10/เดือน** ที่ให้คุณเข้าถึงโมเดลการเขียนโค้ดแบบเปิดยอดนิยมได้อย่างน่าเชื่อถือ + +:::note +ขณะนี้ OpenCode Go อยู่ในช่วงเบต้า +::: + +Go ทำงานเหมือนกับผู้ให้บริการรายอื่นใน OpenCode คุณสมัครสมาชิก OpenCode Go และรับคีย์ API ของคุณ มันเป็น**ตัวเลือกเสริมทั้งหมด** และคุณไม่จำเป็นต้องใช้มันเพื่อใช้งาน OpenCode + +มันถูกออกแบบมาสำหรับผู้ใช้งานระดับนานาชาติเป็นหลัก โดยมีโมเดลโฮสต์อยู่ในสหรัฐอเมริกา สหภาพยุโรป และสิงคโปร์ เพื่อการเข้าถึงที่เสถียรทั่วโลก + +--- + +## ความเป็นมา + +โมเดลแบบเปิดมีคุณภาพดีขึ้นมาก ปัจจุบันมีประสิทธิภาพใกล้เคียงกับโมเดลที่เป็นกรรมสิทธิ์สำหรับงานเขียนโค้ด และเนื่องจากผู้ให้บริการหลายรายสามารถให้บริการโมเดลเหล่านี้ได้อย่างแข่งขันกัน จึงมักจะมีราคาถูกกว่ามาก + +อย่างไรก็ตาม การเข้าถึงโมเดลเหล่านี้อย่างน่าเชื่อถือและมีความหน่วงต่ำอาจเป็นเรื่องยาก ผู้ให้บริการมีคุณภาพและความพร้อมใช้งานที่แตกต่างกัน + +:::tip +เราได้ทดสอบกลุ่มโมเดลและผู้ให้บริการที่เลือกสรรแล้วซึ่งทำงานได้ดีกับ OpenCode +::: + +เพื่อแก้ไขปัญหานี้ เราได้ทำสิ่งต่อไปนี้: + +1. เราทดสอบกลุ่มโมเดลแบบเปิดที่เลือกสรรและพูดคุยกับทีมของพวกเขาเกี่ยวกับวิธีการรันโมเดลให้ดีที่สุด +2. จากนั้นเราทำงานร่วมกับผู้ให้บริการบางรายเพื่อให้แน่ใจว่าโมเดลเหล่านี้ได้รับการให้บริการอย่างถูกต้อง +3. สุดท้าย เราทำการทดสอบประสิทธิภาพ (Benchmark) การรวมกันของโมเดล/ผู้ให้บริการ และได้รายชื่อที่เรารู้สึกดีที่จะแนะนำ + +OpenCode Go ให้คุณเข้าถึงโมเดลเหล่านี้ในราคา **$10/เดือน** + +--- + +## วิธีการทำงาน + +OpenCode Go ทำงานเหมือนกับผู้ให้บริการรายอื่นใน OpenCode + +1. ลงชื่อเข้าใช้ **<a href={console}>OpenCode Zen</a>** สมัครสมาชิก Go และคัดลอกคีย์ API ของคุณ +2. รันคำสั่ง `/connect` ใน TUI เลือก `OpenCode Go` และวางคีย์ API ของคุณ +3. รัน `/models` ใน TUI เพื่อดูรายชื่อโมเดลที่สามารถใช้งานได้ผ่าน Go + +:::note +สมาชิกเพียงหนึ่งคนต่อพื้นที่ทำงาน (Workspace) เท่านั้นที่สามารถสมัครสมาชิก OpenCode Go ได้ +::: + +รายชื่อโมเดลปัจจุบันประกอบด้วย: + +- **GLM-5** +- **Kimi K2.5** +- **MiniMax M2.5** + +รายชื่อโมเดลอาจมีการเปลี่ยนแปลงเมื่อเราทดสอบและเพิ่มโมเดลใหม่ + +--- + +## ขีดจำกัดการใช้งาน + +OpenCode Go มีขีดจำกัดดังต่อไปนี้: + +- **ขีดจำกัด 5 ชั่วโมง** — การใช้งานมูลค่า $12 +- **ขีดจำกัดรายสัปดาห์** — การใช้งานมูลค่า $30 +- **ขีดจำกัดรายเดือน** — การใช้งานมูลค่า $60 + +ขีดจำกัดถูกกำหนดเป็นมูลค่าดอลลาร์ ซึ่งหมายความว่าจำนวนคำขอจริงของคุณจะขึ้นอยู่กับโมเดลที่คุณใช้ โมเดลที่ถูกกว่าเช่น MiniMax M2.5 อนุญาตให้ส่งคำขอได้มากกว่า ในขณะที่โมเดลที่มีราคาสูงกว่าเช่น GLM-5 จะอนุญาตให้ส่งคำขอได้น้อยกว่า + +ตารางด้านล่างแสดงจำนวนคำขอโดยประมาณตามรูปแบบการใช้งาน Go ทั่วไป: + +| | GLM-5 | Kimi K2.5 | MiniMax M2.5 | +| ----------------- | ----- | --------- | ------------ | +| คำขอต่อ 5 ชั่วโมง | 1,150 | 1,850 | 30,000 | +| คำขอต่อสัปดาห์ | 2,880 | 4,630 | 75,000 | +| คำขอต่อเดือน | 5,750 | 9,250 | 150,000 | + +การประมาณการขึ้นอยู่กับรูปแบบคำขอเฉลี่ยที่สังเกตได้: + +- GLM-5 — 700 input, 52,000 cached, 150 output tokens ต่อคำขอ +- Kimi K2.5 — 870 input, 55,000 cached, 200 output tokens ต่อคำขอ +- MiniMax M2.5 — 300 input, 55,000 cached, 125 output tokens ต่อคำขอ + +คุณสามารถติดตามการใช้งานปัจจุบันของคุณได้ใน **<a href={console}>คอนโซล</a>** + +:::tip +หากคุณใช้งานจนถึงขีดจำกัด คุณสามารถใช้โมเดลฟรีต่อไปได้ +::: + +ขีดจำกัดการใช้งานอาจมีการเปลี่ยนแปลงเมื่อเราเรียนรู้จากการใช้งานและข้อเสนอแนะในช่วงแรก + +--- + +### ราคา + +OpenCode Go เป็นแผนการสมัครสมาชิกราคา **$10/เดือน** ด้านล่างคือราคา**ต่อ 1 ล้านโทเค็น** + +| Model | Input | Output | Cached Read | +| ------------ | ----- | ------ | ----------- | +| GLM-5 | $1.00 | $3.20 | $0.20 | +| Kimi K2.5 | $0.60 | $3.00 | $0.10 | +| MiniMax M2.5 | $0.30 | $1.20 | $0.03 | + +--- + +### การใช้งานเกินขีดจำกัด + +หากคุณมีเครดิตในยอดคงเหลือ Zen ของคุณ คุณสามารถเปิดใช้งานตัวเลือก **Use balance** ในคอนโซล เมื่อเปิดใช้งาน Go จะเปลี่ยนไปใช้ยอดคงเหลือ Zen ของคุณหลังจากที่คุณใช้งานถึงขีดจำกัดแล้ว แทนที่จะบล็อกคำขอ + +--- + +## Endpoints + +คุณยังสามารถเข้าถึงโมเดล Go ผ่าน API endpoints ต่อไปนี้ + +| Model | Model ID | Endpoint | AI SDK Package | +| ------------ | ------------ | ------------------------------------------------ | --------------------------- | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | + +[รหัสโมเดล](/docs/config/#models) ในการกำหนดค่า OpenCode ของคุณใช้รูปแบบ `opencode-go/<model-id>` ตัวอย่างเช่น สำหรับ Kimi K2.5 คุณจะใช้ `opencode-go/kimi-k2.5` ในการกำหนดค่าของคุณ + +--- + +## ความเป็นส่วนตัว + +แผนนี้ออกแบบมาสำหรับผู้ใช้ระดับนานาชาติเป็นหลัก โดยมีโมเดลโฮสต์อยู่ในสหรัฐอเมริกา สหภาพยุโรป และสิงคโปร์ เพื่อการเข้าถึงที่เสถียรทั่วโลก + +<a href={email}>ติดต่อเรา</a> หากคุณมีข้อสงสัยใดๆ + +--- + +## เป้าหมาย + +เราสร้าง OpenCode Go เพื่อ: + +1. ทำให้การเขียนโค้ดด้วย AI **เข้าถึงได้** สำหรับผู้คนมากขึ้นด้วยการสมัครสมาชิกราคาประหยัด +2. ให้การเข้าถึงโมเดลการเขียนโค้ดแบบเปิดที่ดีที่สุดอย่าง **น่าเชื่อถือ** +3. คัดสรรโมเดลที่ผ่านการ **ทดสอบและวัดประสิทธิภาพ** สำหรับการใช้งานตัวแทน (Agent) เขียนโค้ด +4. **ไม่มีการผูกมัด** โดยอนุญาตให้คุณใช้ผู้ให้บริการรายอื่นกับ OpenCode ได้เช่นกัน diff --git a/packages/web/src/content/docs/th/keybinds.mdx b/packages/web/src/content/docs/th/keybinds.mdx index 2fbcd02a6e..ce3234a04a 100644 --- a/packages/web/src/content/docs/th/keybinds.mdx +++ b/packages/web/src/content/docs/th/keybinds.mdx @@ -3,11 +3,11 @@ title: ปุ่มลัด description: ปรับแต่งปุ่มลัดของคุณ --- -OpenCode มีรายการปุ่มลัดที่คุณปรับแต่งได้ผ่านการกำหนดค่า OpenCode +OpenCode มีรายการปุ่มลัดที่คุณปรับแต่งได้ผ่าน `tui.json` -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "keybinds": { "leader": "ctrl+x", "app_exit": "ctrl+c,ctrl+d,<leader>q", @@ -28,6 +28,7 @@ OpenCode มีรายการปุ่มลัดที่คุณปร "session_unshare": "none", "session_interrupt": "escape", "session_compact": "<leader>c", + "session_child_first": "<leader>down", "session_child_cycle": "<leader>right", "session_child_cycle_reverse": "<leader>left", "session_parent": "<leader>up", @@ -117,11 +118,11 @@ OpenCode ใช้ปุ่ม `leader` สำหรับการเชื่ ## ปิดการใช้งานการผูกปุ่ม -คุณสามารถปิดการใช้งานการผูกปุ่มได้โดยการเพิ่มคีย์ลงในการกำหนดค่าของคุณด้วยค่า "none" +คุณสามารถปิดการใช้งานการผูกปุ่มได้โดยการเพิ่มคีย์ลงใน `tui.json` ด้วยค่า "none" -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "keybinds": { "session_compact": "none" } diff --git a/packages/web/src/content/docs/th/lsp.mdx b/packages/web/src/content/docs/th/lsp.mdx index 0e5e28c4a6..91d3f479fb 100644 --- a/packages/web/src/content/docs/th/lsp.mdx +++ b/packages/web/src/content/docs/th/lsp.mdx @@ -11,40 +11,41 @@ OpenCode ทำงานร่วมกับ Language Server Protocol (LSP) เ OpenCode มาพร้อมกับเซิร์ฟเวอร์ LSP ในตัวหลายตัวสำหรับภาษายอดนิยม: -| LSP เซิร์ฟเวอร์ | ส่วนขยาย | ความต้องการ | -| -------------------- | ------------------------------------------------------------------- | ------------------------------------------------------- | -| astro | .astro | ติดตั้งอัตโนมัติสำหรับโปรเจ็กต์ Astro | -| bash | .sh, .bash, .zsh, .ksh | ติดตั้ง bash-Language-Server โดยอัตโนมัติ | -| clang | .c, .cpp, .cc, .cxx, .c++, .h, .hpp, .hh, .hxx, .h++ | ติดตั้งอัตโนมัติสำหรับโครงการ C/C++ | -| csharp | .cs | `.NET SDK` ติดตั้งแล้ว | -| clojure-lsp | .clj, .cljs, .cljc, .edn | `clojure-lsp` คำสั่งใช้ได้ | -| dart | .dart | `dart` คำสั่งใช้ได้ | -| deno | .ts, .tsx, .js, .jsx, .mjs | มีคำสั่ง `deno` (ตรวจจับอัตโนมัติ deno.json/deno.jsonc) | -| elixir-ls | .ex, .exs | `elixir` คำสั่งใช้ได้ | -| eslint | .ts, .tsx, .js, .jsx, .mjs, .cjs, .mts, .cts, .vue | `eslint` การพึ่งพาในโครงการ | -| fsharp | .fs, .fsi, .fsx, .fsscript | `.NET SDK` ติดตั้งแล้ว | -| gleam | .gleam | `gleam` คำสั่งใช้ได้ | -| gopls | .go | `go` คำสั่งใช้ได้ | -| haskell | .hs, .lhs | `haskell-language-server-wrapper` คำสั่งใช้ได้ | -| jdtls | .java | `Java SDK (version 21+)` ติดตั้งแล้ว | -| kotlin-ls | .kt, .kts | ติดตั้งอัตโนมัติสำหรับโปรเจ็กต์ Kotlin | -| lua-ls | .lua | ติดตั้งอัตโนมัติสำหรับโปรเจ็กต์ Lua | -| nix | .nix | `nixd` คำสั่งใช้ได้ | -| ocaml-lsp | .ml, .mli | `ocamllsp` คำสั่งใช้ได้ | -| oxlint | .ts, .tsx, .js, .jsx, .mjs, .cjs, .mts, .cts, .vue, .astro, .svelte | `oxlint` การพึ่งพาในโครงการ | -| php intelephense.php | .php | ติดตั้งอัตโนมัติสำหรับโครงการ PHP | -| prisma | .prisma | `prisma` คำสั่งใช้ได้ | -| pyright | .py, .pyi | `pyright` ติดตั้งการพึ่งพาแล้ว | -| ruby-lsp (rubocop) | .rb, .rake, .gemspec, .ru | มีคำสั่ง `ruby` และ `gem` | -| rust | .rs | `rust-analyzer` คำสั่งใช้ได้ | -| sourcekit-lsp | .swift, .objc, .objcpp | ติดตั้ง `swift` (`xcode` บน macOS) | -| svelte | .svelte | ติดตั้งอัตโนมัติสำหรับโครงการ Svelte | -| terraform | .tf, .tfvars | ติดตั้งอัตโนมัติจากรุ่น GitHub | -| tinymist | .typ, .typst | ติดตั้งอัตโนมัติจากรุ่น GitHub | -| typescript | .ts, .tsx, .js, .jsx, .mjs, .cjs, .mts, .cts | `typescript` การพึ่งพาในโครงการ | -| vue | .vue | ติดตั้งอัตโนมัติสำหรับโปรเจ็กต์ Vue | -| yaml-ls | .yaml, .yml | ติดตั้งเซิร์ฟเวอร์ภาษา Red Hat yaml โดยอัตโนมัติ | -| zls | .zig, .zon | `zig` คำสั่งใช้ได้ | +| LSP เซิร์ฟเวอร์ | ส่วนขยาย | ความต้องการ | +| ------------------ | ------------------------------------------------------------------- | ------------------------------------------------------- | +| astro | .astro | ติดตั้งอัตโนมัติสำหรับโปรเจ็กต์ Astro | +| bash | .sh, .bash, .zsh, .ksh | ติดตั้ง bash-Language-Server โดยอัตโนมัติ | +| clangd | .c, .cpp, .cc, .cxx, .c++, .h, .hpp, .hh, .hxx, .h++ | ติดตั้งอัตโนมัติสำหรับโครงการ C/C++ | +| csharp | .cs | `.NET SDK` ติดตั้งแล้ว | +| clojure-lsp | .clj, .cljs, .cljc, .edn | `clojure-lsp` คำสั่งใช้ได้ | +| dart | .dart | `dart` คำสั่งใช้ได้ | +| deno | .ts, .tsx, .js, .jsx, .mjs | มีคำสั่ง `deno` (ตรวจจับอัตโนมัติ deno.json/deno.jsonc) | +| elixir-ls | .ex, .exs | `elixir` คำสั่งใช้ได้ | +| eslint | .ts, .tsx, .js, .jsx, .mjs, .cjs, .mts, .cts, .vue | `eslint` การพึ่งพาในโครงการ | +| fsharp | .fs, .fsi, .fsx, .fsscript | `.NET SDK` ติดตั้งแล้ว | +| gleam | .gleam | `gleam` คำสั่งใช้ได้ | +| gopls | .go | `go` คำสั่งใช้ได้ | +| hls | .hs, .lhs | `haskell-language-server-wrapper` คำสั่งใช้ได้ | +| jdtls | .java | `Java SDK (version 21+)` ติดตั้งแล้ว | +| julials | .jl | ติดตั้ง `julia` และ `LanguageServer.jl` แล้ว | +| kotlin-ls | .kt, .kts | ติดตั้งอัตโนมัติสำหรับโปรเจ็กต์ Kotlin | +| lua-ls | .lua | ติดตั้งอัตโนมัติสำหรับโปรเจ็กต์ Lua | +| nixd | .nix | `nixd` คำสั่งใช้ได้ | +| ocaml-lsp | .ml, .mli | `ocamllsp` คำสั่งใช้ได้ | +| oxlint | .ts, .tsx, .js, .jsx, .mjs, .cjs, .mts, .cts, .vue, .astro, .svelte | `oxlint` การพึ่งพาในโครงการ | +| php intelephense | .php | ติดตั้งอัตโนมัติสำหรับโครงการ PHP | +| prisma | .prisma | `prisma` คำสั่งใช้ได้ | +| pyright | .py, .pyi | `pyright` ติดตั้งการพึ่งพาแล้ว | +| ruby-lsp (rubocop) | .rb, .rake, .gemspec, .ru | มีคำสั่ง `ruby` และ `gem` | +| rust | .rs | `rust-analyzer` คำสั่งใช้ได้ | +| sourcekit-lsp | .swift, .objc, .objcpp | ติดตั้ง `swift` (`xcode` บน macOS) | +| svelte | .svelte | ติดตั้งอัตโนมัติสำหรับโครงการ Svelte | +| terraform | .tf, .tfvars | ติดตั้งอัตโนมัติจากรุ่น GitHub | +| tinymist | .typ, .typc | ติดตั้งอัตโนมัติจากรุ่น GitHub | +| typescript | .ts, .tsx, .js, .jsx, .mjs, .cjs, .mts, .cts | `typescript` การพึ่งพาในโครงการ | +| vue | .vue | ติดตั้งอัตโนมัติสำหรับโปรเจ็กต์ Vue | +| yaml-ls | .yaml, .yml | ติดตั้งเซิร์ฟเวอร์ภาษา Red Hat yaml โดยอัตโนมัติ | +| zls | .zig, .zon | `zig` คำสั่งใช้ได้ | เซิร์ฟเวอร์ LSP จะถูกเปิดใช้งานโดยอัตโนมัติเมื่อตรวจพบนามสกุลไฟล์ใดนามสกุลหนึ่งข้างต้นและเป็นไปตามข้อกำหนด diff --git a/packages/web/src/content/docs/th/plugins.mdx b/packages/web/src/content/docs/th/plugins.mdx index a2d74ceb9c..e672715a4e 100644 --- a/packages/web/src/content/docs/th/plugins.mdx +++ b/packages/web/src/content/docs/th/plugins.mdx @@ -308,6 +308,10 @@ export const CustomToolsPlugin: Plugin = async (ctx) => { เครื่องมือที่คุณกำหนดเองจะพร้อมใช้งานสำหรับ opencode ควบคู่ไปกับเครื่องมือในตัว +:::note +หากเครื่องมือปลั๊กอินใช้ชื่อเดียวกับเครื่องมือในตัว เครื่องมือปลั๊กอินจะมีความสำคัญเหนือกว่า +::: + --- ### การบันทึก diff --git a/packages/web/src/content/docs/th/providers.mdx b/packages/web/src/content/docs/th/providers.mdx index e9fbb351d7..122ade4277 100644 --- a/packages/web/src/content/docs/th/providers.mdx +++ b/packages/web/src/content/docs/th/providers.mdx @@ -84,6 +84,37 @@ OpenCode Zen คือรายชื่อโมเดลที่จัดท --- +## OpenCode Go + +OpenCode Go คือแผนการสมัครสมาชิกราคาประหยัดที่ให้การเข้าถึงโมเดลการเขียนโค้ดแบบเปิดยอดนิยมที่เชื่อถือได้ ซึ่งจัดเตรียมโดยทีมงาน OpenCode ที่ได้รับการทดสอบและตรวจสอบแล้วว่าทำงานได้ดีกับ OpenCode + +1. เรียกใช้คำสั่ง `/connect` ใน TUI เลือก `OpenCode Go` และไปที่ [opencode.ai/auth](https://opencode.ai/zen) + + ```txt + /connect + ``` + +2. ลงชื่อเข้าใช้ เพิ่มรายละเอียดการเรียกเก็บเงินของคุณ และคัดลอกรหัส API ของคุณ + +3. วางคีย์ API ของคุณ + + ```txt + ┌ API key + │ + │ + └ enter + ``` + +4. เรียกใช้ `/models` ใน TUI เพื่อดูรายการรุ่นที่เราแนะนำ + + ```txt + /models + ``` + +มันทำงานเหมือนกับผู้ให้บริการรายอื่นใน OpenCode และเป็นทางเลือกในการใช้งานโดยสมบูรณ์ + +--- + ## ไดเรกทอรี มาดูรายละเอียดผู้ให้บริการบางรายกัน หากคุณต้องการเพิ่มผู้ให้บริการให้กับ @@ -1354,6 +1385,583 @@ OpenCode Zen คือรายการโมเดลที่ได้รั └ enter ``` +4. รันคำสั่ง `/models` เพื่อเลือกโมเดลเช่น _Qwen 3 Coder 480B_ + + ```txt + /models + ``` + +--- + +### OpenRouter + +1. ไปที่ [OpenRouter dashboard](https://openrouter.ai/settings/keys) คลิก **Create API Key** และคัดลอกคีย์ + +2. เรียกใช้คำสั่ง `/connect` และค้นหา OpenRouter + + ```txt + /connect + ``` + +3. ป้อนคีย์ API สำหรับผู้ให้บริการ + + ```txt + ┌ API key + │ + │ + └ enter + ``` + +4. โมเดล OpenRouter จำนวนมากถูกโหลดไว้ล่วงหน้าตามค่าเริ่มต้น รันคำสั่ง `/models` เพื่อเลือกโมเดลที่คุณต้องการ + + ```txt + /models + ``` + + คุณยังสามารถเพิ่มโมเดลเพิ่มเติมผ่านการกำหนดค่า opencode ของคุณได้ + + ```json title="opencode.json" {6} + { + "$schema": "https://opencode.ai/config.json", + "provider": { + "openrouter": { + "models": { + "somecoolnewmodel": {} + } + } + } + } + ``` + +5. คุณยังสามารถปรับแต่งได้ผ่านการกำหนดค่า opencode ของคุณ นี่คือตัวอย่างการระบุผู้ให้บริการ + + ```json title="opencode.json" + { + "$schema": "https://opencode.ai/config.json", + "provider": { + "openrouter": { + "models": { + "moonshotai/kimi-k2": { + "options": { + "provider": { + "order": ["baseten"], + "allow_fallbacks": false + } + } + } + } + } + } + } + ``` + +--- + +### SAP AI Core + +SAP AI Core ให้การเข้าถึงโมเดลมากกว่า 40 รุ่นจาก OpenAI, Anthropic, Google, Amazon, Meta, Mistral และ AI21 ผ่านแพลตฟอร์มเดียว + +1. ไปที่ [SAP BTP Cockpit](https://account.hana.ondemand.com/) ของคุณ ไปที่อินสแตนซ์บริการ SAP AI Core และสร้างคีย์บริการ + + :::tip + คีย์บริการคือวัตถุ JSON ที่มี `clientid`, `clientsecret`, `url` และ `serviceurls.AI_API_URL` คุณสามารถค้นหาอินสแตนซ์ AI Core ของคุณได้ภายใต้ **Services** > **Instances and Subscriptions** ใน BTP Cockpit + ::: + +2. เรียกใช้คำสั่ง `/connect` และค้นหา **SAP AI Core** + + ```txt + /connect + ``` + +3. ป้อน JSON คีย์บริการของคุณ + + ```txt + ┌ Service key + │ + │ + └ enter + ``` + + หรือตั้งค่าตัวแปรสภาพแวดล้อม `AICORE_SERVICE_KEY`: + + ```bash + AICORE_SERVICE_KEY='{"clientid":"...","clientsecret":"...","url":"...","serviceurls":{"AI_API_URL":"..."}}' opencode + ``` + + หรือเพิ่มลงในโปรไฟล์ทุบตีของคุณ: + + ```bash title="~/.bash_profile" + export AICORE_SERVICE_KEY='{"clientid":"...","clientsecret":"...","url":"...","serviceurls":{"AI_API_URL":"..."}}' + ``` + +4. เลือกตั้งค่ารหัสการปรับใช้และกลุ่มทรัพยากร: + + ```bash + AICORE_DEPLOYMENT_ID=your-deployment-id AICORE_RESOURCE_GROUP=your-resource-group opencode + ``` + + :::note + การตั้งค่าเหล่านี้เป็นทางเลือกและควรกำหนดค่าตามการตั้งค่า SAP AI Core ของคุณ + ::: + +5. รันคำสั่ง `/models` เพื่อเลือกจาก 40+ รุ่นที่มีอยู่ + + ```txt + /models + ``` + +--- + +### STACKIT + +STACKIT AI Model Serving มอบสภาพแวดล้อมการโฮสต์ที่มีการจัดการเต็มรูปแบบสำหรับโมเดล AI โดยเน้นที่ LLM เช่น Llama, Mistral และ Qwen โดยมีอธิปไตยของข้อมูลสูงสุดบนโครงสร้างพื้นฐานยุโรป + +1. ไปที่ [STACKIT Portal](https://portal.stackit.cloud) ไปที่ **AI Model Serving** และสร้างโทเค็นการตรวจสอบสิทธิ์สำหรับโครงการของคุณ + + :::tip + คุณต้องมีบัญชีลูกค้า STACKIT บัญชีผู้ใช้ และโครงการก่อนสร้างโทเค็นการตรวจสอบสิทธิ์ + ::: + +2. เรียกใช้คำสั่ง `/connect` และค้นหา **STACKIT** + + ```txt + /connect + ``` + +3. ป้อนโทเค็นการตรวจสอบสิทธิ์ STACKIT AI Model Serving ของคุณ + + ```txt + ┌ API key + │ + │ + └ enter + ``` + +4. รันคำสั่ง `/models` เพื่อเลือกจากโมเดลที่มีอยู่ เช่น _Qwen3-VL 235B_ หรือ _Llama 3.3 70B_ + + ```txt + /models + ``` + +--- + +### OVHcloud AI Endpoints + +1. ไปที่ [OVHcloud panel](https://ovh.com/manager) ไปที่ส่วน `Public Cloud`, `AI & Machine Learning` > `AI Endpoints` และในแท็บ `API Keys` ให้คลิก **Create a new API key** + +2. เรียกใช้คำสั่ง `/connect` และค้นหา **OVHcloud AI Endpoints** + + ```txt + /connect + ``` + +3. ป้อนคีย์ API OVHcloud AI Endpoints ของคุณ + + ```txt + ┌ API key + │ + │ + └ enter + ``` + +4. รันคำสั่ง `/models` เพื่อเลือกโมเดลเช่น _gpt-oss-120b_ + + ```txt + /models + ``` + +--- + +### Scaleway + +วิธีใช้ [Scaleway Generative APIs](https://www.scaleway.com/en/docs/generative-apis/) กับ Opencode: + +1. ไปที่ [Scaleway Console IAM settings](https://console.scaleway.com/iam/api-keys) เพื่อสร้างคีย์ API ใหม่ + +2. เรียกใช้คำสั่ง `/connect` และค้นหา **Scaleway** + + ```txt + /connect + ``` + +3. ป้อนคีย์ Scaleway API ของคุณ + + ```txt + ┌ API key + │ + │ + └ enter + ``` + +4. รันคำสั่ง `/models` เพื่อเลือกโมเดลเช่น _devstral-2-123b-instruct-2512_ หรือ _gpt-oss-120b_ + + ```txt + /models + ``` + +--- + +### Together AI + +1. ไปที่ [Together AI console](https://api.together.ai) สร้างบัญชี และคลิก **Add Key** + +2. เรียกใช้คำสั่ง `/connect` และค้นหา **Together AI** + + ```txt + /connect + ``` + +3. ป้อนคีย์ Together AI API ของคุณ + + ```txt + ┌ API key + │ + │ + └ enter + ``` + +4. รันคำสั่ง `/models` เพื่อเลือกโมเดลเช่น _Kimi K2 Instruct_ + + ```txt + /models + ``` + +--- + +### Venice AI + +1. ไปที่ [Venice AI console](https://venice.ai) สร้างบัญชี และสร้างคีย์ API + +2. เรียกใช้คำสั่ง `/connect` และค้นหา **Venice AI** + + ```txt + /connect + ``` + +3. ป้อนคีย์ Venice AI API ของคุณ + + ```txt + ┌ API key + │ + │ + └ enter + ``` + +4. รันคำสั่ง `/models` เพื่อเลือกโมเดลเช่น _Llama 3.3 70B_ + + ```txt + /models + ``` + +--- + +### Vercel AI Gateway + +Vercel AI Gateway ช่วยให้คุณเข้าถึงโมเดลจาก OpenAI, Anthropic, Google, xAI และอื่นๆ อีกมากมายผ่านจุดสิ้นสุดแบบรวม โมเดลถูกนำเสนอในราคาปลีกโดยไม่มีการบวกเพิ่ม + +1. ไปที่ [Vercel dashboard](https://vercel.com/) ไปที่แท็บ **AI Gateway** และคลิก **API keys** เพื่อสร้างคีย์ API ใหม่ + +2. เรียกใช้คำสั่ง `/connect` และค้นหา **Vercel AI Gateway** + + ```txt + /connect + ``` + +3. ป้อนคีย์ Vercel AI Gateway API ของคุณ + + ```txt + ┌ API key + │ + │ + └ enter + ``` + +4. รันคำสั่ง `/models` เพื่อเลือกรุ่น + + ```txt + /models + ``` + +คุณยังสามารถปรับแต่งโมเดลผ่านการกำหนดค่า opencode ของคุณได้ นี่คือตัวอย่างการระบุลำดับการกำหนดเส้นทางผู้ให้บริการ + +```json title="opencode.json" +{ + "$schema": "https://opencode.ai/config.json", + "provider": { + "vercel": { + "models": { + "anthropic/claude-sonnet-4": { + "options": { + "order": ["anthropic", "vertex"] + } + } + } + } + } +} +``` + +ตัวเลือกการกำหนดเส้นทางที่มีประโยชน์บางประการ: + +| ตัวเลือก | คำอธิบาย | +| ------------------- | ---------------------------------------------------------- | +| `order` | ลำดับผู้ให้บริการที่จะลอง | +| `only` | จำกัดเฉพาะผู้ให้บริการที่ระบุ | +| `zeroDataRetention` | ใช้เฉพาะผู้ให้บริการที่มีนโยบายการเก็บรักษาข้อมูลเป็นศูนย์ | + +--- + +### xAI + +1. ไปที่ [xAI console](https://console.x.ai/) สร้างบัญชี และสร้างคีย์ API + +2. เรียกใช้คำสั่ง `/connect` และค้นหา **xAI** + + ```txt + /connect + ``` + +3. ป้อนคีย์ xAI API ของคุณ + + ```txt + ┌ API key + │ + │ + └ enter + ``` + +4. รันคำสั่ง `/models` เพื่อเลือกโมเดลเช่น _Grok Beta_ + + ```txt + /models + ``` + +--- + +### Z.AI + +1. ไปที่ [Z.AI API console](https://z.ai/manage-apikey/apikey-list) สร้างบัญชี และคลิก **Create a new API key** + +2. เรียกใช้คำสั่ง `/connect` และค้นหา **Z.AI** + + ```txt + /connect + ``` + + หากคุณสมัครรับ **GLM Coding Plan** ให้เลือก **Z.AI Coding Plan** + +3. ป้อนคีย์ Z.AI API ของคุณ + + ```txt + ┌ API key + │ + │ + └ enter + ``` + +4. รันคำสั่ง `/models` เพื่อเลือกโมเดลเช่น _GLM-4.7_ + + ```txt + /models + ``` + +--- + +### ZenMux + +1. ไปที่ [ZenMux dashboard](https://zenmux.ai/settings/keys) คลิก **Create API Key** และคัดลอกคีย์ + +2. เรียกใช้คำสั่ง `/connect` และค้นหา ZenMux + + ```txt + /connect + ``` + +3. ป้อนคีย์ API สำหรับผู้ให้บริการ + + ```txt + ┌ API key + │ + │ + └ enter + ``` + +4. โมเดล ZenMux จำนวนมากถูกโหลดไว้ล่วงหน้าตามค่าเริ่มต้น รันคำสั่ง `/models` เพื่อเลือกโมเดลที่คุณต้องการ + + ```txt + /models + ``` + + คุณยังสามารถเพิ่มโมเดลเพิ่มเติมผ่านการกำหนดค่า opencode ของคุณได้ + + ```json title="opencode.json" {6} + { + "$schema": "https://opencode.ai/config.json", + "provider": { + "zenmux": { + "models": { + "somecoolnewmodel": {} + } + } + } + } + ``` + +--- + +## ผู้ให้บริการที่กำหนดเอง + +หากต้องการเพิ่มผู้ให้บริการที่ **เข้ากันได้กับ OpenAI** ใดๆ ที่ไม่มีรายชื่ออยู่ในคำสั่ง `/connect`: + +:::tip +คุณสามารถใช้ผู้ให้บริการที่เข้ากันได้กับ OpenAI กับ opencode ได้ ผู้ให้บริการ AI สมัยใหม่ส่วนใหญ่เสนอ API ที่เข้ากันได้กับ OpenAI +::: + +1. เรียกใช้คำสั่ง `/connect` และเลื่อนลงไปที่ **Other** + + ```bash + $ /connect + + ┌ Add credential + │ + ◆ Select provider + │ ... + │ ● Other + └ + ``` + +2. ป้อน ID เฉพาะสำหรับผู้ให้บริการ + + ```bash + $ /connect + + ┌ Add credential + │ + ◇ Enter provider id + │ myprovider + └ + ``` + + :::note + เลือก ID ที่น่าจดจำ คุณจะใช้ ID นี้ในไฟล์กำหนดค่าของคุณ + ::: + +3. ป้อนคีย์ API สำหรับผู้ให้บริการ + + ```bash + $ /connect + + ┌ Add credential + │ + ▲ This only stores a credential for myprovider - you will need to configure it in opencode.json, check the docs for examples. + │ + ◇ Enter your API key + │ sk-... + └ + ``` + +4. สร้างหรืออัปเดตไฟล์ `opencode.json` ของคุณในไดเร็กทอรีโครงการของคุณ: + + ```json title="opencode.json" ""myprovider"" {5-15} + { + "$schema": "https://opencode.ai/config.json", + "provider": { + "myprovider": { + "npm": "@ai-sdk/openai-compatible", + "name": "My AI ProviderDisplay Name", + "options": { + "baseURL": "https://api.myprovider.com/v1" + }, + "models": { + "my-model-name": { + "name": "My Model Display Name" + } + } + } + } + } + ``` + + นี่คือตัวเลือกการกำหนดค่า: + - **npm**: แพ็คเกจ AI SDK ที่จะใช้ `@ai-sdk/openai-compatible` สำหรับผู้ให้บริการที่เข้ากันได้กับ OpenAI + - **name**: ชื่อที่แสดงใน UI + - **models**: โมเดลที่มีจำหน่าย + - **options.baseURL**: URL จุดสิ้นสุด API + - **options.apiKey**: ตั้งค่าคีย์ API ทางเลือก หากไม่ได้ใช้การรับรองความถูกต้อง + - **options.headers**: ตั้งค่าส่วนหัวที่กำหนดเองได้ตามต้องการ + + ข้อมูลเพิ่มเติมเกี่ยวกับตัวเลือกขั้นสูงในตัวอย่างด้านล่าง + +5. รันคำสั่ง `/models` และผู้ให้บริการและโมเดลที่คุณกำหนดเองจะปรากฏในรายการตัวเลือก + +--- + +##### ตัวอย่าง + +นี่คือตัวอย่างการตั้งค่าตัวเลือก `apiKey`, `headers` และรุ่น `limit` + +```json title="opencode.json" {9,11,17-20} +{ + "$schema": "https://opencode.ai/config.json", + "provider": { + "myprovider": { + "npm": "@ai-sdk/openai-compatible", + "name": "My AI ProviderDisplay Name", + "options": { + "baseURL": "https://api.myprovider.com/v1", + "apiKey": "{env:ANTHROPIC_API_KEY}", + "headers": { + "Authorization": "Bearer custom-token" + } + }, + "models": { + "my-model-name": { + "name": "My Model Display Name", + "limit": { + "context": 200000, + "output": 65536 + } + } + } + } + } +} +``` + +รายละเอียดการกำหนดค่า: + +- **apiKey**: ตั้งค่าโดยใช้ไวยากรณ์ตัวแปร `env` [เรียนรู้เพิ่มเติม](/docs/config#env-vars) +- **headers**: ส่วนหัวที่กำหนดเองที่ส่งไปกับแต่ละคำขอ +- **limit.context**: โทเค็นอินพุตสูงสุดที่โมเดลยอมรับ +- **limit.output**: โทเค็นสูงสุดที่โมเดลสามารถสร้างได้ + +ฟิลด์ `limit` ช่วยให้ OpenCode เข้าใจว่าคุณมีบริบทเหลืออยู่เท่าใด ผู้ให้บริการมาตรฐานจะดึงข้อมูลเหล่านี้จาก models.dev โดยอัตโนมัติ + +--- + +## การแก้ไขปัญหา + +หากคุณประสบปัญหาในการกำหนดค่าผู้ให้บริการ ให้ตรวจสอบสิ่งต่อไปนี้: + +1. **ตรวจสอบการตั้งค่าการรับรองความถูกต้อง**: รัน `opencode auth list` เพื่อดูว่ามีการเพิ่มข้อมูลรับรอง + สำหรับผู้ให้บริการในการกำหนดค่าของคุณหรือไม่ + + สิ่งนี้ใช้ไม่ได้กับผู้ให้บริการเช่น Amazon Bedrock ซึ่งอาศัยตัวแปรสภาพแวดล้อมสำหรับการตรวจสอบสิทธิ์ + +2. สำหรับผู้ให้บริการที่กำหนดเอง ให้ตรวจสอบการกำหนดค่า opencode และ: + - ตรวจสอบให้แน่ใจว่า ID ผู้ให้บริการที่ใช้ในคำสั่ง `/connect` ตรงกับ ID ในการกำหนดค่า opencode ของคุณ + - ใช้แพ็คเกจ npm ที่ถูกต้องสำหรับผู้ให้บริการ ตัวอย่างเช่น ใช้ `@ai-sdk/cerebras` สำหรับ Cerebras และสำหรับผู้ให้บริการอื่นๆ ที่เข้ากันได้กับ OpenAI ให้ใช้ `@ai-sdk/openai-compatible` + - ตรวจสอบว่าใช้จุดสิ้นสุด API ที่ถูกต้องในฟิลด์ `options.baseURL` + +3. ป้อนคีย์ OpenCode API ของคุณ + + ```txt + ┌ API key + │ + │ + └ enter + ``` + 4. รันคำสั่ง `/models` เพื่อเลือกรุ่นเช่น _Qwen 3 Coder 480B_ ```txt diff --git a/packages/web/src/content/docs/th/sdk.mdx b/packages/web/src/content/docs/th/sdk.mdx index b592c1a4e4..3454b57667 100644 --- a/packages/web/src/content/docs/th/sdk.mdx +++ b/packages/web/src/content/docs/th/sdk.mdx @@ -117,6 +117,78 @@ try { --- +## ผลลัพธ์แบบมีโครงสร้าง + +คุณสามารถร้องขอผลลัพธ์ JSON แบบมีโครงสร้างจากโมเดลได้โดยระบุ `format` ด้วย JSON schema โมเดลจะใช้เครื่องมือ `StructuredOutput` เพื่อส่งคืน JSON ที่ผ่านการตรวจสอบความถูกต้องซึ่งตรงกับสคีมาของคุณ + +### การใช้งานพื้นฐาน + +```typescript +const result = await client.session.prompt({ + path: { id: sessionId }, + body: { + parts: [{ type: "text", text: "Research Anthropic and provide company info" }], + format: { + type: "json_schema", + schema: { + type: "object", + properties: { + company: { type: "string", description: "Company name" }, + founded: { type: "number", description: "Year founded" }, + products: { + type: "array", + items: { type: "string" }, + description: "Main products", + }, + }, + required: ["company", "founded"], + }, + }, + }, +}) + +// Access the structured output +console.log(result.data.info.structured_output) +// { company: "Anthropic", founded: 2021, products: ["Claude", "Claude API"] } +``` + +### ประเภทรูปแบบผลลัพธ์ + +| ประเภท | คำอธิบาย | +| ------------- | ----------------------------------------------------------------- | +| `text` | ค่าเริ่มต้น การตอบสนองข้อความมาตรฐาน (ไม่มีผลลัพธ์แบบมีโครงสร้าง) | +| `json_schema` | ส่งคืน JSON ที่ผ่านการตรวจสอบความถูกต้องซึ่งตรงกับสคีมาที่ระบุ | + +### รูปแบบ JSON Schema + +เมื่อใช้ `type: 'json_schema'` ให้ระบุ: + +| ฟิลด์ | Type | คำอธิบาย | +| ------------ | --------------- | --------------------------------------------------------------------- | +| `type` | `'json_schema'` | จำเป็น ระบุโหมด JSON schema | +| `schema` | `object` | จำเป็น วัตถุ JSON Schema ที่กำหนดโครงสร้างผลลัพธ์ | +| `retryCount` | `number` | ไม่จำเป็น จำนวนการลองใหม่สำหรับการตรวจสอบความถูกต้อง (ค่าเริ่มต้น: 2) | + +### การจัดการข้อผิดพลาด + +หากโมเดลล้มเหลวในการสร้างผลลัพธ์แบบมีโครงสร้างที่ถูกต้องหลังจากลองใหม่ครบทุกครั้ง การตอบสนองจะรวม `StructuredOutputError`: + +```typescript +if (result.data.info.error?.name === "StructuredOutputError") { + console.error("Failed to produce structured output:", result.data.info.error.message) + console.error("Attempts:", result.data.info.error.retries) +} +``` + +### แนวปฏิบัติที่ดีที่สุด + +1. **ระบุคำอธิบายที่ชัดเจน** ในคุณสมบัติสคีมาของคุณเพื่อช่วยให้โมเดลเข้าใจว่าข้อมูลใดที่ต้องดึงออกมา +2. **ใช้ `required`** เพื่อระบุฟิลด์ที่ต้องมี +3. **รักษาสคีมาให้โฟกัส** - สคีมาที่ซ้อนกันซับซ้อนอาจยากสำหรับโมเดลในการกรอกให้ถูกต้อง +4. **ตั้งค่า `retryCount` ที่เหมาะสม** - เพิ่มสำหรับสคีมาที่ซับซ้อน ลดลงสำหรับสคีมาที่เรียบง่าย + +--- + ## API SDK เปิดเผย API ของเซิร์ฟเวอร์ทั้งหมดผ่านไคลเอ็นต์ประเภทที่ปลอดภัย @@ -226,27 +298,27 @@ const { providers, default: defaults } = await client.config.providers() ### เซสชัน -| Method | คำอธิบาย | หมายเหตุ | -| ---------------------------------------------------------- | -------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | -| `session.list()` | แสดงรายการเซสชัน | ส่งคืน <a href={typesUrl}><code>เซสชัน[]</code></a> | -| `session.get({ path })` | รับเซสชัน | ส่งคืน <a href={typesUrl}><code>เซสชัน</code></a> | -| `session.children({ path })` | แสดงรายการเซสชันย่อย | ส่งคืน <a href={typesUrl}><code>เซสชัน[]</code></a> | -| `session.create({ body })` | สร้างเซสชัน | ส่งคืน <a href={typesUrl}><code>เซสชัน</code></a> | -| `session.delete({ path })` | ลบเซสชัน | ส่งคืน `boolean` | -| `session.update({ path, body })` | อัปเดตคุณสมบัติเซสชัน | ส่งคืน <a href={typesUrl}><code>เซสชัน</code></a> | -| `session.init({ path, body })` | วิเคราะห์แอปและสร้าง `AGENTS.md` | ส่งคืน `boolean` | -| `session.abort({ path })` | ยกเลิกเซสชันที่ทำงานอยู่ | ส่งคืน `boolean` | -| `session.share({ path })` | แบ่งปันเซสชั่น | ส่งคืน <a href={typesUrl}><code>เซสชัน</code></a> | -| `session.unshare({ path })` | เลิกแชร์เซสชัน | ส่งคืน <a href={typesUrl}><code>เซสชัน</code></a> | -| `session.summarize({ path, body })` | สรุปเซสชัน | ส่งคืน `boolean` | -| `session.messages({ path })` | แสดงรายการข้อความในเซสชัน | ส่งคืน `{ info: `<a href={typesUrl}><code>ข้อความ</code></a>`, parts: `<a href={typesUrl}><code>ส่วน[]</code></a>`}[]` | -| `session.message({ path })` | รับรายละเอียดข้อความ | ส่งคืน `{ info: `<a href={typesUrl}><code>ข้อความ</code></a>`, parts: `<a href={typesUrl}><code>ส่วน[]</code></a>`}` | -| `session.prompt({ path, body })` | ส่งข้อความแจ้ง | `body.noReply: true` ส่งคืน UserMessage (บริบทเท่านั้น) ค่าเริ่มต้นส่งคืน <a href={typesUrl}><code>AssistantMessage</code></a> พร้อมการตอบสนองของ AI | -| `session.command({ path, body })` | ส่งคำสั่งไปยังเซสชั่น | ส่งคืน `{ info: `<a href={typesUrl}><code>AssistantMessage</code></a>`, parts: `<a href={typesUrl}><code>ส่วน[]</code></a>`}` | -| `session.shell({ path, body })` | รันคำสั่ง shell | ส่งคืน <a href={typesUrl}><code>AssistantMessage</code></a> | -| `session.revert({ path, body })` | คืนค่าข้อความ | ส่งคืน <a href={typesUrl}><code>เซสชัน</code></a> | -| `session.unrevert({ path })` | คืนค่าข้อความที่เปลี่ยนกลับ | ส่งคืน <a href={typesUrl}><code>เซสชัน</code></a> | -| `postSessionByIdPermissionsByPermissionId({ path, body })` | ตอบสนองต่อการร้องขอการอนุญาต | ส่งคืน `boolean` | +| Method | คำอธิบาย | หมายเหตุ | +| ---------------------------------------------------------- | -------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `session.list()` | แสดงรายการเซสชัน | ส่งคืน <a href={typesUrl}><code>เซสชัน[]</code></a> | +| `session.get({ path })` | รับเซสชัน | ส่งคืน <a href={typesUrl}><code>เซสชัน</code></a> | +| `session.children({ path })` | แสดงรายการเซสชันย่อย | ส่งคืน <a href={typesUrl}><code>เซสชัน[]</code></a> | +| `session.create({ body })` | สร้างเซสชัน | ส่งคืน <a href={typesUrl}><code>เซสชัน</code></a> | +| `session.delete({ path })` | ลบเซสชัน | ส่งคืน `boolean` | +| `session.update({ path, body })` | อัปเดตคุณสมบัติเซสชัน | ส่งคืน <a href={typesUrl}><code>เซสชัน</code></a> | +| `session.init({ path, body })` | วิเคราะห์แอปและสร้าง `AGENTS.md` | ส่งคืน `boolean` | +| `session.abort({ path })` | ยกเลิกเซสชันที่ทำงานอยู่ | ส่งคืน `boolean` | +| `session.share({ path })` | แบ่งปันเซสชั่น | ส่งคืน <a href={typesUrl}><code>เซสชัน</code></a> | +| `session.unshare({ path })` | เลิกแชร์เซสชัน | ส่งคืน <a href={typesUrl}><code>เซสชัน</code></a> | +| `session.summarize({ path, body })` | สรุปเซสชัน | ส่งคืน `boolean` | +| `session.messages({ path })` | แสดงรายการข้อความในเซสชัน | ส่งคืน `{ info: `<a href={typesUrl}><code>ข้อความ</code></a>`, parts: `<a href={typesUrl}><code>ส่วน[]</code></a>`}[]` | +| `session.message({ path })` | รับรายละเอียดข้อความ | ส่งคืน `{ info: `<a href={typesUrl}><code>ข้อความ</code></a>`, parts: `<a href={typesUrl}><code>ส่วน[]</code></a>`}` | +| `session.prompt({ path, body })` | ส่งข้อความแจ้ง | `body.noReply: true` ส่งคืน UserMessage (บริบทเท่านั้น) ค่าเริ่มต้นส่งคืน <a href={typesUrl}><code>AssistantMessage</code></a> พร้อมการตอบสนองของ AI รองรับ `body.outputFormat` สำหรับ [ผลลัพธ์แบบมีโครงสร้าง](#ผลลัพธ์แบบมีโครงสร้าง) | +| `session.command({ path, body })` | ส่งคำสั่งไปยังเซสชั่น | ส่งคืน `{ info: `<a href={typesUrl}><code>AssistantMessage</code></a>`, parts: `<a href={typesUrl}><code>ส่วน[]</code></a>`}` | +| `session.shell({ path, body })` | รันคำสั่ง shell | ส่งคืน <a href={typesUrl}><code>AssistantMessage</code></a> | +| `session.revert({ path, body })` | คืนค่าข้อความ | ส่งคืน <a href={typesUrl}><code>เซสชัน</code></a> | +| `session.unrevert({ path })` | คืนค่าข้อความที่เปลี่ยนกลับ | ส่งคืน <a href={typesUrl}><code>เซสชัน</code></a> | +| `postSessionByIdPermissionsByPermissionId({ path, body })` | ตอบสนองต่อการร้องขอการอนุญาต | ส่งคืน `boolean` | --- diff --git a/packages/web/src/content/docs/th/share.mdx b/packages/web/src/content/docs/th/share.mdx index 195d7696f9..91bfce4417 100644 --- a/packages/web/src/content/docs/th/share.mdx +++ b/packages/web/src/content/docs/th/share.mdx @@ -41,7 +41,7 @@ OpenCode รองรับโหมดการแชร์สามโหม ```json title="opencode.json" { - "$schema": "https://opncd.ai/config.json", + "$schema": "https://opencode.ai/config.json", "share": "manual" } ``` @@ -54,7 +54,7 @@ OpenCode รองรับโหมดการแชร์สามโหม ```json title="opencode.json" { - "$schema": "https://opncd.ai/config.json", + "$schema": "https://opencode.ai/config.json", "share": "auto" } ``` @@ -69,7 +69,7 @@ OpenCode รองรับโหมดการแชร์สามโหม ```json title="opencode.json" { - "$schema": "https://opncd.ai/config.json", + "$schema": "https://opencode.ai/config.json", "share": "disabled" } ``` diff --git a/packages/web/src/content/docs/th/themes.mdx b/packages/web/src/content/docs/th/themes.mdx index 2244c3dcf1..44514148ea 100644 --- a/packages/web/src/content/docs/th/themes.mdx +++ b/packages/web/src/content/docs/th/themes.mdx @@ -61,11 +61,11 @@ OpenCode มาพร้อมกับธีมในตัวหลายธ ## การใช้ธีม -คุณสามารถเลือกธีมได้โดยเปิดการเลือกธีมขึ้นมาด้วยคำสั่ง `/theme` หรือคุณสามารถระบุได้ใน [config](/docs/config) +คุณสามารถเลือกธีมได้โดยเปิดการเลือกธีมขึ้นมาด้วยคำสั่ง `/theme` หรือคุณสามารถระบุได้ใน `tui.json` -```json title="opencode.json" {3} +```json title="tui.json" {3} { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "theme": "tokyonight" } ``` diff --git a/packages/web/src/content/docs/th/tui.mdx b/packages/web/src/content/docs/th/tui.mdx index 9151462d70..2a5064b9d7 100644 --- a/packages/web/src/content/docs/th/tui.mdx +++ b/packages/web/src/content/docs/th/tui.mdx @@ -235,7 +235,7 @@ How is auth handled in @packages/functions/src/api/index.ts? แสดงรายการธีมที่มีอยู่ ```bash frame="none" -/theme +/themes ``` **ผูกปุ่ม:** `ctrl+x t` @@ -355,24 +355,34 @@ How is auth handled in @packages/functions/src/api/index.ts? ## กำหนดค่า -คุณสามารถปรับแต่งพฤติกรรม TUI ผ่านไฟล์กำหนดค่า OpenCode ของคุณได้ +คุณสามารถปรับแต่งพฤติกรรม TUI ได้ผ่าน `tui.json` (หรือ `tui.jsonc`) -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", - "tui": { - "scroll_speed": 3, - "scroll_acceleration": { - "enabled": true - } - } + "$schema": "https://opencode.ai/tui.json", + "theme": "opencode", + "keybinds": { + "leader": "ctrl+x" + }, + "scroll_speed": 3, + "scroll_acceleration": { + "enabled": true + }, + "diff_style": "auto" } ``` +สิ่งนี้แยกจาก `opencode.json` ซึ่งกำหนดค่าพฤติกรรมเซิร์ฟเวอร์/รันไทม์ + ### ตัวเลือก -- `scroll_acceleration` - ​​เปิดใช้งานการเร่งความเร็วการเลื่อนแบบ macOS เพื่อการเลื่อนที่ราบรื่นและเป็นธรรมชาติ เมื่อเปิดใช้งาน ความเร็วในการเลื่อนจะเพิ่มขึ้นตามท่าทางการเลื่อนอย่างรวดเร็ว และคงความแม่นยำไว้สำหรับการเคลื่อนไหวที่ช้าลง **การตั้งค่านี้มีความสำคัญมากกว่า `scroll_speed` และแทนที่เมื่อเปิดใช้งาน** -- `scroll_speed` - ​​ควบคุมความเร็วของการเลื่อน TUI เมื่อใช้คำสั่งการเลื่อน (ขั้นต่ำ: `1`) ค่าเริ่มต้นเป็น `3` **หมายเหตุ: สิ่งนี้จะถูกละเว้นหากตั้งค่า `scroll_acceleration.enabled` เป็น `true`.** +- `theme` - ตั้งค่าธีม UI ของคุณ [เรียนรู้เพิ่มเติม](/docs/themes) +- `keybinds` - ปรับแต่งแป้นพิมพ์ลัด [เรียนรู้เพิ่มเติม](/docs/keybinds) +- `scroll_acceleration.enabled` - ​​เปิดใช้งานการเร่งความเร็วการเลื่อนแบบ macOS เพื่อการเลื่อนที่ราบรื่นและเป็นธรรมชาติ เมื่อเปิดใช้งาน ความเร็วในการเลื่อนจะเพิ่มขึ้นตามท่าทางการเลื่อนอย่างรวดเร็ว และคงความแม่นยำไว้สำหรับการเคลื่อนไหวที่ช้าลง **การตั้งค่านี้มีความสำคัญมากกว่า `scroll_speed` และแทนที่เมื่อเปิดใช้งาน** +- `scroll_speed` - ​​ควบคุมความเร็วของการเลื่อน TUI เมื่อใช้คำสั่งการเลื่อน (ขั้นต่ำ: `0.001` รองรับค่าทศนิยม) ค่าเริ่มต้นเป็น `3` **หมายเหตุ: สิ่งนี้จะถูกละเว้นหากตั้งค่า `scroll_acceleration.enabled` เป็น `true`.** +- `diff_style` - ควบคุมการเรนเดอร์ diff `"auto"` ปรับให้เข้ากับความกว้างของ terminal `"stacked"` จะแสดงคอลัมน์เดียวเสมอ + +ใช้ `OPENCODE_TUI_CONFIG` เพื่อโหลดเส้นทางการกำหนดค่า TUI แบบกำหนดเอง --- diff --git a/packages/web/src/content/docs/th/zen.mdx b/packages/web/src/content/docs/th/zen.mdx index f0b39ceaaa..36b2090807 100644 --- a/packages/web/src/content/docs/th/zen.mdx +++ b/packages/web/src/content/docs/th/zen.mdx @@ -64,31 +64,35 @@ OpenCode Zen ทำงานเหมือนกับผู้ให้บร | Model | Model ID | Endpoint | แพ็คเกจ AI SDK | | ------------------ | ------------------ | -------------------------------------------------- | --------------------------- | -| GPT 5.2 | GPT-5.2 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| GPT 5.4 | gpt-5.4 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| GPT 5.3 Codex | gpt-5.3-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| GPT 5.2 | gpt-5.2 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.2 Codex | gpt-5.2-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | -| GPT 5.1 | GPT-5.1 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| GPT 5.1 | gpt-5.1 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.1 Codex | gpt-5.1-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.1 Codex Max | gpt-5.1-codex-max | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.1 Codex Mini | gpt-5.1-codex-mini | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | -| GPT 5 | GPT-5 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| GPT 5 | gpt-5 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5 Codex | gpt-5-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5 Nano | gpt-5-nano | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | -| Claude Sonnet 4.5 | claude-sonnet-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| Claude Sonnet 4 | claude-sonnet-4 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| Claude Haiku 4.5 | claude-haiku-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| Claude Haiku 3.5 | claude-haiku-3-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Opus 4.6 | claude-opus-4-6 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Opus 4.5 | claude-opus-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Opus 4.1 | claude-opus-4-1 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Sonnet 4.6 | claude-sonnet-4-6 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Sonnet 4.5 | claude-sonnet-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Sonnet 4 | claude-sonnet-4 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Haiku 4.5 | claude-haiku-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Haiku 3.5 | claude-3-5-haiku | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Gemini 3.1 Pro | gemini-3.1-pro | `https://opencode.ai/zen/v1/models/gemini-3.1-pro` | `@ai-sdk/google` | | Gemini 3 Pro | gemini-3-pro | `https://opencode.ai/zen/v1/models/gemini-3-pro` | `@ai-sdk/google` | | Gemini 3 Flash | gemini-3-flash | `https://opencode.ai/zen/v1/models/gemini-3-flash` | `@ai-sdk/google` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.5 Free | minimax-m2.5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.1 | minimax-m2.1 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.1 Free | minimax-m2.1-free | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| GLM 5 | glm-5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | GLM 4.7 | glm-4.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM 4.7 Free | glm-4.7-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | GLM 4.6 | glm-4.6 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 Free | kimi-k2.5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2 Thinking | kimi-k2-thinking | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2 | kimi-k2 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Qwen3 Coder 480B | qwen3-coder | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -114,41 +118,47 @@ https://opencode.ai/zen/v1/models เราสนับสนุนรูปแบบการจ่ายเงินตามการใช้งาน ด้านล่างนี้คือราคา **ต่อtokens 1M** -| Model | ป้อนข้อมูล | เอาท์พุต | แคชอ่าน | เขียนในแคช | -| --------------------------------------- | ------------ | ------------ | ------------- | ---------- | -| Big Pickle | ฟรี | ฟรี | ฟรี | - | -| MiniMax M2.1 Free | ฟรี | ฟรี | ฟรี | - | -| Miniแม็กซ์ M2.1 | $0.30 | $1.20 | $0.10 | - | -| GLM 4.7 Free | ฟรี | ฟรี | ฟรี | - | -| GLM 4.7 | $0.60 | $2.20 | $0.10 | - | -| GLM 4.6 | $0.60 | $2.20 | $0.10 | - | -| Kimi K2.5 Free | ฟรี | ฟรี | ฟรี | - | -| Kimi K2.5 | $0.60 | $3.00 | $0.08 | - | -| Kimi K2 Thinking | $0.40 | $2.50 | - | - | -| Kimi K2 | $0.40 | $2.50 | - | - | -| Qwen3 Coder 480B | $0.45 | $1.50 | - | - | -| Claude Sonnet 4.5 (tokens ≤ 200K) | $3.00 | $15.00 | $0.30 | $3.75 | -| Claude Sonnet 4.5 (> tokens 200,000) | $6.00 | $22.50 | $0.60 | $7.50 | -| Claude Sonnet 4 (tokens 200,000 tokens) | $3.00 | $15.00 | $0.30 | $3.75 | -| Claude Sonnet 4 (> tokens 200,000) | $6.00 | $22.50 | $0.60 | $7.50 | -| Claude Haiku 4.5 | $1.00 | $5.00 | $0.10 | $1.25 | -| Claude Haiku 3.5 | $0.80 | $4.00 | $0.08 | $1.00 | -| Claude Opus 4.6 (tokens ≤ 200K) | $5.00 | $25.00 | $0.50 | $6.25 | -| Claude Opus 4.6 (> tokens 200,000) | $10.00 | $37.50 | $1.00 | $12.50 | -| Claude Opus 4.5 | $5.00 | $25.00 | $0.50 | $6.25 | -| Claude Opus 4.1 | $15.00 | $75.00 | $1.50 | $18.75 | -| Gemini 3 Pro (tokens ≤ 200,000) | 2.00 ดอลลาร์ | $12.00 | $0.20 | - | -| Gemini 3 Pro (tokens> 200,000) | $4.00 | $18.00 | $0.40 | - | -| Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | -| GPT 5.2 | $1.75 | $14.00 | 0.175 ดอลลาร์ | - | -| GPT 5.2 Codex | $1.75 | $14.00 | 0.175 ดอลลาร์ | - | -| GPT 5.1 | $1.07 | 8.50 ดอลลาร์ | $0.107 | - | -| GPT 5.1 Codex | $1.07 | 8.50 ดอลลาร์ | $0.107 | - | -| GPT 5.1 CodexMax | $1.25 | $10.00 | $0.125 | - | -| GPT 5.1 CodexMini | $0.25 | 2.00 ดอลลาร์ | 0.025 ดอลลาร์ | - | -| GPT 5 | $1.07 | 8.50 ดอลลาร์ | $0.107 | - | -| GPT 5 Codex | $1.07 | 8.50 ดอลลาร์ | $0.107 | - | -| GPT 5Nano | ฟรี | ฟรี | ฟรี | - | +| Model | ป้อนข้อมูล | เอาท์พุต | แคชอ่าน | เขียนในแคช | +| --------------------------------- | ---------- | -------- | ------- | ---------- | +| Big Pickle | ฟรี | ฟรี | ฟรี | - | +| MiniMax M2.5 Free | ฟรี | ฟรี | ฟรี | - | +| MiniMax M2.5 | $0.30 | $1.20 | $0.06 | $0.375 | +| MiniMax M2.1 | $0.30 | $1.20 | $0.10 | - | +| GLM 5 | $1.00 | $3.20 | $0.20 | - | +| GLM 4.7 | $0.60 | $2.20 | $0.10 | - | +| GLM 4.6 | $0.60 | $2.20 | $0.10 | - | +| Kimi K2.5 | $0.60 | $3.00 | $0.10 | - | +| Kimi K2 Thinking | $0.40 | $2.50 | - | - | +| Kimi K2 | $0.40 | $2.50 | - | - | +| Qwen3 Coder 480B | $0.45 | $1.50 | - | - | +| Claude Opus 4.6 (≤ 200K tokens) | $5.00 | $25.00 | $0.50 | $6.25 | +| Claude Opus 4.6 (> 200K tokens) | $10.00 | $37.50 | $1.00 | $12.50 | +| Claude Opus 4.5 | $5.00 | $25.00 | $0.50 | $6.25 | +| Claude Opus 4.1 | $15.00 | $75.00 | $1.50 | $18.75 | +| Claude Sonnet 4.6 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 | +| Claude Sonnet 4.6 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 | +| Claude Sonnet 4.5 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 | +| Claude Sonnet 4.5 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 | +| Claude Sonnet 4 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 | +| Claude Sonnet 4 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 | +| Claude Haiku 4.5 | $1.00 | $5.00 | $0.10 | $1.25 | +| Claude Haiku 3.5 | $0.80 | $4.00 | $0.08 | $1.00 | +| Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | +| Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | +| Gemini 3 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | +| Gemini 3 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | +| Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | +| GPT 5.4 | $2.50 | $15.00 | $0.25 | - | +| GPT 5.3 Codex | $1.75 | $14.00 | $0.175 | - | +| GPT 5.2 | $1.75 | $14.00 | $0.175 | - | +| GPT 5.2 Codex | $1.75 | $14.00 | $0.175 | - | +| GPT 5.1 | $1.07 | $8.50 | $0.107 | - | +| GPT 5.1 Codex | $1.07 | $8.50 | $0.107 | - | +| GPT 5.1 Codex Max | $1.25 | $10.00 | $0.125 | - | +| GPT 5.1 Codex Mini | $0.25 | $2.00 | $0.025 | - | +| GPT 5 | $1.07 | $8.50 | $0.107 | - | +| GPT 5 Codex | $1.07 | $8.50 | $0.107 | - | +| GPT 5 Nano | ฟรี | ฟรี | ฟรี | - | คุณอาจสังเกตเห็น _Claude Haiku 3.5_ ในประวัติการใช้งานของคุณ นี่คือ [โมเดลราคาประหยัด](/docs/config/#models) ที่ใช้ในการสร้างชื่อเซสชันของคุณ @@ -158,9 +168,7 @@ https://opencode.ai/zen/v1/models รุ่นฟรี: -- GLM 4.7 ใช้งานได้ฟรีบน OpenCode ในระยะเวลาจำกัด ทีมงานใช้เวลานี้เพื่อรวบรวมคำติชมและปรับปรุงโมเดล -- Kimi K2.5 Free พร้อมใช้งานบน OpenCode ในระยะเวลาจำกัด ทีมงานใช้เวลานี้เพื่อรวบรวมคำติชมและปรับปรุงโมเดล -- MiniMax M2.1 Free พร้อมใช้งานบน OpenCode ในระยะเวลาจำกัด ทีมงานใช้เวลานี้เพื่อรวบรวมคำติชมและปรับปรุงโมเดล +- MiniMax M2.5 Free พร้อมใช้งานบน OpenCode ในระยะเวลาจำกัด ทีมงานใช้เวลานี้เพื่อรวบรวมคำติชมและปรับปรุงโมเดล - Big Pickle เป็นโมเดลล่องหนที่ให้บริการฟรีบน OpenCode ในระยะเวลาจำกัด ทีมงานใช้เวลานี้เพื่อรวบรวมคำติชมและปรับปรุงโมเดล <a href={email}>Contact us</a> if you have any questions. @@ -186,14 +194,25 @@ https://opencode.ai/zen/v1/models --- +### โมเดลที่เลิกใช้แล้ว + +| Model | วันที่เลิกใช้ | +| ---------------- | ------------- | +| Qwen3 Coder 480B | 6 ก.พ. 2026 | +| Kimi K2 Thinking | 6 มี.ค. 2026 | +| Kimi K2 | 6 มี.ค. 2026 | +| MiniMax M2.1 | 15 มี.ค. 2026 | +| GLM 4.7 | 15 มี.ค. 2026 | +| GLM 4.6 | 15 มี.ค. 2026 | + +--- + ## ความเป็นส่วนตัว โมเดลทั้งหมดของเราโฮสต์ในสหรัฐอเมริกา ผู้ให้บริการของเราปฏิบัติตามนโยบายการเก็บรักษาเป็นศูนย์ และไม่ใช้ข้อมูลของคุณสำหรับการฝึกโมเดล โดยมีข้อยกเว้นต่อไปนี้: -- Big Pickle: ในช่วงระยะเวลาว่าง ข้อมูลที่รวบรวมอาจนำไปใช้ในการปรับปรุงโมเดลได้ -- GLM 4.7 Free: ในช่วงระยะเวลาฟรี ข้อมูลที่รวบรวมอาจนำไปใช้ในการปรับปรุงโมเดล -- Kimi K2.5 Free: ในช่วงระยะเวลาฟรี ข้อมูลที่รวบรวมอาจนำไปใช้ในการปรับปรุงโมเดล -- MiniMax M2.1 Free: ในช่วงระยะเวลาฟรี ข้อมูลที่รวบรวมอาจนำไปใช้ในการปรับปรุงโมเดล +- Big Pickle: ในช่วงระยะเวลาฟรี ข้อมูลที่รวบรวมอาจนำไปใช้ในการปรับปรุงโมเดลได้ +- MiniMax M2.5 Free: ในช่วงระยะเวลาฟรี ข้อมูลที่รวบรวมอาจนำไปใช้ในการปรับปรุงโมเดล - OpenAI API: คำขอจะถูกเก็บไว้เป็นเวลา 30 วันตาม [นโยบายข้อมูลของ OpenAI](https://platform.openai.com/docs/guides/your-data) - Anthropic API: คำขอจะถูกเก็บไว้เป็นเวลา 30 วันตาม [นโยบายข้อมูลของ Anthropic](https://docs.anthropic.com/en/docs/claude-code/data-usage) diff --git a/packages/web/src/content/docs/themes.mdx b/packages/web/src/content/docs/themes.mdx index d37ce31355..8a7c6a46ac 100644 --- a/packages/web/src/content/docs/themes.mdx +++ b/packages/web/src/content/docs/themes.mdx @@ -61,11 +61,11 @@ The system theme is for users who: ## Using a theme -You can select a theme by bringing up the theme select with the `/theme` command. Or you can specify it in your [config](/docs/config). +You can select a theme by bringing up the theme select with the `/theme` command. Or you can specify it in `tui.json`. -```json title="opencode.json" {3} +```json title="tui.json" {3} { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "theme": "tokyonight" } ``` diff --git a/packages/web/src/content/docs/tr/agents.mdx b/packages/web/src/content/docs/tr/agents.mdx index 47c16abf12..1f582511be 100644 --- a/packages/web/src/content/docs/tr/agents.mdx +++ b/packages/web/src/content/docs/tr/agents.mdx @@ -21,7 +21,7 @@ opencode'da iki tür agent vardır; birincil agent'lar ve alt agent'lar. ### Birincil agent'lar -Birincil agent'lar, doğrudan etkileşim kurduğunuz ana yardımcılardır. **Sekme** tuşunu veya yapılandırılmış `switch_agent` tuş atamanızı kullanarak bunlar arasında geçiş yapabilirsiniz. Bu agent'lar ana görüşmenizi yönetir. Araç erişimi, izinler aracılığıyla yapılandırılır; örneğin, Plan kısıtlıyken Build'de tüm araçlar etkindir. +Birincil agent'lar, doğrudan etkileşim kurduğunuz ana yardımcılardır. **Sekme** tuşunu veya yapılandırılmış `switch_agent` tuş atamanızı kullanarak bunlar arasında geçiş yapabilirsiniz. Bu agent'lar ana görüşmenizi yönetir. Araç erişimi, izinler aracılığıyla yapılandırılır; örneğin, Build'de tüm araçlar etkindir ancak Plan kısıtlıdır. :::tip Bir oturum sırasında birincil agent'lar arasında geçiş yapmak için **Sekme** tuşunu kullanabilirsiniz. @@ -83,7 +83,7 @@ Kod tabanlarını keşfetmeye yönelik hızlı, salt okunur bir agent. Dosyalar --- -### Compact Kullanımı +### Compaction Kullanımı _Mod_: `primary` @@ -181,7 +181,7 @@ Agent'ları `opencode.json` yapılandırma dosyanızda yapılandırın: Ayrıca agent'ları Markdown dosyalarını kullanarak da tanımlayabilirsiniz. Bunları şuraya yerleştirin: - Global: `~/.config/opencode/agents/` -- Per-project: `.opencode/agents/` +- Proje başına: `.opencode/agents/` ```markdown title="~/.config/opencode/agents/review.md" --- @@ -342,10 +342,10 @@ Bu yol, yapılandırma dosyasının bulunduğu yere göredir. Yani bu hem global ### Model -Bu agent'ın kodu geçersiz için `model` ayarını kullanın. Farklı bölümler için optimize edilmiş farklı modelleri kullanmak için kullanışlıdır. Örneğin planlama için daha hızlı bir model, uygulama için daha yetenekli bir model. +Bu agent'ın modelini geçersiz kılmak için `model` ayarını kullanın. Farklı bölümler için optimize edilmiş farklı modelleri kullanmak için kullanışlıdır. Örneğin planlama için daha hızlı bir model, uygulama için daha yetenekli bir model. :::tip -Bir model belirtmezseniz, birincil agent'lar [model globally configured](/docs/config#models)'yi kullanırken alt agent'lar, alt agent'ı çağıran birincil agent'ın modelini kullanır. +Bir model belirtmezseniz, birincil agent'lar [küresel olarak yapılandırılmış modeli](/docs/config#models) kullanırken alt agent'lar, alt agent'ı çağıran birincil agent'ın modelini kullanır. ::: ```json title="opencode.json" @@ -358,7 +358,7 @@ Bir model belirtmezseniz, birincil agent'lar [model globally configured](/docs/c } ``` -opencode hesabınızdaki model kimliğini `provider/model-id` biçimini kullanır. Örneğin, [OpenCode Zen](/docs/zen) kullanıyorsanız, GPT 5.1 Codex için `opencode/gpt-5.1-codex` kullanırsınız. +opencode yapılandırmanızdaki model kimliği `provider/model-id` biçimini kullanır. Örneğin, [OpenCode Zen](/docs/zen) kullanıyorsanız, GPT 5.1 Codex için `opencode/gpt-5.1-codex` kullanırsınız. --- @@ -599,7 +599,7 @@ Kullanıcılar, agent'ın görev izinleri bunu reddetse bile, her zaman herhangi Agent'ın kullanıcı arayüzündeki görsel görünümünü `color` seçeneğiyle özelleştirin. Bu, agent'ın arayüzde nasıl göründüğünü etkiler. -geçerli bir onaltılık renk (ör. `#FF5733`) veya tema rengini kullanın: `primary`, `secondary`, `accent`, `success`, `warning`, `error`, `info`. +Geçerli bir onaltılık renk (ör. `#FF5733`) veya tema rengini kullanın: `primary`, `secondary`, `accent`, `success`, `warning`, `error`, `info`. ```json title="opencode.json" { @@ -744,627 +744,3 @@ Look for: - Dependency vulnerabilities - Configuration security issues ``` - -3. **Oturumlar arasında gezinme**: Subagent'lar kendi alt oturumlarını oluşturduğunda, aşağıdakileri kullanarak ana oturum ile tüm alt oturumlar arasında gezinebilirsiniz: - - **\<Leader>+Right** (veya yapılandırılmış `session_child_cycle` tuş atamanız) ebeveyn → çocuk1 → çocuk2 → ... → ebeveyn arasında ileri doğru geçiş yapmak için - - **\<Leader>+Left** (veya yapılandırılmış `session_child_cycle_reverse` tuş atamanız) ebeveyn ← çocuk1 ← çocuk2 ← ... ← ebeveyn arasında geriye doğru geçiş yapmak için - - Bu, ana görüşme ile özel subagent çalışması arasında sorunsuz bir şekilde geçiş yapmanıza olanak tanır. - ---- - -## Yapılandırma veya yapılandırma yoluyla kendinizinkini oluşturabilirsiniz. Agent'lar iki şekilde yapılandırılabilir: - ---- - -### JSON - -Agent'ları `opencode.json` yapılandırma dosyanızda yapılandırın: - -```json title="opencode.json" -{ - "$schema": "https://opencode.ai/config.json", - "agent": { - "build": { - "mode": "primary", - "model": "anthropic/claude-sonnet-4-20250514", - "prompt": "{file:./prompts/build.txt}", - "tools": { - "write": true, - "edit": true, - "bash": true - } - }, - "plan": { - "mode": "primary", - "model": "anthropic/claude-haiku-4-20250514", - "tools": { - "write": false, - "edit": false, - "bash": false - } - }, - "code-reviewer": { - "description": "Reviews code for best practices and potential issues", - "mode": "subagent", - "model": "anthropic/claude-sonnet-4-20250514", - "prompt": "You are a code reviewer. Focus on security, performance, and maintainability.", - "tools": { - "write": false, - "edit": false - } - } - } -} -``` - ---- - -### Markdown - -Ayrıca agent'ları Markdown dosyalarını kullanarak da tanımlayabilirsiniz. Bunları şuraya yerleştirin: - -- Global: `~/.config/opencode/agents/` -- Per-project: `.opencode/agents/` - -```markdown title="~/.config/opencode/agents/review.md" ---- -description: Reviews code for quality and best practices -mode: subagent -model: anthropic/claude-sonnet-4-20250514 -temperature: 0.1 -tools: - write: false - edit: false - bash: false ---- - -You are in code review mode. Focus on: - -- Code quality and best practices -- Potential bugs and edge cases -- Performance implications -- Security considerations - -Provide constructive feedback without making direct changes. -``` - -Markdown dosyasının adı agent'ın adı olur. Örneğin, `review.md` bir `review` agent'ı oluşturur. - ---- - -## Seçenekler - -Bu yapılandırma seçeneklerine ayrıntılı olarak bakalım. - ---- - -### Açıklama - -Agent'ın ne yaptığına ve ne zaman kullanılacağına ilişkin kısa bir açıklama sağlamak için `description` seçeneğini kullanın. - -```json title="opencode.json" -{ - "agent": { - "review": { - "description": "Reviews code for best practices and potential issues" - } - } -} -``` - -Bu **gerekli** bir yapılandırma seçeneğidir. - ---- - -### Sıcaklık - -LLM'nin yanıtlarının rastgeleliğini ve yaratıcılığını `temperature` yapılandırmasıyla kontrol edin. - -Düşük değerler yanıtları daha odaklı ve belirleyici hale getirirken, yüksek değerler yaratıcılığı ve değişkenliği artırır. - -```json title="opencode.json" -{ - "agent": { - "plan": { - "temperature": 0.1 - }, - "creative": { - "temperature": 0.8 - } - } -} -``` - -Sıcaklık değerleri tipik olarak 0,0 ila 1,0 arasındadır: - -- **0,0-0,2**: Çok odaklı ve belirleyici yanıtlar, kod analizi ve planlama için idealdir -- **0,3-0,5**: Biraz yaratıcılık içeren dengeli yanıtlar, genel gelişim görevleri için iyi -- **0,6-1,0**: Daha yaratıcı ve çeşitli yanıtlar, beyin fırtınası ve keşif için yararlı - -```json title="opencode.json" -{ - "agent": { - "analyze": { - "temperature": 0.1, - "prompt": "{file:./prompts/analysis.txt}" - }, - "build": { - "temperature": 0.3 - }, - "brainstorm": { - "temperature": 0.7, - "prompt": "{file:./prompts/creative.txt}" - } - } -} -``` - -Sıcaklık belirtilmezse opencode modeline özgü varsayılanları kullanır; çoğu model için genellikle 0, Qwen modelleri için 0,55. - ---- - -### Maksimum adım - -Bir agent'ın yalnızca metinle yanıt vermeye zorlanmadan önce gerçekleştirebileceği maksimum agent yineleme sayısını kontrol edin. Bu, maliyetleri kontrol etmek isteyen kullanıcıların agent eylemlerine bir sınır koymasına olanak tanır. - -Bu ayarlanmazsa, model durmayı seçene veya kullanıcı oturumu kesene kadar agent yinelemeye devam edecektir. - -```json title="opencode.json" -{ - "agent": { - "quick-thinker": { - "description": "Fast reasoning with limited iterations", - "prompt": "You are a quick thinker. Solve problems with minimal steps.", - "steps": 5 - } - } -} -``` - -Sınıra ulaşıldığında, agent, işinin özeti ve önerilen kalan görevlerin bir özetiyle yanıt vermesi talimatını veren özel bir sistem prompt'u alır. - -:::caution -Eski `maxSteps` alanı kullanımdan kaldırıldı. Bunun yerine `steps` kullanın. -::: - ---- - -### Devre dışı bırakma - -Agent'ı devre dışı bırakmak için `true` olarak ayarlayın. - -```json title="opencode.json" -{ - "agent": { - "review": { - "disable": true - } - } -} -``` - ---- - -### İstem - -Bu agent için `prompt` yapılandırmasıyla özel bir sistem prompt dosyası belirtin. Prompt dosyası, agent'ın amacına özel talimatlar içermelidir. - -```json title="opencode.json" -{ - "agent": { - "review": { - "prompt": "{file:./prompts/code-review.txt}" - } - } -} -``` - -Bu yol, yapılandırma dosyasının bulunduğu yere göredir. Yani bu hem global opencode yapılandırması hem de projeye özel yapılandırma için işe yarar. - ---- - -### Model - -Bu agent'ın varsayılan modelini geçersiz kılmak için `model` ayarını kullanın. Farklı bölümler için optimize edilmiş farklı modelleri kullanmak için kullanışlıdır. Örneğin planlama için daha hızlı bir model, uygulama için daha yetenekli bir model. - -:::tip -Bir model belirtmezseniz, primary agent'lar [model globally configured](/docs/config#models)'yi kullanırken subagent'lar, subagent'ı çağıran primary agent'ın modelini kullanır. -::: - -```json title="opencode.json" -{ - "agent": { - "plan": { - "model": "anthropic/claude-haiku-4-20250514" - } - } -} -``` - -opencode hesabınızdaki model kimliğini `provider/model-id` biçimini kullanır. Örneğin, [OpenCode Zen](/docs/zen) kullanıyorsanız, GPT 5.1 Codex için `opencode/gpt-5.1-codex` kullanırsınız. - ---- - -### Araçlar - -`tools` yapılandırmasıyla bu agent'ta hangi araçların mevcut olduğunu kontrol edin. Belirli araçları `true` veya `false` olarak ayarlayarak etkinleştirebilir veya devre dışı bırakabilirsiniz. - -```json title="opencode.json" {3-6,9-12} -{ - "$schema": "https://opencode.ai/config.json", - "tools": { - "write": true, - "bash": true - }, - "agent": { - "plan": { - "tools": { - "write": false, - "bash": false - } - } - } -} -``` - -:::note -Agent'a özgü yapılandırma, genel yapılandırmayı geçersiz kılar. -::: - -Aynı anda birden fazla aracı kontrol etmek için joker karakterleri de kullanabilirsiniz. Örneğin, bir MCP sunucusundaki tüm araçları devre dışı bırakmak için: - -```json title="opencode.json" -{ - "$schema": "https://opencode.ai/config.json", - "agent": { - "readonly": { - "tools": { - "mymcp_*": false, - "write": false, - "edit": false - } - } - } -} -``` - -[Araçlar hakkında daha fazla bilgi](/docs/tools). - ---- - -### İzinler - -Bir agent'ın gerçekleştirebileceği eylemleri yönetmek için izinleri yapılandırabilirsiniz. Şu anda `edit`, `bash` ve `webfetch` araçlarının izinleri şu şekilde yapılandırılabilir: - -- `"ask"` — Agent çalıştırmadan önce onay iste -- `"allow"` — Onay olmadan tüm işlemlere izin ver -- `"deny"` — Agent'ı devre dışı bırakır - -```json title="opencode.json" -{ - "$schema": "https://opencode.ai/config.json", - "permission": { - "edit": "deny" - } -} -``` - -Bu izinleri agent başına geçersiz kılabilirsiniz. - -```json title="opencode.json" {3-5,8-10} -{ - "$schema": "https://opencode.ai/config.json", - "permission": { - "edit": "deny" - }, - "agent": { - "build": { - "permission": { - "edit": "ask" - } - } - } -} -``` - -İzinleri Markdown agent'larında da ayarlayabilirsiniz. - -```markdown title="~/.config/opencode/agents/review.md" ---- -description: Code review without edits -mode: subagent -permission: - edit: deny - bash: - "*": ask - "git diff": allow - "git log*": allow - "grep *": allow - webfetch: deny ---- - -Only analyze code and suggest changes. -``` - -Belirli bash komutları için izinleri ayarlayabilirsiniz. - -```json title="opencode.json" {7} -{ - "$schema": "https://opencode.ai/config.json", - "agent": { - "build": { - "permission": { - "bash": { - "git push": "ask", - "grep *": "allow" - } - } - } - } -} -``` - -Bu küresel bir desen alabilir. - -```json title="opencode.json" {7} -{ - "$schema": "https://opencode.ai/config.json", - "agent": { - "build": { - "permission": { - "bash": { - "git *": "ask" - } - } - } - } -} -``` - -Ayrıca tüm komutların izinlerini yönetmek için `*` joker karakterini de kullanabilirsiniz. -Son eşleşen kural öncelikli olduğundan, `*` joker karakterini ilk sıraya ve belirli kuralları sonraya koyun. - -```json title="opencode.json" {8} -{ - "$schema": "https://opencode.ai/config.json", - "agent": { - "build": { - "permission": { - "bash": { - "*": "ask", - "git status *": "allow" - } - } - } - } -} -``` - -[İzinler hakkında daha fazla bilgi](/docs/permissions). - ---- - -### Mod - -Agent'ın modunu `mode` yapılandırmasıyla kontrol edin. `mode` seçeneği agent'ın nasıl kullanılabileceğini belirlemek için kullanılır. - -```json title="opencode.json" -{ - "agent": { - "review": { - "mode": "subagent" - } - } -} -``` - -`mode` seçeneği `primary`, `subagent` veya `all` olarak ayarlanabilir. `mode` belirtilmezse varsayılan olarak `all` olur. - ---- - -### Gizli - -`@` otomatik tamamlama menüsünden bir subagent'ı `hidden: true` ile gizleyin. Yalnızca diğer agent'lar tarafından Task aracı aracılığıyla programlı olarak çağrılması gereken dahili subagent'lar için kullanışlıdır. - -```json title="opencode.json" -{ - "agent": { - "internal-helper": { - "mode": "subagent", - "hidden": true - } - } -} -``` - -Bu yalnızca otomatik menüdeki kullanıcının görünümlerinin etkileri. İzinler izin vermesine, gizli agent'lar modeli tarafından Task aracı aracılığıyla çağrılmaya devam edilebilir. - -:::note -Yalnızca `mode: subagent` agent'ları için geçerlidir. -::: - ---- - -### Görev izinleri - -`permission.task` ile bir agent'ın Task aracı aracılığıyla hangi subagent'ları çağırabileceğini kontrol edin. Esnek eşleştirme için küresel desenleri kullanır. - -```json title="opencode.json" -{ - "agent": { - "orchestrator": { - "mode": "primary", - "permission": { - "task": { - "*": "deny", - "orchestrator-*": "allow", - "code-reviewer": "ask" - } - } - } - } -} -``` - -`deny` olarak ayarlandığında, subagent Task aracı açıklamasından tamamen kaldırılır, böylece model onu çağırmaya çalışmaz. - -:::tip -Kurallar sırayla değerlendirilir ve **son eşleşen kural kazanır**. Yukarıdaki örnekte `orchestrator-planner`, hem `*` (reddet) hem de `orchestrator-*` (izin ver) ile eşleşir, ancak `orchestrator-*`, `*`'den sonra geldiğinden sonuç `allow` olur. -::: - -:::tip -Kullanıcılar, agent'ın görev izinleri bunu reddetse bile, her zaman herhangi bir subagent'ı `@` otomatik tamamlama menüsü aracılığıyla doğrudan çağırabilir. -::: - ---- - -### Renk - -Agent'ın kullanıcı arayüzündeki görsel görünümünü `color` seçeneğiyle özelleştirin. Bu, agent'ın arayüzde nasıl göründüğünü etkiler. - -geçerli bir onaltılık renk (ör. `#FF5733`) veya tema rengini kullanın: `primary`, `secondary`, `accent`, `success`, `warning`, `error`, `info`. - -```json title="opencode.json" -{ - "agent": { - "creative": { - "color": "#ff6b6b" - }, - "code-reviewer": { - "color": "accent" - } - } -} -``` - ---- - -### Top P - -`top_p` seçeneğiyle yanıt çeşitliliğini kontrol edin. Rastgeleliği kontrol etmek için sıcaklığa alternatif. - -```json title="opencode.json" -{ - "agent": { - "brainstorm": { - "top_p": 0.9 - } - } -} -``` - -Değerler 0,0 ile 1,0 arasında değişir. Düşük değerler daha odaklıdır, yüksek değerler ise daha çeşitlidir. - ---- - -### Ek - -Agent yapılandırmanızdaki diğer seçenekler, model seçenekleri olarak **doğrudan sağlayıcıya** iletilecektir. Bu, sağlayıcıya özgü özelliklerin kullanılmasını sağlar. - -Örneğin OpenAI'nin akıl yürütme modelleriyle akıl yürütme çabasını kontrol edebilirsiniz: - -```json title="opencode.json" {6,7} -{ - "agent": { - "deep-thinker": { - "description": "Agent that uses high reasoning effort for complex problems", - "model": "openai/gpt-5", - "reasoningEffort": "high", - "textVerbosity": "low" - } - } -} -``` - -Bu ek seçenekler modele ve sağlayıcıya özeldir. Kullanılabilir parametreler için sağlayıcınızın belgelerine bakın. - -:::tip -Mevcut modellerin listesini görmek için `opencode models` komutunu çalıştırın. -::: - ---- - -## Agent Oluşturma - -Aşağıdaki komutu kullanarak yeni agent'lar oluşturabilirsiniz: - -```bash -opencode agent create -``` - -Bu etkileşimli komut şunları sağlayacaktır: - -1. Agent'ı nereye kaydedeceğinizi sorun; küresel veya projeye özel. -2. Agent'ın ne yapması gerektiğinin açıklaması. -3. Uygun bir sistem istemi ve tanımlayıcı oluşturun. -4. Agent'ın hangi araçlara erişebileceğini seçmenize izin verin. -5. Son olarak agent yapılandırmasıyla bir Markdown dosyası oluşturun. - ---- - -## Kullanım Senaryoları - -Farklı agent'lara yönelik bazı yaygın kullanım senaryoları aşağıda verilmiştir. - -- **Build agent**: Tüm araçların etkinleştirildiği tam geliştirme çalışması -- **Plan agent**: Değişiklik yapmadan analiz ve planlama -- **Review agent**: Salt okunur erişim ve belgeleme araçlarıyla kod incelemesi -- **Debug agent**: Bash ve okuma araçları etkinken araştırmaya odaklanmıştır -- **Docs agent**: Dosya işlemleriyle ancak sistem komutları olmadan belge yazma - ---- - -## Örnekler - -Yararlı bulabileceğiniz bazı örnek agent'ları burada bulabilirsiniz. - -:::tip -Paylaşmak istediğiniz bir agent'ınız var mı? [Submit a PR](https://github.com/anomalyco/opencode). -::: - ---- - -### Dokümantasyon agent'ı - -```markdown title="~/.config/opencode/agents/docs-writer.md" ---- -description: Writes and maintains project documentation -mode: subagent -tools: - bash: false ---- - -You are a technical writer. Create clear, comprehensive documentation. - -Focus on: - -- Clear explanations -- Proper structure -- Code examples -- User-friendly language -``` - ---- - -### Güvenlik denetçisi - -```markdown title="~/.config/opencode/agents/security-auditor.md" ---- -description: Performs security audits and identifies vulnerabilities -mode: subagent -tools: - write: false - edit: false ---- - -You are a security expert. Focus on identifying potential security issues. - -Look for: - -- Input validation vulnerabilities -- Authentication and authorization flaws -- Data exposure risks -- Dependency vulnerabilities -- Configuration security issues -``` diff --git a/packages/web/src/content/docs/tr/cli.mdx b/packages/web/src/content/docs/tr/cli.mdx index ae151bd5c9..5f3cd4bfcd 100644 --- a/packages/web/src/content/docs/tr/cli.mdx +++ b/packages/web/src/content/docs/tr/cli.mdx @@ -558,6 +558,7 @@ opencode ortam değişkenleri kullanılarak yapılandırılabilir. | `OPENCODE_AUTO_SHARE` | boolean | Oturumları otomatik olarak paylaş | | `OPENCODE_GIT_BASH_PATH` | string | Windows'ta yürütülebilir Git Bash'in Yolu | | `OPENCODE_CONFIG` | string | Yapılandırma dosyasının yolu | +| `OPENCODE_TUI_CONFIG` | string | TUI yapılandırma dosyasının yolu | | `OPENCODE_CONFIG_DIR` | string | Yapılandırma dizinine giden yol | | `OPENCODE_CONFIG_CONTENT` | string | Satır içi JSON config içeriği | | `OPENCODE_DISABLE_AUTOUPDATE` | boolean | Otomatik güncelleme kontrollerini devre dışı bırak | diff --git a/packages/web/src/content/docs/tr/config.mdx b/packages/web/src/content/docs/tr/config.mdx index fe60991c62..8a769ba690 100644 --- a/packages/web/src/content/docs/tr/config.mdx +++ b/packages/web/src/content/docs/tr/config.mdx @@ -491,13 +491,15 @@ Bağlam sıkıştırma davranışını `compaction` seçeneği aracılığıyla "$schema": "https://opencode.ai/config.json", "compaction": { "auto": true, - "prune": true + "prune": true, + "reserved": 10000 } } ``` - `auto` - Bağlam dolduğunda oturumu otomatik olarak sıkıştırır (varsayılan: `true`). - `prune` - Belirteçleri kaydetmek için eski araç çıktılarını kaldırın (varsayılan: `true`). +- `reserved` - Sıkıştırma için belirteç tamponu. Sıkıştırma sırasında taşmayı önlemek için yeterli pencere bırakır. --- diff --git a/packages/web/src/content/docs/tr/custom-tools.mdx b/packages/web/src/content/docs/tr/custom-tools.mdx index cb6a12debb..87ff66d1d6 100644 --- a/packages/web/src/content/docs/tr/custom-tools.mdx +++ b/packages/web/src/content/docs/tr/custom-tools.mdx @@ -79,6 +79,32 @@ Bu iki araç oluşturur: `math_add` ve `math_multiply`. --- +#### Yerleşik araçlarla ad çakışmaları + +Özel araçlar, araç adına göre anahtarlanır. Özel bir araç yerleşik bir araçla aynı adı kullanıyorsa, özel araç önceliklidir. + +Örneğin, bu dosya yerleşik `bash` aracının yerini alır: + +```ts title=".opencode/tools/bash.ts" +import { tool } from "@opencode-ai/plugin" + +export default tool({ + description: "Restricted bash wrapper", + args: { + command: tool.schema.string(), + }, + async execute(args) { + return `blocked: ${args.command}` + }, +}) +``` + +:::note +Kasıtlı olarak yerleşik bir aracı değiştirmek istemiyorsanız benzersiz adları tercih edin. Yerleşik bir aracı devre dışı bırakmak ancak geçersiz kılmak istemiyorsanız [izinleri](/docs/permissions) kullanın. +::: + +--- + ### Argümanlar Bağımsız değişken türlerini tanımlamak için yalnızca [Zod](https://zod.dev) olan `tool.schema` öğesini kullanabilirsiniz. diff --git a/packages/web/src/content/docs/tr/ecosystem.mdx b/packages/web/src/content/docs/tr/ecosystem.mdx index 835d9ba895..ba534c70b4 100644 --- a/packages/web/src/content/docs/tr/ecosystem.mdx +++ b/packages/web/src/content/docs/tr/ecosystem.mdx @@ -1,74 +1,76 @@ --- title: Ekosistem -description: opencode ile ilgili tasarımlar ve entegrasyonlar. +description: OpenCode ile geliştirilen projeler ve entegrasyonlar. --- -opencode üzerine inşa edilmiş bir topluluk projeleri koleksiyonu. +OpenCode üzerine inşa edilmiş topluluk projeleri koleksiyonu. :::note -opencode ile ilgili projenizi bu listeye eklemek ister misiniz? Bir PR gönderin. +OpenCode ile ilgili projenizi bu listeye eklemek ister misiniz? Bir PR gönderin. ::: -Ayrıca ekosistemi ve topluluğu bir araya getiren bir topluluk olan [awesome-opencode](https://github.com/awesome-opencode/awesome-opencode) ve [opencode.cafe](https://opencode.cafe)'e de göz atabilirsiniz. +Ayrıca ekosistemi ve topluluğu bir araya getiren [awesome-opencode](https://github.com/awesome-opencode/awesome-opencode) ve [opencode.cafe](https://opencode.cafe) adreslerine de göz atabilirsiniz. --- ## Eklentiler -| İsim | Açıklama | -| --------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | -| [opencode-daytona](https://github.com/jamesmurdza/daytona/blob/main/guides/typescript/opencode/README.md) | opencode oturumlarını git senkronizasyonu ve canlı önizlemelerle izole Daytona sanal alanlarında otomatik olarak çalıştırın | -| [opencode-helicone-session](https://github.com/H2Shami/opencode-helicone-session) | İstek gruplaması için Helicone oturum başlıklarını otomatik olarak ekleme | -| [opencode-type-inject](https://github.com/nick-vi/opencode-type-inject) | Arama araçlarıyla TypeScript/Svelte türlerini dosya okumalarına otomatik olarak enjekte edin | -| [opencode-openai-codex-auth](https://github.com/numman-ali/opencode-openai-codex-auth) | API kredisi yerine ChatGPT Plus/Pro aboneliğinizi kullanın | -| [opencode-gemini-auth](https://github.com/jenslys/opencode-gemini-auth) | API faturalandırma yerine mevcut Gemini planınızı kullanın | -| [opencode-antigravity-auth](https://github.com/NoeFabris/opencode-antigravity-auth) | API faturalandırma yerine Antigravity'nin ücretsiz modellerini kullanın | -| [opencode-devcontainers](https://github.com/athal7/opencode-devcontainers) | Sığ klonlar ve otomatik atanan bağlantı noktalarıyla çok dallı devcontainer izolasyonu | -| [opencode-google-antigravity-auth](https://github.com/shekohex/opencode-google-antigravity-auth) | Google Arama desteği ve daha sağlam API işleme özelliğiyle Google Antigravity OAuth Eklentisi | -| [opencode-dynamic-context-pruning](https://github.com/Tarquinen/opencode-dynamic-context-pruning) | Optimize token usage by pruning obsolete tool outputs | -| [opencode-websearch-cited](https://github.com/ghoulr/opencode-websearch-cited.git) | Desteklenen sağlayıcılar için Google tabanlı stil ile yerel web araması desteği ekleyin | -| [opencode-pty](https://github.com/shekohex/opencode-pty.git) | Yapay zeka aracılarının bir PTY'de arka plan işlemlerini çalıştırmasına ve onlara etkileşimli girdi göndermesine olanak tanır. | -| [opencode-shell-strategy](https://github.com/JRedeker/opencode-shell-strategy) | Etkileşimli olmayan kabuk komutlarına yönelik talimatlar - TTY bağımlı işlemlerden kaynaklanan askıda kalmaları önler | -| [opencode-wakatime](https://github.com/angristan/opencode-wakatime) | Wakatime ile opencode kullanımını izleyin | -| [opencode-md-table-formatter](https://github.com/franlol/opencode-md-table-formatter/tree/main) | Clean up markdown tables produced by LLMs | -| [opencode-morph-fast-apply](https://github.com/JRedeker/opencode-morph-fast-apply) | Morph Fast Apply API ve yavaş düzenleme işaretçileriyle 10 kat daha hızlı kod düzenleme | -| [oh-my-opencode](https://github.com/code-yeongyu/oh-my-opencode) | Background agents, pre-built LSP/AST/MCP tools, curated agents, Claude Code compatible | -| [opencode-notificator](https://github.com/panta82/opencode-notificator) | opencode oturumları için masaüstü bildirimleri ve sesli uyarılar | -| [opencode-notifier](https://github.com/mohak34/opencode-notifier) | İzin, tamamlama ve hata olayları için masaüstü bildirimleri ve sesli uyarılar | -| [opencode-zellij-namer](https://github.com/24601/opencode-zellij-namer) | opencode bağlamına dayalı yapay zeka destekli otomatik Zellij oturumu adlandırma | -| [opencode-skillful](https://github.com/zenobi-us/opencode-skillful) | opencode temsilcilerinin, beceri keşfi ve ekleme ile istek üzerine istemleri yavaş yüklemesine izin verin | -| [opencode-supermemory](https://github.com/supermemoryai/opencode-supermemory) | Supermemory kullanarak oturumlar arasında kalıcı hafıza | -| [@plannotator/opencode](https://github.com/backnotprop/plannotator/tree/main/apps/opencode-plugin) | Görsel açıklama ve private/offline paylaşımıyla etkileşimli plan incelemesi | -| [@openspoon/subtask2](https://github.com/spoons-and-mirrors/subtask2) | opencode'u/komutları ayrıntılı akış kontrolüyle güçlü bir orkestrasyon sistemine genişletin | -| [opencode-scheduler](https://github.com/different-ai/opencode-scheduler) | Cron sözdizimi ile launchd (Mac) veya systemd (Linux) kullanarak yinelenen işleri planlayın | -| [micode](https://github.com/vtemian/micode) | Yapılandırılmış Beyin Fırtınası → Planla → Oturum sürekliliği ile iş akışını uygulama | -| [octto](https://github.com/vtemian/octto) | Çoklu soru formlarıyla yapay zeka beyin fırtınası için etkileşimli tarayıcı arayüzü | -| [opencode-background-agents](https://github.com/kdcokenny/opencode-background-agents) | Eşzamansız delegasyon ve bağlam kalıcılığına sahip Claude Code tarzı arka plan aracıları | -| [opencode-notify](https://github.com/kdcokenny/opencode-notify) | opencode için yerel işletim sistemi bildirimleri – görevlerin ne zaman tamamlandığını bilin | -| [opencode-workspace](https://github.com/kdcokenny/opencode-workspace) | Birlikte verilen çok aracılı orkestrasyon donanımı – 16 bileşen, tek kurulum | -| [opencode-worktree](https://github.com/kdcokenny/opencode-worktree) | opencode için sıfır sürtünmeli git çalışma ağaçları | +| İsim | Açıklama | +| -------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | +| [opencode-daytona](https://github.com/daytonaio/daytona/tree/main/libs/opencode-plugin) | OpenCode oturumlarını, git senkronizasyonu ve canlı önizlemelerle izole Daytona sanal alanlarında otomatik olarak çalıştırın | +| [opencode-helicone-session](https://github.com/H2Shami/opencode-helicone-session) | İstek gruplaması için Helicone oturum başlıklarını otomatik olarak ekleyin | +| [opencode-type-inject](https://github.com/nick-vi/opencode-type-inject) | Arama araçlarıyla TypeScript/Svelte türlerini dosya okumalarına otomatik olarak enjekte edin | +| [opencode-openai-codex-auth](https://github.com/numman-ali/opencode-openai-codex-auth) | API kredisi yerine ChatGPT Plus/Pro aboneliğinizi kullanın | +| [opencode-gemini-auth](https://github.com/jenslys/opencode-gemini-auth) | API faturalandırması yerine mevcut Gemini planınızı kullanın | +| [opencode-antigravity-auth](https://github.com/NoeFabris/opencode-antigravity-auth) | API faturalandırması yerine Antigravity'nin ücretsiz modellerini kullanın | +| [opencode-devcontainers](https://github.com/athal7/opencode-devcontainers) | Sığ klonlar ve otomatik atanan portlarla çok dallı devcontainer izolasyonu | +| [opencode-google-antigravity-auth](https://github.com/shekohex/opencode-google-antigravity-auth) | Google Arama desteği ve daha sağlam API işleme özelliğiyle Google Antigravity OAuth Eklentisi | +| [opencode-dynamic-context-pruning](https://github.com/Tarquinen/opencode-dynamic-context-pruning) | Eski araç çıktılarını budayarak token kullanımını optimize edin | +| [opencode-vibeguard](https://github.com/inkdust2021/opencode-vibeguard) | LLM çağrılarından önce sırları/kişisel verileri VibeGuard tarzı yer tutucularla gizleyin; yerel olarak geri yükleyin | +| [opencode-websearch-cited](https://github.com/ghoulr/opencode-websearch-cited.git) | Desteklenen sağlayıcılar için Google kaynaklı stil ile yerel web araması desteği ekleyin | +| [opencode-pty](https://github.com/shekohex/opencode-pty.git) | Yapay zeka aracılarının bir PTY'de arka plan işlemlerini çalıştırmasına ve onlara etkileşimli girdi göndermesine olanak tanır | +| [opencode-shell-strategy](https://github.com/JRedeker/opencode-shell-strategy) | Etkileşimli olmayan kabuk komutları için talimatlar - TTY bağımlı işlemlerden kaynaklanan takılmaları önler | +| [opencode-wakatime](https://github.com/angristan/opencode-wakatime) | Wakatime ile OpenCode kullanımını takip edin | +| [opencode-md-table-formatter](https://github.com/franlol/opencode-md-table-formatter/tree/main) | LLM'ler tarafından üretilen markdown tablolarını temizleyin | +| [opencode-morph-fast-apply](https://github.com/JRedeker/opencode-morph-fast-apply) | Morph Fast Apply API ve tembel düzenleme işaretçileriyle 10 kat daha hızlı kod düzenleme | +| [oh-my-opencode](https://github.com/code-yeongyu/oh-my-opencode) | Arka plan aracıları, hazır LSP/AST/MCP araçları, seçilmiş aracılar, Claude Code uyumlu | +| [opencode-notificator](https://github.com/panta82/opencode-notificator) | OpenCode oturumları için masaüstü bildirimleri ve sesli uyarılar | +| [opencode-notifier](https://github.com/mohak34/opencode-notifier) | İzin, tamamlanma ve hata olayları için masaüstü bildirimleri ve sesli uyarılar | +| [opencode-zellij-namer](https://github.com/24601/opencode-zellij-namer) | OpenCode bağlamına dayalı yapay zeka destekli otomatik Zellij oturum isimlendirmesi | +| [opencode-skillful](https://github.com/zenobi-us/opencode-skillful) | OpenCode aracılarının, beceri keşfi ve enjeksiyonu ile istemleri talep üzerine tembel yüklemesine (lazy load) izin verin | +| [opencode-supermemory](https://github.com/supermemoryai/opencode-supermemory) | Supermemory kullanarak oturumlar arası kalıcı hafıza | +| [@plannotator/opencode](https://github.com/backnotprop/plannotator/tree/main/apps/opencode-plugin) | Görsel not alma ve özel/çevrimdışı paylaşım ile etkileşimli plan incelemesi | +| [@openspoon/subtask2](https://github.com/spoons-and-mirrors/subtask2) | opencode /commands komutlarını, ayrıntılı akış kontrolü ile güçlü bir orkestrasyon sistemine genişletin | +| [opencode-scheduler](https://github.com/different-ai/opencode-scheduler) | Launchd (Mac) veya systemd (Linux) kullanarak cron sözdizimi ile tekrarlayan işler planlayın | +| [micode](https://github.com/vtemian/micode) | Oturum sürekliliği ile Yapılandırılmış Beyin Fırtınası → Planlama → Uygulama iş akışı | +| [octto](https://github.com/vtemian/octto) | Çok sorulu formlarla yapay zeka beyin fırtınası için etkileşimli tarayıcı arayüzü | +| [opencode-background-agents](https://github.com/kdcokenny/opencode-background-agents) | Asenkron delegasyon ve bağlam kalıcılığına sahip Claude Code tarzı arka plan aracıları | +| [opencode-notify](https://github.com/kdcokenny/opencode-notify) | OpenCode için yerel işletim sistemi bildirimleri – görevlerin ne zaman tamamlandığını bilin | +| [opencode-workspace](https://github.com/kdcokenny/opencode-workspace) | Paketlenmiş çoklu aracı orkestrasyon donanımı – 16 bileşen, tek kurulum | +| [opencode-worktree](https://github.com/kdcokenny/opencode-worktree) | OpenCode için sıfır sürtünmeli git çalışma ağaçları (worktrees) | +| [opencode-sentry-monitor](https://github.com/stolinski/opencode-sentry-monitor) | Sentry AI Monitoring ile yapay zeka aracılarınızı izleyin ve hatalarını ayıklayın | --- ## Projeler -| İsim | Tanım | -| ------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------- | -| [kimaki](https://github.com/remorses/kimaki) | SDK üzerine kurulu opencode oturumlarını kontrol eden Discord botu | -| [opencode.nvim](https://github.com/NickvanDyke/opencode.nvim) | API temel alınarak oluşturulmuş, editöre duyarlı istemler için Neovim eklentisi | -| [portal](https://github.com/hosenur/portal) | Tailscale/VPN üzerinden opencode için mobil öncelikli web kullanıcı arayüzü | -| [opencode plugin template](https://github.com/zenobi-us/opencode-plugin-template/) | opencode eklentileri oluşturmak için şablon | -| [opencode.nvim](https://github.com/sudo-tee/opencode.nvim) | opencode için Neovim ön ucu - terminal tabanlı bir AI kodlama aracısı | -| [ai-sdk-provider-opencode-sdk](https://github.com/ben-vargas/ai-sdk-provider-opencode-sdk) | @opencode-ai/sdk aracılığıyla opencode'u kullanmak için Vercel AI SDK sağlayıcısı | -| [OpenChamber](https://github.com/btriapitsyn/openchamber) | opencode için Web / Masaüstü Uygulaması ve VS Code Uzantısı | -| [OpenCode-Obsidian](https://github.com/mtymek/opencode-obsidian) | opencode'u Obsidian'ın kullanıcı arayüzüne yerleştiren Obsidian eklentisi | -| [OpenWork](https://github.com/different-ai/openwork) | opencode tarafından desteklenen, Claude Cowork'e açık kaynaklı bir alternatif | -| [ocx](https://github.com/kdcokenny/ocx) | Taşınabilir, yalıtılmış profillere sahip opencode uzantı yöneticisi. | -| [CodeNomad](https://github.com/NeuralNomadsAI/CodeNomad) | opencode için Masaüstü, Web, Mobil ve Uzak İstemci Uygulaması | +| İsim | Açıklama | +| ------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------- | +| [kimaki](https://github.com/remorses/kimaki) | SDK üzerine inşa edilmiş, OpenCode oturumlarını kontrol eden Discord botu | +| [opencode.nvim](https://github.com/NickvanDyke/opencode.nvim) | API üzerine inşa edilmiş, editör farkındalıklı istemler için Neovim eklentisi | +| [portal](https://github.com/hosenur/portal) | Tailscale/VPN üzerinden OpenCode için mobil öncelikli web arayüzü | +| [opencode plugin template](https://github.com/zenobi-us/opencode-plugin-template/) | OpenCode eklentileri oluşturmak için şablon | +| [opencode.nvim](https://github.com/sudo-tee/opencode.nvim) | opencode için Neovim ön yüzü - terminal tabanlı bir yapay zeka kodlama aracısı | +| [ai-sdk-provider-opencode-sdk](https://github.com/ben-vargas/ai-sdk-provider-opencode-sdk) | @opencode-ai/sdk aracılığıyla OpenCode kullanmak için Vercel AI SDK sağlayıcısı | +| [OpenChamber](https://github.com/btriapitsyn/openchamber) | OpenCode için Web / Masaüstü Uygulaması ve VS Code Uzantısı | +| [OpenCode-Obsidian](https://github.com/mtymek/opencode-obsidian) | OpenCode'u Obsidian arayüzüne gömen Obsidian eklentisi | +| [OpenWork](https://github.com/different-ai/openwork) | OpenCode tarafından desteklenen, Claude Cowork'e açık kaynaklı bir alternatif | +| [ocx](https://github.com/kdcokenny/ocx) | Taşınabilir, izole profillere sahip OpenCode eklenti yöneticisi | +| [CodeNomad](https://github.com/NeuralNomadsAI/CodeNomad) | OpenCode için Masaüstü, Web, Mobil ve Uzak İstemci Uygulaması | --- -## Agent'lar +## Aracılar | İsim | Açıklama | | ----------------------------------------------------------------- | --------------------------------------------------------------------------- | diff --git a/packages/web/src/content/docs/tr/go.mdx b/packages/web/src/content/docs/tr/go.mdx new file mode 100644 index 0000000000..794e7f269e --- /dev/null +++ b/packages/web/src/content/docs/tr/go.mdx @@ -0,0 +1,145 @@ +--- +title: Go +description: Açık kodlama modelleri için düşük maliyetli abonelik. +--- + +import config from "../../../../config.mjs" +export const console = config.console +export const email = `mailto:${config.email}` + +OpenCode Go, popüler açık kodlama modellerine güvenilir erişim sağlayan **aylık 10$** tutarında düşük maliyetli bir aboneliktir. + +:::note +OpenCode Go şu anda beta aşamasındadır. +::: + +Go, OpenCode içindeki diğer sağlayıcılar gibi çalışır. OpenCode Go'ya abone olur ve API anahtarınızı alırsınız. Bu **tamamen isteğe bağlıdır** ve OpenCode'u kullanmak için buna ihtiyacınız yoktur. + +Kararlı küresel erişim için ABD, AB ve Singapur'da barındırılan modellerle, öncelikli olarak uluslararası kullanıcılar için tasarlanmıştır. + +--- + +## Arka Plan + +Açık modeller gerçekten iyi hale geldi. Artık kodlama görevleri için tescilli modellere yakın performans sunuyorlar. Ve birçok sağlayıcı bunları rekabetçi bir şekilde sunabildiği için genellikle çok daha ucuzlar. + +Ancak, bunlara güvenilir ve düşük gecikmeli erişim sağlamak zor olabilir. Sağlayıcılar kalite ve kullanılabilirlik açısından farklılık gösterir. + +:::tip +OpenCode ile iyi çalışan seçkin bir model ve sağlayıcı grubunu test ettik. +::: + +Bunu düzeltmek için birkaç şey yaptık: + +1. Seçkin bir açık model grubunu test ettik ve bunları en iyi nasıl çalıştıracakları konusunda ekipleriyle görüştük. +2. Daha sonra bunların doğru şekilde sunulduğundan emin olmak için birkaç sağlayıcıyla çalıştık. +3. Son olarak, model/sağlayıcı kombinasyonunu kıyasladık ve önermekten memnuniyet duyduğumuz bir liste oluşturduk. + +OpenCode Go, bu modellere **aylık 10$** karşılığında erişmenizi sağlar. + +--- + +## Nasıl çalışır + +OpenCode Go, OpenCode'daki diğer herhangi bir sağlayıcı gibi çalışır. + +1. **<a href={console}>OpenCode Zen</a>**'de oturum açın, Go'ya abone olun ve API anahtarınızı kopyalayın. +2. TUI'de `/connect` komutunu çalıştırın, `OpenCode Go`yu seçin ve API anahtarınızı yapıştırın. +3. Go üzerinden kullanılabilen modellerin listesini görmek için TUI'de `/models` komutunu çalıştırın. + +:::note +Çalışma alanı başına yalnızca bir üye OpenCode Go'ya abone olabilir. +::: + +Mevcut model listesi şunları içerir: + +- **GLM-5** +- **Kimi K2.5** +- **MiniMax M2.5** + +Test ettikçe ve yenilerini ekledikçe model listesi değişebilir. + +--- + +## Kullanım sınırları + +OpenCode Go aşağıdaki sınırları içerir: + +- **5 saatlik sınır** — 12$ kullanım +- **Haftalık sınır** — 30$ kullanım +- **Aylık sınır** — 60$ kullanım + +Sınırlar dolar değeri üzerinden tanımlanmıştır. Bu, gerçek istek sayınızın kullandığınız modele bağlı olduğu anlamına gelir. MiniMax M2.5 gibi daha ucuz modeller daha fazla isteğe izin verirken, GLM-5 gibi daha yüksek maliyetli modeller daha azına izin verir. + +Aşağıdaki tablo, tipik Go kullanım modellerine dayalı tahmini bir istek sayısı sunmaktadır: + +| | GLM-5 | Kimi K2.5 | MiniMax M2.5 | +| ------------------- | ----- | --------- | ------------ | +| 5 saat başına istek | 1.150 | 1.850 | 30.000 | +| haftalık istek | 2.880 | 4.630 | 75.000 | +| aylık istek | 5.750 | 9.250 | 150.000 | + +Tahminler gözlemlenen ortalama istek modellerine dayanmaktadır: + +- GLM-5 — İstek başına 700 girdi, 52.000 önbelleğe alınmış, 150 çıktı token'ı +- Kimi K2.5 — İstek başına 870 girdi, 55.000 önbelleğe alınmış, 200 çıktı token'ı +- MiniMax M2.5 — İstek başına 300 girdi, 55.000 önbelleğe alınmış, 125 çıktı token'ı + +Mevcut kullanımınızı **<a href={console}>konsoldan</a>** takip edebilirsiniz. + +:::tip +Kullanım sınırına ulaşırsanız, ücretsiz modelleri kullanmaya devam edebilirsiniz. +::: + +Erken kullanım ve geri bildirimlerden öğrendiklerimize göre kullanım sınırları değişebilir. + +--- + +### Fiyatlandırma + +OpenCode Go, **aylık 10$** tutarında bir abonelik planıdır. Aşağıda **1M token başına** fiyatlar yer almaktadır. + +| Model | Girdi | Çıktı | Önbelleğe Alınmış Okuma | +| ------------ | ----- | ----- | ----------------------- | +| GLM-5 | $1.00 | $3.20 | $0.20 | +| Kimi K2.5 | $0.60 | $3.00 | $0.10 | +| MiniMax M2.5 | $0.30 | $1.20 | $0.03 | + +--- + +### Sınırların ötesinde kullanım + +Zen bakiyenizde krediniz de varsa, konsoldaki **Bakiyeyi kullan** (Use balance) seçeneğini etkinleştirebilirsiniz. Etkinleştirildiğinde, kullanım sınırlarınıza ulaştıktan sonra Go, istekleri engellemek yerine Zen bakiyenize geri dönecektir. + +--- + +## Uç Noktalar + +Go modellerine aşağıdaki API uç noktaları üzerinden de erişebilirsiniz. + +| Model | Model ID | Endpoint | AI SDK Paketi | +| ------------ | ------------ | ------------------------------------------------ | --------------------------- | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | + +OpenCode yapılandırmanızdaki [model kimliği](/docs/config/#models), `opencode-go/<model-id>` biçimini kullanır. Örneğin, Kimi K2.5 için yapılandırmanızda `opencode-go/kimi-k2.5` kullanırsınız. + +--- + +## Gizlilik + +Plan öncelikli olarak uluslararası kullanıcılar için tasarlanmıştır; modeller kararlı küresel erişim için ABD, AB ve Singapur'da barındırılmaktadır. + +Herhangi bir sorunuz varsa <a href={email}>bizimle iletişime geçin</a>. + +--- + +## Hedefler + +OpenCode Go'yu şu amaçlarla oluşturduk: + +1. Düşük maliyetli bir abonelikle yapay zeka kodlamasını daha fazla insan için **erişilebilir** kılmak. +2. En iyi açık kodlama modellerine **güvenilir** erişim sağlamak. +3. Kodlama ajanı kullanımı için **test edilmiş ve kıyaslanmış** modelleri seçmek. +4. OpenCode ile başka herhangi bir sağlayıcıyı kullanmanıza da izin vererek **kilitlenmeyi önlemek**. diff --git a/packages/web/src/content/docs/tr/index.mdx b/packages/web/src/content/docs/tr/index.mdx index 291d3d490c..696eddc3a1 100644 --- a/packages/web/src/content/docs/tr/index.mdx +++ b/packages/web/src/content/docs/tr/index.mdx @@ -1,13 +1,13 @@ --- title: Giriş -description: opencode kullanmaya başlayın. +description: OpenCode kullanmaya başlayın. --- import { Tabs, TabItem } from "@astrojs/starlight/components" import config from "../../../../config.mjs" export const console = config.console -[**opencode**](/) açık kaynaklı bir AI kodlama ajanıdır. Terminal tabanlı bir arayüz, masaüstü uygulaması veya IDE uzantısı olarak mevcuttur. +[**OpenCode**](/) açık kaynaklı bir AI kodlama ajanıdır. Terminal tabanlı bir arayüz, masaüstü uygulaması veya IDE uzantısı olarak mevcuttur. ![opencode TUI with the opencode theme](../../../assets/lander/screenshot.png) @@ -17,11 +17,11 @@ Başlayalım. #### Ön koşullar -opencode'u terminalinizde kullanmak için ihtiyacınız olacak: +OpenCode'u terminalinizde kullanmak için ihtiyacınız olacak: 1. Şu gibi modern bir terminal emülatörü: - - [WezTerm](https://wezterm.org), cross-platform - - [Alacritty](https://alacritty.org), cross-platform + - [WezTerm](https://wezterm.org), cross-platform (tüm platformlarda) + - [Alacritty](https://alacritty.org), cross-platform (tüm platformlarda) - [Ghostty](https://ghostty.org), Linux ve macOS - [Kitty](https://sw.kovidgoyal.net/kitty/), Linux ve macOS @@ -31,7 +31,7 @@ opencode'u terminalinizde kullanmak için ihtiyacınız olacak: ## Kurulum -opencode'u kurmanın en kolay yolu kurulum betiğidir. +OpenCode'u kurmanın en kolay yolu kurulum betiğidir. ```bash curl -fsSL https://opencode.ai/install | bash @@ -79,7 +79,7 @@ Ayrıca aşağıdaki komutlarla da yükleyebilirsiniz: brew install anomalyco/tap/opencode ``` - > En güncel sürümler için opencode tap'ini kullanmanızı öneririz. Resmi `brew install opencode` formülü Homebrew ekibi tarafından korunur ve daha sık güncellenir. + > En güncel sürümler için OpenCode tap'ini kullanmanızı öneririz. Resmi `brew install opencode` formülü Homebrew ekibi tarafından korunur ve daha sık güncellenir. - **Paru'yu Arch Linux'ta kullanma** @@ -91,7 +91,7 @@ Ayrıca aşağıdaki komutlarla da yükleyebilirsiniz: #### Windows :::tip[Önerilen: WSL kullanın] -Windows'ta en iyi deneyim için [Windows Subsystem for Linux (WSL)](/docs/windows-wsl) kullanılmasını öneririz. Daha iyi performans ve opencode'un özellikleriyle tam uyumluluğu sağlar. +Windows'ta en iyi deneyim için [Windows Subsystem for Linux (WSL)](/docs/windows-wsl) kullanılmasını öneririz. Daha iyi performans ve OpenCode'un özellikleriyle tam uyumluluğu sağlar. ::: - **Chocolatey Kullanımı** @@ -124,7 +124,7 @@ Windows'ta en iyi deneyim için [Windows Subsystem for Linux (WSL)](/docs/window docker run -it --rm ghcr.io/anomalyco/opencode ``` -opencode'un Bun kullanılarak Windows'a yüklenmesine yönelik destek şu anda devam etmektedir. +OpenCode'un Bun kullanılarak Windows'a yüklenmesine yönelik destek şu anda devam etmektedir. İkili dosyayı [Releases](https://github.com/anomalyco/opencode/releases)'dan da alabilirsiniz. @@ -132,12 +132,12 @@ opencode'un Bun kullanılarak Windows'a yüklenmesine yönelik destek şu anda d ## Yapılandırma -opencode ile herhangi bir LLM sağlayıcısının API anahtarlarını yapılandırarak kullanabilirsiniz. +OpenCode ile herhangi bir LLM sağlayıcısının API anahtarlarını yapılandırarak kullanabilirsiniz. LLM sağlayıcılarını kullanmaya yeni başlıyorsanız, [OpenCode Zen](/docs/zen) kullanmanızı öneririz. -opencode ekibi tarafından test edilmiş ve doğrulanmış modellerin seçilmiş bir listesidir. +OpenCode ekibi tarafından test edilmiş ve doğrulanmış modellerin seçilmiş bir listesidir. -1. TUI'de `/connect` komutunu çalıştırın, opencode'u seçin ve [opencode.ai/auth](https://opencode.ai/auth)'ye gidin. +1. TUI'de `/connect` komutunu çalıştırın, OpenCode'u seçin ve [opencode.ai/auth](https://opencode.ai/auth)'ye gidin. ```txt /connect @@ -160,39 +160,37 @@ Alternatif olarak diğer sağlayıcılardan birini seçebilirsiniz. [Daha fazla ## Başlatma -Artık bir sağlayıcı yapılandırdığınıza göre, bir projeye gidebilirsiniz. -üzerinde çalışmak istiyorsun. +Artık bir sağlayıcı yapılandırdığınıza göre, üzerinde çalışmak istediğiniz bir projeye gidebilirsiniz. ```bash cd /path/to/project ``` -Ve opencode'u çalıştırın. +Ve OpenCode'u çalıştırın. ```bash opencode ``` -Daha sonra aşağıdaki komutu çalıştırarak proje için opencode'u başlatın. +Daha sonra aşağıdaki komutu çalıştırarak proje için OpenCode'u başlatın. ```bash frame="none" /init ``` -Bu, opencode'un projenizi analiz etmesini ve bir `AGENTS.md` dosyası oluşturmasını sağlayacaktır. -proje kökü. +Bu, OpenCode'un projenizi analiz etmesini ve bir `AGENTS.md` proje kökünde dosyası oluşturmasını sağlayacaktır. :::tip Projenizin `AGENTS.md` dosyasını Git'e göndermelisiniz. ::: -Bu, opencode'un proje yapısını ve kullanılan kodlama kalıplarını anlamasına yardımcı olur. +Bu, OpenCode'un proje yapısını ve kullanılan kodlama kalıplarını anlamasına yardımcı olur. --- ## Kullanım -Artık projeniz üzerinde çalışmak için opencode'u kullanmaya hazırsınız. Dilediğiniz soruyu sorabilirsiniz. +Artık projeniz üzerinde çalışmak için OpenCode'u kullanmaya hazırsınız. Dilediğiniz soruyu sorabilirsiniz. AI kodlama ajanını kullanmaya yeniyseniz aşağıdaki örnekler yardımcı olabilir. @@ -200,7 +198,7 @@ AI kodlama ajanını kullanmaya yeniyseniz aşağıdaki örnekler yardımcı ola ### Soru Sorma -opencode'dan kod tabanını size açıklamasını isteyebilirsiniz. +OpenCode'dan kod tabanını size açıklamasını isteyebilirsiniz. :::tip Projedeki dosyaları bulanık aramak için `@` tuşunu kullanın. @@ -216,14 +214,14 @@ Kod tabanının üzerinde çalışmadığınız bir kısmı varsa bu yararlı ol ### Özellik Ekleme -opencode'dan projenize yeni özellikler eklemesini isteyebilirsiniz. Yine de öncelikle ondan bir plan oluşturmasını istemenizi öneririz. +OpenCode'dan projenize yeni özellikler eklemesini isteyebilirsiniz. Yine de öncelikle ondan bir plan oluşturmasını istemenizi öneririz. 1. **Bir plan oluşturun** - opencode, değişiklik yapma özelliğini kapatan bir \_Plan modu_na sahiptir. + OpenCode, değişiklik yapma özelliğini kapatan bir \_Plan modu\_\na sahiptir. Bu modda, özelliğin nasıl uygulanacağını önerir. - **Sekme** tuşunu kullanarak buna geçin. Bunun için sağ alt köşede bir gösterge göreceksiniz. + **Tab** tuşunu kullanarak buna geçin. Bunun için sağ alt köşede bir gösterge göreceksiniz. ```bash frame="none" title="Plan moduna geç" <TAB> @@ -237,16 +235,13 @@ opencode'dan projenize yeni özellikler eklemesini isteyebilirsiniz. Yine de ön From this screen, the user can undelete a note or permanently delete it. ``` - opencode'un isteğinizi anlaması için yeterli ayrıntı verin. + OpenCode'un isteğinizi anlaması için yeterli ayrıntı verin. Ekibinizdeki junior bir geliştiriciyle konuşur gibi yazmak genelde iyi sonuç verir. :::tip - opencode'a bol bağlam ve örnek verin. + OpenCode'a ne istediğinizi anlamasına yardımcı olacak bol miktarda bağlam ve örnek verin. ::: - opencode verdiğiniz görselleri tarayıp prompt'a ekleyebilir. - Bunu bir görseli terminale sürükleyip bırakarak yapabilirsiniz. - 2. **Planı yineleyin** Size bir plan sunduğunda ona geri bildirimde bulunabilir veya daha fazla ayrıntı ekleyebilirsiniz. @@ -260,12 +255,12 @@ opencode'dan projenize yeni özellikler eklemesini isteyebilirsiniz. Yine de ön İsteme eklemek için görüntüleri terminale sürükleyip bırakın. ::: - opencode verdiğiniz görselleri tarayıp prompt'a ekleyebilir. + OpenCode verdiğiniz görselleri tarayıp prompt'a ekleyebilir. Bunu bir görseli terminale sürükleyip bırakarak yapabilirsiniz. 3. **Özelliği oluşturun** - Planı yeterli bulduğunuzda **Sekme** tuşuna tekrar basarak \_Build modu_na dönün. + Planı yeterli bulduğunuzda **Tab** tuşuna tekrar basarak \_Build modu\_\na dönün. ```bash frame="none" <TAB> @@ -281,7 +276,7 @@ opencode'dan projenize yeni özellikler eklemesini isteyebilirsiniz. Yine de ön ### Değişiklik Yapma -Daha basit değişikliklerde, önce planı incelemeden opencode'dan doğrudan değişiklik yapmasını isteyebilirsiniz. +Daha basit değişikliklerde, önce planı incelemeden OpenCode'dan doğrudan değişiklik yapmasını isteyebilirsiniz. ```txt frame="none" "@packages/functions/src/settings.ts" "@packages/functions/src/notes.ts" We need to add authentication to the /settings route. Take a look at how this is @@ -289,32 +284,31 @@ handled in the /notes route in @packages/functions/src/notes.ts and implement the same logic in @packages/functions/src/settings.ts ``` -opencode'un doğru değişiklikleri yapması için yeterli ayrıntı verdiğinizden emin olun. +OpenCode'un doğru değişiklikleri yapması için yeterli ayrıntı verdiğinizden emin olun. --- ### Değişiklikleri Geri Alma -Diyelim ki opencode'dan bazı değişiklikler yapmasını istediniz. +Diyelim ki OpenCode'dan bazı değişiklikler yapmasını istediniz. ```txt frame="none" "@packages/functions/src/api/index.ts" Can you refactor the function in @packages/functions/src/api/index.ts? ``` -Ama istediğinin bu olmadığını anlıyorsun. Değişiklikleri **geri alabilirsiniz** -`/undo` komutunu kullanarak. +Ama istediğinin bu olmadığını anlıyorsun. `/undo` komutunu kullanarak değişiklikleri **geri alabilirsiniz**. ```bash frame="none" /undo ``` -opencode değişiklikleri geri alır ve orijinal mesajınızı tekrar gösterir. +OpenCode değişiklikleri geri alır ve orijinal mesajınızı tekrar gösterir. ```txt frame="none" "@packages/functions/src/api/index.ts" Can you refactor the function in @packages/functions/src/api/index.ts? ``` -Buradan komut isteminde ince ayar yapabilir ve opencode'dan tekrar denemesini isteyebilirsiniz. +Buradan komut isteminde ince ayar yapabilir ve OpenCode'dan tekrar denemesini isteyebilirsiniz. :::tip Birden çok değişikliği geri almak için `/undo` komutunu birden çok kez çalıştırabilirsiniz. @@ -330,7 +324,7 @@ Veya `/redo` komutunu kullanarak değişiklikleri **yeniden yapabilirsiniz**. ## Paylaşma -opencode ile yaptığınız görüşmeleri [ekibinizle paylaşabilirsiniz](/docs/share). +OpenCode ile yaptığınız görüşmeleri [ekibinizle paylaşabilirsiniz](/docs/share). ```bash frame="none" /share @@ -342,12 +336,12 @@ Bu, mevcut konuşmaya bir bağlantı oluşturacak ve bunu panonuza kopyalayacakt Konuşmalar varsayılan olarak paylaşılmaz. ::: -İşte opencode'lu bir [örnek konuşma](https://opencode.ai/s/4XP1fce5). +İşte OpenCode ile bir [örnek konuşma](https://opencode.ai/s/4XP1fce5). --- ## Özelleştirme -İşte bu kadar! Artık opencode'u kullanma konusunda profesyonelsiniz. +İşte bu kadar! Artık OpenCode'u kullanma konusunda profesyonelsiniz. -Kendinize göre uyarlamak için [tema seçebilir](/docs/themes), [tuş atamalarını özelleştirebilir](/docs/keybinds), [kod biçimlendirici ayarlayabilir](/docs/formatters), [özel komutlar oluşturabilir](/docs/commands) veya [opencode config](/docs/config) ile oynayabilirsiniz. +Kendinize göre uyarlamak için [tema seçebilir](/docs/themes), [tuş atamalarını özelleştirebilir](/docs/keybinds), [kod biçimlendirici ayarlayabilir](/docs/formatters), [özel komutlar oluşturabilir](/docs/commands) veya [OpenCode config](/docs/config) ile oynayabilirsiniz. diff --git a/packages/web/src/content/docs/tr/keybinds.mdx b/packages/web/src/content/docs/tr/keybinds.mdx index 9a22c329cc..7d3142bf38 100644 --- a/packages/web/src/content/docs/tr/keybinds.mdx +++ b/packages/web/src/content/docs/tr/keybinds.mdx @@ -3,11 +3,11 @@ title: Tuş atamaları description: Tuş bağlantılarınızı özelleştirin. --- -opencode, opencode yapılandırması aracılığıyla özelleştirebileceğiniz bir tuş bağlantıları listesine sahiptir. +opencode, `tui.json` aracılığıyla özelleştirebileceğiniz bir tuş bağlantıları listesine sahiptir. -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "keybinds": { "leader": "ctrl+x", "app_exit": "ctrl+c,ctrl+d,<leader>q", @@ -28,6 +28,7 @@ opencode, opencode yapılandırması aracılığıyla özelleştirebileceğiniz "session_unshare": "none", "session_interrupt": "escape", "session_compact": "<leader>c", + "session_child_first": "<leader>down", "session_child_cycle": "<leader>right", "session_child_cycle_reverse": "<leader>left", "session_parent": "<leader>up", @@ -119,9 +120,9 @@ Tuş atamalarınız için lider anahtar kullanmanıza gerek yoktur ancak bunu ya Anahtarı yapılandırmanıza "none" değeriyle ekleyerek bir tuş atamasını devre dışı bırakabilirsiniz. -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "keybinds": { "session_compact": "none" } @@ -134,21 +135,21 @@ Anahtarı yapılandırmanıza "none" değeriyle ekleyerek bir tuş atamasını d opencode masaüstü uygulaması bilgi istemi girişi, metni düzenlemek için yaygın Readline/Emacs tarzı kısayolları destekler. Bunlar yerleşiktir ve şu anda `opencode.json` aracılığıyla yapılandırılamaz. -| Shortcut | Action | -| -------- | ---------------------------------------- | -| `ctrl+a` | Geçerli satırın başına git | -| `ctrl+e` | Move to end of current line | -| `ctrl+b` | Move cursor back one character | -| `ctrl+f` | Move cursor forward one character | -| `alt+b` | Move cursor back one word | -| `alt+f` | Move cursor forward one word | -| `ctrl+d` | Delete character under cursor | -| `ctrl+k` | Kill to end of line | -| `ctrl+u` | Satırın başına kadar öldür | -| `ctrl+w` | Kill previous word | -| `alt+d` | Kill next word | -| `ctrl+t` | Transpose characters | -| `ctrl+g` | Cancel popovers / abort running response | +| Shortcut | Action | +| -------- | --------------------------------------------------- | +| `ctrl+a` | Geçerli satırın başına git | +| `ctrl+e` | Geçerli satırın sonuna git | +| `ctrl+b` | İmleci bir karakter geri taşı | +| `ctrl+f` | İmleci bir karakter ileri taşı | +| `alt+b` | İmleci bir kelime geri taşı | +| `alt+f` | İmleci bir kelime ileri taşı | +| `ctrl+d` | İmleç altındaki karakteri sil | +| `ctrl+k` | Satırın sonuna kadar sil | +| `ctrl+u` | Satırın başına kadar sil | +| `ctrl+w` | Önceki kelimeyi sil | +| `alt+d` | Sonraki kelimeyi sil | +| `ctrl+t` | Karakterlerin yerini değiştir | +| `ctrl+g` | Açılır pencereleri iptal et / çalışan yanıtı durdur | --- @@ -158,7 +159,7 @@ Bazı terminaller varsayılan olarak Enter ile değiştirici tuşlar göndermez. ### Windows Terminali -`settings.json` cihazınızı şu adreste açın: +`settings.json` dosyasını şurada açın: ``` %LOCALAPPDATA%\Packages\Microsoft.WindowsTerminal_8wekyb3d8bbwe\LocalState\settings.json diff --git a/packages/web/src/content/docs/tr/lsp.mdx b/packages/web/src/content/docs/tr/lsp.mdx index db74211385..52a95d1c3c 100644 --- a/packages/web/src/content/docs/tr/lsp.mdx +++ b/packages/web/src/content/docs/tr/lsp.mdx @@ -1,15 +1,15 @@ --- title: LSP Sunucuları -description: opencode, LSP sunucularınızla bütünleşir. +description: OpenCode, LSP sunucularınızla bütünleşir. --- -opencode, LLM'in kod tabanınızla etkileşime girmesine yardımcı olmak için Dil Sunucusu Protokolünüzle (LSP) bütünleşir. LLM'ye geri bildirim sağlamak için tanılamayı kullanır. +OpenCode, LLM'in kod tabanınızla etkileşime girmesine yardımcı olmak için Dil Sunucusu Protokolünüzle (LSP) bütünleşir. LLM'ye geri bildirim sağlamak için tanılamayı kullanır. --- ## Yerleşik -opencode, popüler diller için çeşitli yerleşik LSP sunucularıyla birlikte gelir: +OpenCode, popüler diller için çeşitli yerleşik LSP sunucularıyla birlikte gelir: | LSP Sunucu | Uzantılar | Gereksinimler | | ------------------ | ------------------------------------------------------------------- | --------------------------------------------------------------------- | @@ -27,6 +27,7 @@ opencode, popüler diller için çeşitli yerleşik LSP sunucularıyla birlikte | gopls | .go | `go` komutu mevcut | | hls | .hs, .lhs | `haskell-language-server-wrapper` komutu mevcut | | jdtls | .java | `Java SDK (version 21+)` kurulu | +| julials | .jl | `julia` ve `LanguageServer.jl` kurulu | | kotlin-ls | .kt, .kts | Kotlin projeleri için otomatik kurulumlar | | lua-ls | .lua | Lua projeleri için otomatik kurulumlar | | nixd | .nix | `nixd` komutu mevcut | @@ -56,7 +57,7 @@ Yukarıdaki dosya uzantılarından biri tespit edildiğinde ve gereksinimler kar ## Nasıl Çalışır? -Opencode bir dosyayı açtığında: +opencode bir dosyayı açtığında: 1. Dosya uzantısını tüm etkin LSP sunucularına göre kontrol eder. 2. Henüz çalışmıyorsa uygun LSP sunucusunu başlatır. @@ -182,7 +183,7 @@ Komutu ve dosya uzantılarını belirterek özel LSP sunucuları ekleyebilirsini PHP Intelephense, bir lisans anahtarı aracılığıyla premium özellikler sunar. Anahtarı (yalnızca) şu adresteki bir metin dosyasına yerleştirerek bir lisans anahtarı sağlayabilirsiniz: -- MacOS/Linux'ta: `$HOME/intelephense/license.txt` +- macOS/Linux'ta: `$HOME/intelephense/license.txt` - Windows'ta: `%USERPROFILE%/intelephense/license.txt` Dosya, ek içerik olmadan yalnızca lisans anahtarını içermelidir. diff --git a/packages/web/src/content/docs/tr/plugins.mdx b/packages/web/src/content/docs/tr/plugins.mdx index 0b24e48c35..4926f5f70e 100644 --- a/packages/web/src/content/docs/tr/plugins.mdx +++ b/packages/web/src/content/docs/tr/plugins.mdx @@ -1,9 +1,9 @@ --- title: Eklentiler -description: opencode'u genişletmek için kendi eklentilerinizi yazın. +description: OpenCode'u genişletmek için kendi eklentilerinizi yazın. --- -Eklentiler, çeşitli olaylara bağlanarak ve davranışı özelleştirerek opencode'u genişletmenize olanak tanır. Yeni özellikler eklemek, harici hizmetlerle entegrasyon sağlamak veya opencode'un varsayılan davranışını değiştirmek için eklentiler oluşturabilirsiniz. +Eklentiler, çeşitli olaylara bağlanarak ve davranışı özelleştirerek OpenCode'u genişletmenize olanak tanır. Yeni özellikler eklemek, harici hizmetlerle entegrasyon sağlamak veya OpenCode'un varsayılan davranışını değiştirmek için eklentiler oluşturabilirsiniz. Örnekler için topluluk tarafından oluşturulan [eklentilere](/docs/ecosystem#plugins) göz atın. @@ -47,7 +47,7 @@ Hem normal hem de kapsamlı npm paketleri desteklenir. **npm eklentileri** başlangıçta Bun kullanılarak otomatik olarak yüklenir. Paketler ve bağımlılıkları `~/.cache/opencode/node_modules/`'da önbelleğe alınır. -**Yerel eklentiler** doğrudan eklenti dizininden yüklenir. Harici paketleri kullanmak için, sisteminizin dizininde bir `package.json` oluşturmanız (bkz. [Bağımlılıklar](#dependencies)) veya eklentiyi npm ve [add it to your config](/docs/config#plugins)'de yayınlamanız gerekir. +**Yerel eklentiler** doğrudan eklenti dizininden yüklenir. Harici paketleri kullanmak için, sisteminizin dizininde bir `package.json` oluşturmanız (bkz. [Bağımlılıklar](#dependencies)) veya eklentiyi npm ve [yapılandırmanıza eklemeniz](/docs/config#plugins) gerekir. --- @@ -66,8 +66,7 @@ Aynı ad ve sürüme sahip yinelenen npm paketleri bir kez yüklenir. Ancak benz ## Eklenti oluşturma -Eklenti, bir veya daha fazla eklentiyi dışa aktaran bir **JavaScript/TypeScript modülüdür** -işlevler. Her işlev bir bağlam nesnesi alır ve bir kanca nesnesi döndürür. +Eklenti, bir veya daha fazla eklenti işlevini dışa aktaran bir **JavaScript/TypeScript modülüdür**. Her işlev bir bağlam nesnesi alır ve bir kanca nesnesi döndürür. --- @@ -83,7 +82,7 @@ Yerel eklentiler ve özel araçlar harici npm paketlerini kullanabilir. İhtiyac } ``` -opencode bunları yüklemek için başlangıçta `bun install` komutunu çalıştırır. Eklentileriniz ve araçlarınız daha sonra bunları içe aktarabilir. +OpenCode bunları yüklemek için başlangıçta `bun install` komutunu çalıştırır. Eklentileriniz ve araçlarınız daha sonra bunları içe aktarabilir. ```ts title=".opencode/plugins/my-plugin.ts" import { escape } from "shescape" @@ -116,9 +115,9 @@ export const MyPlugin = async ({ project, client, $, directory, worktree }) => { Eklenti işlevi şunları alır: - `project`: Mevcut proje bilgisi. -- `directory`: güncel çalışma dizini. +- `directory`: Güncel çalışma dizini. - `worktree`: Git çalışma ağacı yolu. -- `client`: Yapay zeka ile etkileşime geçmek için opencode'lu bir SDK istemcisi. +- `client`: Yapay zeka ile etkileşim kurmak için bir OpenCode SDK istemcisi. - `$`: Bun'un komutları yürütmek için kullandığı [shell API](https://bun.com/docs/runtime/shell). --- @@ -211,7 +210,7 @@ Eklentiler aşağıdaki Örnekler bölümünde görüldüğü gibi etkinliklere ## Örnekler -opencode'u genişletmek için kullanabileceğiniz bazı eklenti örneklerini burada bulabilirsiniz. +OpenCode'u genişletmek için kullanabileceğiniz bazı eklenti örneklerini burada bulabilirsiniz. --- @@ -232,17 +231,17 @@ export const NotificationPlugin = async ({ project, client, $, directory, worktr } ``` -MacOS'ta AppleScript'i çalıştırmak için `osascript` kullanıyoruz. Burada bildirim göndermek için kullanıyoruz. +macOS'ta AppleScript'i çalıştırmak için `osascript` kullanıyoruz. Burada bildirim göndermek için kullanıyoruz. :::note -opencode masaüstü uygulamasını kullanıyorsanız yanıt hazır olduğunda veya oturum hataları oluştuğunda otomatik olarak sistem bildirimleri gönderebilir. +OpenCode masaüstü uygulamasını kullanıyorsanız yanıt hazır olduğunda veya oturum hataları oluştuğunda otomatik olarak sistem bildirimleri gönderebilir. ::: --- ### .env Koruması -opencode'un `.env` dosyalarını okumasını önleyin: +OpenCode'un `.env` dosyalarını okumasını önleyin: ```javascript title=".opencode/plugins/env-protection.js" export const EnvProtection = async ({ project, client, $, directory, worktree }) => { @@ -277,7 +276,7 @@ export const InjectEnvPlugin = async () => { ### Özel araçlar -Eklentiler ayrıca opencode'a özel araçlar da ekleyebilir: +Eklentiler ayrıca OpenCode'a özel araçlar da ekleyebilir: ```ts title=".opencode/plugins/custom-tools.ts" import { type Plugin, tool } from "@opencode-ai/plugin" @@ -300,19 +299,23 @@ export const CustomToolsPlugin: Plugin = async (ctx) => { } ``` -`tool` yardımcısı, opencode'un çağırabileceği özel bir araç oluşturur. Bir Zod şeması işlevini alır ve aşağıdakileri içeren bir araç tanımı döndürür: +`tool` yardımcısı, OpenCode'un çağırabileceği özel bir araç oluşturur. Bir Zod şeması işlevini alır ve aşağıdakileri içeren bir araç tanımı döndürür: - `description`: Araç ne yapar? - `args`: Aracın argümanları için Zod şeması - `execute`: Araç çağrıldığında çalışan fonksiyon -Özel araçlarınız, yerleşik araçların yanı sıra kod açmaya da hazır olacaktır. +Özel araçlarınız, yerleşik araçların yanı sıra OpenCode'a da hazır olacaktır. + +:::note +Eğer bir eklenti aracı yerleşik bir araçla aynı adı kullanırsa, eklenti aracı öncelik kazanır. +::: --- ### Günlüğe kaydetme -Yapılandırılmış günlük kaydı için `client.app.log()` yerine `console.log` kullanın: +Yapılandırılmış günlük kaydı için `console.log` yerine `client.app.log()` kullanın: ```ts title=".opencode/plugins/my-plugin.ts" export const MyPlugin = async ({ client }) => { @@ -327,7 +330,7 @@ export const MyPlugin = async ({ client }) => { } ``` -Seviyeler: `debug`, `info`, `warn`, `error`. Ayrıntılar için [SDK documentation](https://opencode.ai/docs/sdk)'e bakın. +Seviyeler: `debug`, `info`, `warn`, `error`. Ayrıntılar için [SDK belgelerine](https://opencode.ai/docs/sdk) bakın. --- diff --git a/packages/web/src/content/docs/tr/providers.mdx b/packages/web/src/content/docs/tr/providers.mdx index efe5ff9afa..1ddc65131c 100644 --- a/packages/web/src/content/docs/tr/providers.mdx +++ b/packages/web/src/content/docs/tr/providers.mdx @@ -84,6 +84,37 @@ opencode'daki diğer sağlayıcılar gibi çalışır ve kullanımı tamamen ist --- +## OpenCode Go + +OpenCode Go, opencode ile iyi çalıştığı test edilmiş ve doğrulanmış, opencode ekibi tarafından sağlanan popüler açık kodlama modellerine güvenilir erişim sağlayan düşük maliyetli bir abonelik planıdır. + +1. TUI'de `/connect` komutunu çalıştırın, `OpenCode Go`'yu seçin ve [opencode.ai/auth](https://opencode.ai/zen) adresine gidin. + + ```txt + /connect + ``` + +2. Oturum açın, fatura ayrıntılarınızı ekleyin ve API anahtarınızı kopyalayın. + +3. API anahtarınızı yapıştırın. + + ```txt + ┌ API key + │ + │ + └ enter + ``` + +4. Önerdiğimiz modellerin listesini görmek için TUI'de `/models` komutunu çalıştırın. + + ```txt + /models + ``` + +opencode'daki diğer sağlayıcılar gibi çalışır ve kullanımı tamamen isteğe bağlıdır. + +--- + ## Dizin Sağlayıcılardan bazılarına ayrıntılı olarak bakalım. Bir sağlayıcı eklemek istiyorsanız @@ -1481,6 +1512,39 @@ SAP AI Core, birleşik bir platform aracılığıyla OpenAI, Anthropic, Google, --- +### STACKIT + +STACKIT AI Model Serving, Llama, Mistral ve Qwen gibi LLM'lere odaklanarak, Avrupa altyapısında maksimum veri egemenliğine sahip AI modelleri için tam olarak yönetilen bağımsız barındırma ortamı sağlar. + +1. [STACKIT Portal](https://portal.stackit.cloud) adresine gidin, **AI Model Serving**'e gidin ve projeniz için bir yetkilendirme belirteci oluşturun. + + :::tip + Yetkilendirme belirteçleri oluşturmadan önce bir STACKIT müşteri hesabına, kullanıcı hesabına ve projesine ihtiyacınız vardır. + ::: + +2. `/connect` komutunu çalıştırın ve **STACKIT**'i arayın. + + ```txt + /connect + ``` + +3. STACKIT AI Model Serving yetkilendirme belirtecinizi girin. + + ```txt + ┌ API key + │ + │ + └ enter + ``` + +4. _Qwen3-VL 235B_ veya _Llama 3.3 70B_ gibi mevcut modellerden seçim yapmak için `/models` komutunu çalıştırın. + + ```txt + /models + ``` + +--- + ### OVHcloud AI Endpoints 1. [OVHcloud panel](https://ovh.com/manager)'a gidin. `Public Cloud` bölümüne gidin, `AI & Machine Learning` > `AI Endpoints` ve `API Keys` sekmesinde **Yeni bir API anahtarı oluştur**'u tıklayın. diff --git a/packages/web/src/content/docs/tr/sdk.mdx b/packages/web/src/content/docs/tr/sdk.mdx index b5ba99f437..44c910b1cb 100644 --- a/packages/web/src/content/docs/tr/sdk.mdx +++ b/packages/web/src/content/docs/tr/sdk.mdx @@ -117,6 +117,78 @@ try { --- +## Yapılandırılmış Çıktı + +Bir JSON şeması ile `format` belirterek modelden yapılandırılmış JSON çıktısı isteyebilirsiniz. Model, şemanızla eşleşen doğrulanmış JSON'u döndürmek için bir `StructuredOutput` aracı kullanacaktır. + +### Temel Kullanım + +```typescript +const result = await client.session.prompt({ + path: { id: sessionId }, + body: { + parts: [{ type: "text", text: "Anthropic'i araştırın ve şirket bilgileri sağlayın" }], + format: { + type: "json_schema", + schema: { + type: "object", + properties: { + company: { type: "string", description: "Şirket adı" }, + founded: { type: "number", description: "Kuruluş yılı" }, + products: { + type: "array", + items: { type: "string" }, + description: "Ana ürünler", + }, + }, + required: ["company", "founded"], + }, + }, + }, +}) + +// Yapılandırılmış çıktıya erişin +console.log(result.data.info.structured_output) +// { company: "Anthropic", founded: 2021, products: ["Claude", "Claude API"] } +``` + +### Çıktı Format Türleri + +| Tür | Açıklama | +| ------------- | ------------------------------------------------------------- | +| `text` | Varsayılan. Standart metin yanıtı (yapılandırılmış çıktı yok) | +| `json_schema` | Sağlanan şema ile eşleşen doğrulanmış JSON döndürür | + +### JSON Şema Formatı + +`type: 'json_schema'` kullanırken şunları sağlayın: + +| Alan | Tür | Açıklama | +| ------------ | --------------- | ------------------------------------------------------------- | +| `type` | `'json_schema'` | Gerekli. JSON şema modunu belirtir | +| `schema` | `object` | Gerekli. Çıktı yapısını tanımlayan JSON Şema nesnesi | +| `retryCount` | `number` | İsteğe bağlı. Doğrulama yeniden deneme sayısı (varsayılan: 2) | + +### Hata Yönetimi + +Model, tüm yeniden denemelerden sonra geçerli bir yapılandırılmış çıktı üretemezse, yanıt bir `StructuredOutputError` içerecektir: + +```typescript +if (result.data.info.error?.name === "StructuredOutputError") { + console.error("Yapılandırılmış çıktı üretilemedi:", result.data.info.error.message) + console.error("Denemeler:", result.data.info.error.retries) +} +``` + +### En İyi Uygulamalar + +1. **Açık açıklamalar sağlayın**: Modelin hangi verileri çıkaracağını anlamasına yardımcı olmak için şema özelliklerinde +2. **`required` kullanın**: Hangi alanların mevcut olması gerektiğini belirtmek için +3. **Şemaları odaklı tutun**: Karmaşık iç içe geçmiş şemaların model tarafından doğru doldurulması daha zor olabilir +4. **Uygun `retryCount` ayarlayın**: Karmaşık şemalar için artırın, basit olanlar için azaltın + +--- + ## API'ler SDK, tüm sunucu API'lerini type-safe bir istemci aracılığıyla sunar. @@ -226,27 +298,27 @@ const { providers, default: defaults } = await client.config.providers() ### Oturumlar -| Yöntem | Açıklama | Notlar | -| ---------------------------------------------------------- | ------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `session.list()` | Oturumları listele | <a href={typesUrl}><code>Session[]</code></a> döndürür | -| `session.get({ path })` | Oturum al | <a href={typesUrl}><code>Session</code></a> döndürür | -| `session.children({ path })` | Alt oturumları listele | <a href={typesUrl}><code>Session[]</code></a> döndürür | -| `session.create({ body })` | Oturum oluştur | <a href={typesUrl}><code>Session</code></a> döndürür | -| `session.delete({ path })` | Oturum sil | `boolean` döndürür | -| `session.update({ path, body })` | Oturum özelliklerini güncelle | <a href={typesUrl}><code>Session</code></a> döndürür | -| `session.init({ path, body })` | Uygulamayı analiz et ve `AGENTS.md` oluştur | `boolean` döndürür | -| `session.abort({ path })` | Çalışan bir oturumu iptal et | `boolean` döndürür | -| `session.share({ path })` | Oturum paylaş | <a href={typesUrl}><code>Session</code></a> döndürür | -| `session.unshare({ path })` | Oturum paylaşımını kaldır | <a href={typesUrl}><code>Session</code></a> döndürür | -| `session.summarize({ path, body })` | Oturumu özetle | `boolean` döndürür | -| `session.messages({ path })` | Oturumdaki mesajları listele | `{ info: `<a href={typesUrl}><code>Message</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}[]` döndürür | -| `session.message({ path })` | Mesaj ayrıntılarını al | `{ info: `<a href={typesUrl}><code>Message</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}` döndürür | -| `session.prompt({ path, body })` | İstem mesajı gönder | `body.noReply: true` UserMessage (yalnızca bağlam) döndürür. Varsayılan olarak AI yanıtıyla <a href={typesUrl}><code>AssistantMessage</code></a> döndürür | -| `session.command({ path, body })` | Oturuma komut gönder | `{ info: `<a href={typesUrl}><code>AssistantMessage</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}` döndürür | -| `session.shell({ path, body })` | Bir kabuk komutu çalıştır | <a href={typesUrl}><code>AssistantMessage</code></a> döndürür | -| `session.revert({ path, body })` | Bir mesajı geri al | <a href={typesUrl}><code>Session</code></a> döndürür | -| `session.unrevert({ path })` | Geri alınan mesajları geri yükle | <a href={typesUrl}><code>Session</code></a> döndürür | -| `postSessionByIdPermissionsByPermissionId({ path, body })` | Bir izin isteğine yanıt ver | `boolean` döndürür | +| Yöntem | Açıklama | Notlar | +| ---------------------------------------------------------- | ------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `session.list()` | Oturumları listele | <a href={typesUrl}><code>Session[]</code></a> döndürür | +| `session.get({ path })` | Oturum al | <a href={typesUrl}><code>Session</code></a> döndürür | +| `session.children({ path })` | Alt oturumları listele | <a href={typesUrl}><code>Session[]</code></a> döndürür | +| `session.create({ body })` | Oturum oluştur | <a href={typesUrl}><code>Session</code></a> döndürür | +| `session.delete({ path })` | Oturum sil | `boolean` döndürür | +| `session.update({ path, body })` | Oturum özelliklerini güncelle | <a href={typesUrl}><code>Session</code></a> döndürür | +| `session.init({ path, body })` | Uygulamayı analiz et ve `AGENTS.md` oluştur | `boolean` döndürür | +| `session.abort({ path })` | Çalışan bir oturumu iptal et | `boolean` döndürür | +| `session.share({ path })` | Oturum paylaş | <a href={typesUrl}><code>Session</code></a> döndürür | +| `session.unshare({ path })` | Oturum paylaşımını kaldır | <a href={typesUrl}><code>Session</code></a> döndürür | +| `session.summarize({ path, body })` | Oturumu özetle | `boolean` döndürür | +| `session.messages({ path })` | Oturumdaki mesajları listele | `{ info: `<a href={typesUrl}><code>Message</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}[]` döndürür | +| `session.message({ path })` | Mesaj ayrıntılarını al | `{ info: `<a href={typesUrl}><code>Message</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}` döndürür | +| `session.prompt({ path, body })` | İstem mesajı gönder | `body.noReply: true` UserMessage (yalnızca bağlam) döndürür. Varsayılan olarak AI yanıtıyla <a href={typesUrl}><code>AssistantMessage</code></a> döndürür. [yapılandırılmış çıktı](#yapılandırılmış-çıktı) için `body.outputFormat` destekler | +| `session.command({ path, body })` | Oturuma komut gönder | `{ info: `<a href={typesUrl}><code>AssistantMessage</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}` döndürür | +| `session.shell({ path, body })` | Bir kabuk komutu çalıştır | <a href={typesUrl}><code>AssistantMessage</code></a> döndürür | +| `session.revert({ path, body })` | Bir mesajı geri al | <a href={typesUrl}><code>Session</code></a> döndürür | +| `session.unrevert({ path })` | Geri alınan mesajları geri yükle | <a href={typesUrl}><code>Session</code></a> döndürür | +| `postSessionByIdPermissionsByPermissionId({ path, body })` | Bir izin isteğine yanıt ver | `boolean` döndürür | --- diff --git a/packages/web/src/content/docs/tr/share.mdx b/packages/web/src/content/docs/tr/share.mdx index 1b7abfdb7e..a0544eb02a 100644 --- a/packages/web/src/content/docs/tr/share.mdx +++ b/packages/web/src/content/docs/tr/share.mdx @@ -41,7 +41,7 @@ Manuel modu acikca ayarlamak icin [config dosyaniza](/docs/config) sunu ekleyin: ```json title="opencode.json" { - "$schema": "https://opncd.ai/config.json", + "$schema": "https://opencode.ai/config.json", "share": "manual" } ``` @@ -54,7 +54,7 @@ Tum yeni konusmalar icin otomatik paylasimi acmak isterseniz, [config dosyanizda ```json title="opencode.json" { - "$schema": "https://opncd.ai/config.json", + "$schema": "https://opencode.ai/config.json", "share": "auto" } ``` @@ -69,7 +69,7 @@ Paylasimi tamamen kapatmak icin [config dosyanizda](/docs/config) `share` degeri ```json title="opencode.json" { - "$schema": "https://opncd.ai/config.json", + "$schema": "https://opencode.ai/config.json", "share": "disabled" } ``` diff --git a/packages/web/src/content/docs/tr/themes.mdx b/packages/web/src/content/docs/tr/themes.mdx index 93911315f2..1511e2b921 100644 --- a/packages/web/src/content/docs/tr/themes.mdx +++ b/packages/web/src/content/docs/tr/themes.mdx @@ -61,11 +61,11 @@ Sistem teması şu kullanıcılar için idealdir: ## Tema kullanımı -`/theme` komutuyla tema seçicisini açıp tema seçebilirsiniz. İsterseniz [config](/docs/config) dosyanızda da belirtebilirsiniz. +`/theme` komutuyla tema seçicisini açıp tema seçebilirsiniz. İsterseniz `tui.json` içinde de belirtebilirsiniz. -```json title="opencode.json" {3} +```json title="tui.json" {3} { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "theme": "tokyonight" } ``` diff --git a/packages/web/src/content/docs/tr/tui.mdx b/packages/web/src/content/docs/tr/tui.mdx index 2bd5db8f5d..55305f3672 100644 --- a/packages/web/src/content/docs/tr/tui.mdx +++ b/packages/web/src/content/docs/tr/tui.mdx @@ -1,25 +1,25 @@ --- title: TUI -description: opencode terminal arayuzunu kullanin. +description: OpenCode terminal kullanıcı arayüzünü kullanma. --- import { Tabs, TabItem } from "@astrojs/starlight/components" -opencode, projelerinizde LLM ile calismak icin etkilesimli bir terminal arayuzu (TUI) sunar. +OpenCode, projelerinizde LLM ile çalışmak için etkileşimli bir terminal arayüzü (TUI) sunar. -opencode'u calistirdiginizda mevcut dizin icin TUI baslar. +OpenCode'u çalıştırdığınızda mevcut dizin için TUI başlar. ```bash opencode ``` -Isterseniz belirli bir calisma dizini icin de baslatabilirsiniz. +İsterseniz belirli bir çalışma dizini için de başlatabilirsiniz. ```bash opencode /path/to/project ``` -TUI icinde bir mesaj yazarak istem gonderebilirsiniz. +TUI içine girdiğinizde, bir mesajla istem gönderebilirsiniz. ```text Give me a quick summary of the codebase. @@ -27,51 +27,51 @@ Give me a quick summary of the codebase. --- -## Dosya referanslari +## Dosya referansları -Mesajlarinizda `@` kullanarak dosyalara referans verebilirsiniz. Bu, mevcut calisma dizininde bulanik dosya aramasi yapar. +Mesajlarınızda `@` kullanarak dosyalara referans verebilirsiniz. Bu, mevcut çalışma dizininde bulanık dosya araması yapar. :::tip -Mesajlarinizda dosyalara referans vermek icin `@` kullanabilirsiniz. +Mesajlarınızda dosyalara referans vermek için `@` kullanabilirsiniz. ::: ```text "@packages/functions/src/api/index.ts" How is auth handled in @packages/functions/src/api/index.ts? ``` -Dosya icerigi otomatik olarak konusmaya eklenir. +Dosya içeriği otomatik olarak konuşmaya eklenir. --- -## Bash komutlari +## Bash komutları -Bir mesaji `!` ile baslatarak shell komutu calistirin. +Bir mesajı `!` ile başlatarak shell komutu çalıştırın. ```bash frame="none" !ls -la ``` -Komut ciktiisi bir arac sonucu olarak konusmaya eklenir. +Komut çıktısı bir araç sonucu olarak konuşmaya eklenir. --- ## Komutlar -opencode TUI kullanirken `/` ve komut adini yazarak hizli eylemler calistirabilirsiniz. Ornek: +OpenCode TUI kullanırken `/` ve ardından komut adını yazarak hızlı eylemler çalıştırabilirsiniz. Örneğin: ```bash frame="none" /help ``` -Komutlarin cogu, lider tusu `ctrl+x` olan bir kisayola da sahiptir. [Daha fazla bilgi](/docs/keybinds). +Komutların çoğu, lider tuşu `ctrl+x` olan bir kısayola da sahiptir. [Daha fazla bilgi](/docs/keybinds). -Mevcut slash komutlarinin tam listesi: +İşte mevcut slash komutlarının tümü: --- ### connect -opencode'a bir provider ekler. Mevcut provider'lari secip API anahtarlari eklemenizi saglar. +OpenCode'a bir sağlayıcı ekler. Mevcut sağlayıcıları seçip API anahtarları eklemenizi sağlar. ```bash frame="none" /connect @@ -81,172 +81,172 @@ opencode'a bir provider ekler. Mevcut provider'lari secip API anahtarlari ekleme ### compact -Guncel oturumu sikistirir. _Takma ad_: `/summarize` +Mevcut oturumu sıkıştırır. _Takma ad_: `/summarize` ```bash frame="none" /compact ``` -**Kisayol:** `ctrl+x c` +**Kısayol:** `ctrl+x c` --- ### details -Arac calistirma detaylarini goster/gizle yapar. +Araç çalıştırma detaylarını göster/gizle yapar. ```bash frame="none" /details ``` -**Kisayol:** `ctrl+x d` +**Kısayol:** `ctrl+x d` --- ### editor -Mesaj yazmak icin harici editor acar. `EDITOR` ortam degiskeninde ayarli editoru kullanir. [Daha fazla bilgi](#editor-setup). +Mesaj yazmak için harici editör açar. `EDITOR` ortam değişkeninde ayarlı editörü kullanır. [Daha fazla bilgi](#editor-setup). ```bash frame="none" /editor ``` -**Kisayol:** `ctrl+x e` +**Kısayol:** `ctrl+x e` --- ### exit -opencode'dan cikar. _Takma adlar_: `/quit`, `/q` +OpenCode'dan çıkar. _Takma adlar_: `/quit`, `/q` ```bash frame="none" /exit ``` -**Kisayol:** `ctrl+x q` +**Kısayol:** `ctrl+x q` --- ### export -Mevcut konusmayi Markdown olarak disa aktarir ve varsayilan editorunuzde acar. `EDITOR` ortam degiskenindeki editoru kullanir. [Daha fazla bilgi](#editor-setup). +Mevcut konuşmayı Markdown olarak dışa aktarır ve varsayılan editörünüzde açar. `EDITOR` ortam değişkeninde ayarlı editörü kullanır. [Daha fazla bilgi](#editor-setup). ```bash frame="none" /export ``` -**Kisayol:** `ctrl+x x` +**Kısayol:** `ctrl+x x` --- ### help -Yardim penceresini gosterir. +Yardım penceresini gösterir. ```bash frame="none" /help ``` -**Kisayol:** `ctrl+x h` +**Kısayol:** `ctrl+x h` --- ### init -`AGENTS.md` dosyasini olusturur veya gunceller. [Daha fazla bilgi](/docs/rules). +`AGENTS.md` dosyasını oluşturur veya günceller. [Daha fazla bilgi](/docs/rules). ```bash frame="none" /init ``` -**Kisayol:** `ctrl+x i` +**Kısayol:** `ctrl+x i` --- ### models -Kullanilabilir modelleri listeler. +Kullanılabilir modelleri listeler. ```bash frame="none" /models ``` -**Kisayol:** `ctrl+x m` +**Kısayol:** `ctrl+x m` --- ### new -Yeni bir oturum baslatir. _Takma ad_: `/clear` +Yeni bir oturum başlatır. _Takma ad_: `/clear` ```bash frame="none" /new ``` -**Kisayol:** `ctrl+x n` +**Kısayol:** `ctrl+x n` --- ### redo -Geri alinan bir mesaji tekrar uygular. Yalnizca `/undo` kullanildiktan sonra kullanilabilir. +Geri alınan bir mesajı tekrar uygular. Yalnızca `/undo` kullanıldıktan sonra kullanılabilir. :::tip -Dosya degisiklikleri de geri yuklenir. +Herhangi bir dosya değişikliği de geri yüklenir. ::: -Dahilde bu islem dosya degisikliklerini yonetmek icin Git kullanir. Bu nedenle projenizin **bir Git deposu olmasi gerekir**. +Dahili olarak bu işlem dosya değişikliklerini yönetmek için Git kullanır. Bu nedenle projenizin **bir Git deposu olması gerekir**. ```bash frame="none" /redo ``` -**Kisayol:** `ctrl+x r` +**Kısayol:** `ctrl+x r` --- ### sessions -Oturumlari listeler ve aralarinda gecis yapar. _Takma adlar_: `/resume`, `/continue` +Oturumları listeler ve aralarında geçiş yapar. _Takma adlar_: `/resume`, `/continue` ```bash frame="none" /sessions ``` -**Kisayol:** `ctrl+x l` +**Kısayol:** `ctrl+x l` --- ### share -Mevcut oturumu paylasir. [Daha fazla bilgi](/docs/share). +Mevcut oturumu paylaşır. [Daha fazla bilgi](/docs/share). ```bash frame="none" /share ``` -**Kisayol:** `ctrl+x s` +**Kısayol:** `ctrl+x s` --- ### themes -Kullanilabilir temalari listeler. +Kullanılabilir temaları listeler. ```bash frame="none" -/theme +/themes ``` -**Kisayol:** `ctrl+x t` +**Kısayol:** `ctrl+x t` --- ### thinking -Konusmadaki thinking/reasoning bloklarinin gorunurlugunu degistirir. Etkin oldugunda, genisletilmis dusunmeyi destekleyen modellerin akil yurutmelerini gorebilirsiniz. +Konuşmadaki thinking/reasoning bloklarının görünürlüğünü değiştirir. Etkin olduğunda, genişletilmiş düşünmeyi destekleyen modellerin akıl yürütme sürecini görebilirsiniz. :::note -Bu komut sadece thinking bloklarinin **gosterimini** kontrol eder, modelin gercek akil yurutmelerini acip kapatmaz. Gercek akil yurutme yetenegini degistirmek icin `ctrl+t` ile model varyantlari arasinda gecis yapin. +Bu komut sadece thinking bloklarının **gösterilip gösterilmeyeceğini** kontrol eder - modelin akıl yürütme yeteneklerini etkinleştirmez veya devre dışı bırakmaz. Gerçek akıl yürütme yeteneklerini değiştirmek için `ctrl+t` kullanarak model varyantları arasında geçiş yapın. ::: ```bash frame="none" @@ -257,25 +257,25 @@ Bu komut sadece thinking bloklarinin **gosterimini** kontrol eder, modelin gerce ### undo -Konusmadaki son mesaji geri alir. En son kullanici mesaji, sonraki tum yanitlar ve dosya degisiklikleri kaldirilir. +Konuşmadaki son mesajı geri alır. En son kullanıcı mesajını, sonraki tüm yanıtları ve dosya değişikliklerini kaldırır. :::tip -Yapilan dosya degisiklikleri de geri cevrilir. +Yapılan tüm dosya değişiklikleri de geri alınır. ::: -Dahilde bu islem dosya degisikliklerini yonetmek icin Git kullanir. Bu nedenle projenizin **bir Git deposu olmasi gerekir**. +Dahili olarak bu işlem dosya değişikliklerini yönetmek için Git kullanır. Bu nedenle projenizin **bir Git deposu olması gerekir**. ```bash frame="none" /undo ``` -**Kisayol:** `ctrl+x u` +**Kısayol:** `ctrl+x u` --- ### unshare -Mevcut oturumun paylasimini kaldirir. [Daha fazla bilgi](/docs/share#paylasimi-kaldirma). +Mevcut oturumun paylaşımını kaldırır. [Daha fazla bilgi](/docs/share#un-sharing). ```bash frame="none" /unshare @@ -283,9 +283,9 @@ Mevcut oturumun paylasimini kaldirir. [Daha fazla bilgi](/docs/share#paylasimi-k --- -## Editor kurulumu +## Editör kurulumu -`/editor` ve `/export` komutlari, `EDITOR` ortam degiskeninde tanimli editoru kullanir. +Hem `/editor` hem de `/export` komutları, `EDITOR` ortam değişkeninde belirtilen editörü kullanır. <Tabs> <TabItem label="Linux/macOS"> @@ -299,7 +299,7 @@ Mevcut oturumun paylasimini kaldirir. [Daha fazla bilgi](/docs/share#paylasimi-k export EDITOR="code --wait" ``` - Kalici yapmak icin bunu kabuk profilinize ekleyin: + Kalıcı yapmak için bunu kabuk profilinize ekleyin; `~/.bashrc`, `~/.zshrc` vb. </TabItem> @@ -313,7 +313,8 @@ Mevcut oturumun paylasimini kaldirir. [Daha fazla bilgi](/docs/share#paylasimi-k set EDITOR=code --wait ``` - Kalici yapmak icin **System Properties** > **Environment Variables** yolunu kullanin. + Kalıcı yapmak için **System Properties** > **Environment + Variables** yolunu kullanın. </TabItem> @@ -326,62 +327,72 @@ Mevcut oturumun paylasimini kaldirir. [Daha fazla bilgi](/docs/share#paylasimi-k $env:EDITOR = "code --wait" ``` - Kalici yapmak icin bunu PowerShell profilinize ekleyin. + Kalıcı yapmak için bunu PowerShell profilinize ekleyin. </TabItem> </Tabs> -Yaygin editor secenekleri: +Popüler editör seçenekleri şunları içerir: - `code` - Visual Studio Code - `cursor` - Cursor - `windsurf` - Windsurf -- `nvim` - Neovim editoru -- `vim` - Vim editoru -- `nano` - Nano editoru +- `nvim` - Neovim editörü +- `vim` - Vim editörü +- `nano` - Nano editörü - `notepad` - Windows Notepad - `subl` - Sublime Text :::note -VS Code gibi bazi editorlerin `--wait` parametresiyle baslatilmasi gerekir. +VS Code gibi bazı editörlerin `--wait` bayrağı ile başlatılması gerekir. ::: -Bazi editorler bloklayici modda calismak icin komut satiri argumanlari ister. `--wait` bayragi editor surecinin kapanana kadar beklemesini saglar. +Bazı editörler bloklama modunda çalışmak için komut satırı argümanlarına ihtiyaç duyar. `--wait` bayrağı, editör süreci kapanana kadar işlemin bloklanmasını sağlar. --- -## Yapilandirin +## Yapılandırma -TUI davranisini opencode config dosyanizdan ozellestirebilirsiniz. +TUI davranışını `tui.json` (veya `tui.jsonc`) aracılığıyla özelleştirebilirsiniz. -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", - "tui": { - "scroll_speed": 3, - "scroll_acceleration": { - "enabled": true - } - } + "$schema": "https://opencode.ai/tui.json", + "theme": "opencode", + "keybinds": { + "leader": "ctrl+x" + }, + "scroll_speed": 3, + "scroll_acceleration": { + "enabled": true + }, + "diff_style": "auto" } ``` -### Secenekler +Bu, sunucu/çalışma zamanı davranışını yapılandıran `opencode.json` dosyasından ayrıdır. -- `scroll_acceleration` - Daha akici ve dogal kaydirma icin macOS tarzı hizlanmayi acar. Etkin oldugunda hizli kaydirma hareketlerinde hiz artar, yavas hareketlerde hassas kalir. **Bu ayar etkin oldugunda `scroll_speed` degerini gecersiz kilar.** -- `scroll_speed` - Kaydirma komutlariyla TUI'nin ne kadar hizli kayacagini belirler (minimum: `1`). Varsayilan `3` degeridir. **Not: `scroll_acceleration.enabled` `true` ise yok sayilir.** +### Seçenekler + +- `theme` - UI temanızı ayarlar. [Daha fazla bilgi](/docs/themes). +- `keybinds` - Klavye kısayollarını özelleştirir. [Daha fazla bilgi](/docs/keybinds). +- `scroll_acceleration.enabled` - Pürüzsüz, doğal kaydırma için macOS tarzı kaydırma ivmesini etkinleştirin. Etkinleştirildiğinde, kaydırma hızı hızlı kaydırma hareketleriyle artar ve daha yavaş hareketler için hassas kalır. **Bu ayar `scroll_speed` ayarından önceliklidir ve etkinleştirildiğinde onu geçersiz kılar.** +- `scroll_speed` - Kaydırma komutlarını kullanırken TUI'nin ne kadar hızlı kaydırılacağını kontrol eder (minimum: `0.001`, ondalık değerleri destekler). Varsayılan değer `3`'tür. **Not: `scroll_acceleration.enabled` `true` olarak ayarlanmışsa bu yok sayılır.** +- `diff_style` - Fark (diff) oluşturmayı kontrol eder. `"auto"` terminal genişliğine uyum sağlar, `"stacked"` her zaman tek sütunlu bir düzen gösterir. + +Özel bir TUI yapılandırma yolu yüklemek için `OPENCODE_TUI_CONFIG` kullanın. --- -## Ozellestirme +## Özelleştirme -TUI gorunumunun cesitli kisimlarini komut paletiyle (`ctrl+x h` veya `/help`) ozellestirebilirsiniz. Bu ayarlar yeniden baslatmalar arasinda korunur. +Komut paletini (`ctrl+x h` veya `/help`) kullanarak TUI görünümünün çeşitli yönlerini özelleştirebilirsiniz. Bu ayarlar yeniden başlatmalar arasında korunur. --- -#### Kullanici adi gorunumu +#### Kullanıcı adı görünümü -Sohbet mesajlarinda kullanici adinizin gosterilip gosterilmeyecegini degistirir. Sunlardan erisebilirsiniz: +Sohbet mesajlarında kullanıcı adınızın görünüp görünmeyeceğini değiştirin. Buna şuradan erişin: -- Komut paleti: "username" veya "hide username" aratin -- Ayar otomatik saklanir ve TUI oturumlarinda hatirlanir +- Komut paleti: "username" veya "hide username" araması yapın +- Ayar otomatik olarak kalıcı hale gelir ve TUI oturumları arasında hatırlanır diff --git a/packages/web/src/content/docs/tr/zen.mdx b/packages/web/src/content/docs/tr/zen.mdx index b997889419..2b79bb9625 100644 --- a/packages/web/src/content/docs/tr/zen.mdx +++ b/packages/web/src/content/docs/tr/zen.mdx @@ -1,61 +1,62 @@ --- title: Zen -description: opencode ekibinin sundugu secili model listesi. +description: opencode tarafından sağlanan seçilmiş modeller listesi. --- import config from "../../../../config.mjs" export const console = config.console export const email = `mailto:${config.email}` -OpenCode Zen, opencode ekibi tarafindan test edilip dogrulanmis modellerin listesidir. +OpenCode Zen, opencode ekibi tarafından test edilip doğrulanmış modellerin bir listesidir. :::note -OpenCode Zen su anda beta asamasindadir. +OpenCode Zen şu anda beta aşamasındadır. ::: -Zen, opencode'daki diger provider'lar gibi calisir. OpenCode Zen'e giris yapar ve API anahtarinizi alirsiniz. -Tamamen istege baglidir; opencode kullanmak icin Zen kullanmak zorunda degilsiniz. +Zen, opencode'daki diğer sağlayıcılar gibi çalışır. OpenCode Zen'e giriş yapar ve API anahtarınızı alırsınız. Tamamen isteğe bağlıdır ve opencode kullanmak için bunu kullanmanıza gerek yoktur. --- ## Arka plan -Piyasada cok sayida model var, ancak bunlarin sadece bir kismi kodlama ajani olarak iyi calisir. Ayrica provider'larin cogu birbirinden cok farkli sekilde ayarlanir; bu da performans ve kaliteyi ciddi bicimde degistirir. +Piyasada çok sayıda model var ancak bu modellerden sadece birkaçı kodlama ajanı olarak iyi çalışır. Ayrıca çoğu sağlayıcı çok farklı şekilde yapılandırılmıştır; bu nedenle çok farklı performans ve kalite elde edersiniz. :::tip -opencode ile iyi calisan belirli model/provider kombinasyonlarini test ettik. +opencode ile iyi çalışan seçkin bir grup model ve sağlayıcıyı test ettik. ::: -Bu nedenle OpenRouter benzeri bir servis uzerinden model kullaniyorsaniz, istediginiz modelin en iyi surumunu alip almadiginizdan her zaman emin olamazsiniz. +Bu nedenle, OpenRouter gibi bir şey üzerinden bir model kullanıyorsanız, istediğiniz modelin en iyi sürümünü alıp almadığınızdan asla emin olamazsınız. -Bunu cozmeye yonelik olarak sunlari yaptik: +Bunu düzeltmek için birkaç şey yaptık: -1. Secili bir model grubunu test ettik ve ekipleriyle en iyi calisma sekli uzerine gorustuk -2. Daha sonra bazi provider'larla bu modellerin dogru sekilde sunuldugunu dogruladik -3. Son olarak model/provider kombinasyonlarini benchmark ederek guvenle onerebilecegimiz bir liste olusturduk +1. Seçkin bir grup modeli test ettik ve ekipleriyle bunları en iyi nasıl çalıştıracakları hakkında konuştuk. +2. Daha sonra bunların doğru şekilde sunulduğundan emin olmak için birkaç sağlayıcıyla çalıştık. +3. Son olarak model/sağlayıcı kombinasyonunu karşılaştırdık ve önermekten memnuniyet duyduğumuz bir liste oluşturduk. -OpenCode Zen, bu modellere erisim saglayan bir AI gateway'dir. +OpenCode Zen, bu modellere erişmenizi sağlayan bir AI ağ geçididir. --- -## Nasil calisir +## Nasıl çalışır -OpenCode Zen, opencode'daki diger provider'lar gibi calisir. +OpenCode Zen, opencode'daki diğer sağlayıcılar gibi çalışır. -1. **<a href={console}>OpenCode Zen</a>** hesabina giris yapin, odeme bilgilerinizi ekleyin ve API anahtarinizi kopyalayin -2. TUI'da `/connect` komutunu calistirin, OpenCode Zen'i secin ve API anahtarinizi yapistirin -3. Onerdigimiz model listesini gormek icin TUI'da `/models` calistirin +1. **<a href={console}>OpenCode Zen</a>**'de oturum açın, fatura ayrıntılarınızı ekleyin ve API anahtarınızı kopyalayın. +2. TUI'de `/connect` komutunu çalıştırın, OpenCode Zen'i seçin ve API anahtarınızı yapıştırın. +3. Önerdiğimiz modellerin listesini görmek için TUI'de `/models` komutunu çalıştırın. -Ucretlendirme istek basina yapilir ve hesabiniza kredi yukleyebilirsiniz. +İstek başına ücretlendirilirsiniz ve hesabınıza kredi ekleyebilirsiniz. --- -## Endpoint'ler +## Uç Noktalar -Modellerimize asagidaki API endpoint'leri uzerinden de erisebilirsiniz. +Modellerimize aşağıdaki API uç noktaları aracılığıyla da erişebilirsiniz. | Model | Model ID | Endpoint | AI SDK Package | | ------------------ | ------------------ | -------------------------------------------------- | --------------------------- | +| GPT 5.4 | gpt-5.4 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| GPT 5.3 Codex | gpt-5.3-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.2 | gpt-5.2 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.2 Codex | gpt-5.2-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.1 | gpt-5.1 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | @@ -65,35 +66,36 @@ Modellerimize asagidaki API endpoint'leri uzerinden de erisebilirsiniz. | GPT 5 | gpt-5 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5 Codex | gpt-5-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5 Nano | gpt-5-nano | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| Claude Opus 4.6 | claude-opus-4-6 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Opus 4.5 | claude-opus-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Opus 4.1 | claude-opus-4-1 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Sonnet 4.6 | claude-sonnet-4-6 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Sonnet 4.5 | claude-sonnet-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Sonnet 4 | claude-sonnet-4 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Haiku 4.5 | claude-haiku-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Haiku 3.5 | claude-3-5-haiku | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| Claude Opus 4.6 | claude-opus-4-6 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| Claude Opus 4.5 | claude-opus-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| Claude Opus 4.1 | claude-opus-4-1 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Gemini 3.1 Pro | gemini-3.1-pro | `https://opencode.ai/zen/v1/models/gemini-3.1-pro` | `@ai-sdk/google` | | Gemini 3 Pro | gemini-3-pro | `https://opencode.ai/zen/v1/models/gemini-3-pro` | `@ai-sdk/google` | | Gemini 3 Flash | gemini-3-flash | `https://opencode.ai/zen/v1/models/gemini-3-flash` | `@ai-sdk/google` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.5 Free | minimax-m2.5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | MiniMax M2.1 | minimax-m2.1 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.1 Free | minimax-m2.1-free | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| GLM 5 | glm-5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | GLM 4.7 | glm-4.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM 4.7 Free | glm-4.7-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | GLM 4.6 | glm-4.6 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 Free | kimi-k2.5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2 Thinking | kimi-k2-thinking | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2 | kimi-k2 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Qwen3 Coder 480B | qwen3-coder | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Big Pickle | big-pickle | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -opencode config'inizdeki [model id](/docs/config/#models), `opencode/<model-id>` formatini kullanir. -Ornegin GPT 5.2 Codex icin config'te `opencode/gpt-5.2-codex` kullanirsiniz. +opencode yapılandırmanızdaki [model kimliği](/docs/config/#models) `opencode/<model-id>` biçimini kullanır. Örneğin, GPT 5.2 Codex için yapılandırmanızda `opencode/gpt-5.2-codex` kullanırsınız. --- ### Modeller -Mevcut modellerin tam listesini ve metadatasini su adresten cekebilirsiniz: +Mevcut modellerin tam listesini ve meta verilerini şuradan alabilirsiniz: ``` https://opencode.ai/zen/v1/models @@ -101,36 +103,42 @@ https://opencode.ai/zen/v1/models --- -## Fiyatlandirma +## Fiyatlandırma -Kullandikca ode modelini destekliyoruz. Asagidaki fiyatlar **1M token basina** verilmistir. +Kullandıkça öde modelini destekliyoruz. Aşağıda **1 milyon token başına** fiyatlar verilmiştir. | Model | Input | Output | Cached Read | Cached Write | | --------------------------------- | ------ | ------ | ----------- | ------------ | | Big Pickle | Free | Free | Free | - | -| MiniMax M2.1 Free | Free | Free | Free | - | +| MiniMax M2.5 Free | Free | Free | Free | - | +| MiniMax M2.5 | $0.30 | $1.20 | $0.06 | - | | MiniMax M2.1 | $0.30 | $1.20 | $0.10 | - | -| GLM 4.7 Free | Free | Free | Free | - | +| GLM 5 | $1.00 | $3.20 | $0.20 | - | | GLM 4.7 | $0.60 | $2.20 | $0.10 | - | | GLM 4.6 | $0.60 | $2.20 | $0.10 | - | -| Kimi K2.5 Free | Free | Free | Free | - | | Kimi K2.5 | $0.60 | $3.00 | $0.08 | - | | Kimi K2 Thinking | $0.40 | $2.50 | - | - | | Kimi K2 | $0.40 | $2.50 | - | - | | Qwen3 Coder 480B | $0.45 | $1.50 | - | - | +| Claude Opus 4.6 (≤ 200K tokens) | $5.00 | $25.00 | $0.50 | $6.25 | +| Claude Opus 4.6 (> 200K tokens) | $10.00 | $37.50 | $1.00 | $12.50 | +| Claude Opus 4.5 | $5.00 | $25.00 | $0.50 | $6.25 | +| Claude Opus 4.1 | $15.00 | $75.00 | $1.50 | $18.75 | +| Claude Sonnet 4.6 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 | +| Claude Sonnet 4.6 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 | | Claude Sonnet 4.5 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 | | Claude Sonnet 4.5 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 | | Claude Sonnet 4 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 | | Claude Sonnet 4 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 | | Claude Haiku 4.5 | $1.00 | $5.00 | $0.10 | $1.25 | | Claude Haiku 3.5 | $0.80 | $4.00 | $0.08 | $1.00 | -| Claude Opus 4.6 (≤ 200K tokens) | $5.00 | $25.00 | $0.50 | $6.25 | -| Claude Opus 4.6 (> 200K tokens) | $10.00 | $37.50 | $1.00 | $12.50 | -| Claude Opus 4.5 | $5.00 | $25.00 | $0.50 | $6.25 | -| Claude Opus 4.1 | $15.00 | $75.00 | $1.50 | $18.75 | +| Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | +| Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | | Gemini 3 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | +| GPT 5.4 | $2.50 | $15.00 | $0.25 | - | +| GPT 5.3 Codex | $1.75 | $14.00 | $0.175 | - | | GPT 5.2 | $1.75 | $14.00 | $0.175 | - | | GPT 5.2 Codex | $1.75 | $14.00 | $0.175 | - | | GPT 5.1 | $1.07 | $8.50 | $0.107 | - | @@ -141,98 +149,107 @@ Kullandikca ode modelini destekliyoruz. Asagidaki fiyatlar **1M token basina** v | GPT 5 Codex | $1.07 | $8.50 | $0.107 | - | | GPT 5 Nano | Free | Free | Free | - | -Kullanim gecmisinizde _Claude Haiku 3.5_ gorebilirsiniz. Bu, oturum basliklarini olusturmak icin kullanilan [dusuk maliyetli bir modeldir](/docs/config/#models). +Kullanım geçmişinizde _Claude Haiku 3.5_ fark edebilirsiniz. Bu, oturumlarınızın başlıklarını oluşturmak için kullanılan [düşük maliyetli bir modeldir](/docs/config/#models). :::note -Kredi karti ucretleri maliyetine yansitilir (islem basina %4.4 + $0.30); bunun disinda ek ucret almiyoruz. +Kredi kartı ücretleri maliyetine yansıtılır (işlem başına %4,4 + 0,30$); bunun ötesinde hiçbir ücret talep etmiyoruz. ::: -Ucretsiz modeller: +Ücretsiz modeller: -- GLM 4.7 Free, sinirli bir sure icin opencode'da ucretsizdir. Ekip bu surede geri bildirim toplayip modeli iyilestiriyor -- Kimi K2.5 Free, sinirli bir sure icin opencode'da ucretsizdir. Ekip bu surede geri bildirim toplayip modeli iyilestiriyor -- MiniMax M2.1 Free, sinirli bir sure icin opencode'da ucretsizdir. Ekip bu surede geri bildirim toplayip modeli iyilestiriyor -- Big Pickle, sinirli bir sure icin opencode'da ucretsiz olan gizli bir modeldir. Ekip bu surede geri bildirim toplayip modeli iyilestiriyor +- MiniMax M2.5 Free, sınırlı bir süre için OpenCode'da ücretsizdir. Ekip bu süreyi geri bildirim toplamak ve modeli iyileştirmek için kullanıyor. +- Big Pickle, sınırlı bir süre için OpenCode'da ücretsiz olan gizli bir modeldir. Ekip bu süreyi geri bildirim toplamak ve modeli iyileştirmek için kullanıyor. -Sorunuz varsa <a href={email}>bize ulasin</a>. +Sorularınız varsa <a href={email}>bizimle iletişime geçin</a>. --- -### Otomatik yukleme +### Otomatik yükleme -Bakiyeniz $5'in altina dustugunde Zen otomatik olarak $20 yukler. +Bakiyeniz 5$'ın altına düşerse, Zen otomatik olarak 20$ yükler. -Otomatik yukleme tutarini degistirebilir veya bu ozelligi tamamen kapatabilirsiniz. +Otomatik yükleme tutarını değiştirebilirsiniz. Otomatik yüklemeyi tamamen devre dışı da bırakabilirsiniz. --- -### Aylik limitler +### Aylık limitler -Tum calisma alani ve ekip uyeleri icin aylik kullanim limiti belirleyebilirsiniz. +Ayrıca tüm çalışma alanı ve ekibinizin her üyesi için aylık kullanım limiti belirleyebilirsiniz. -Ornegin aylik limiti $20 yaptiysaniz Zen bir ayda $20'den fazla kullandirtmaz. Ancak otomatik yukleme aciksa bakiye $5 altina dustugunde toplam odemeniz $20'nin uzerine cikabilir. +Örneğin, aylık kullanım limitini 20$ olarak ayarladığınızı varsayalım, Zen bir ayda 20$'dan fazla kullanmaz. Ancak otomatik yüklemeyi etkinleştirdiyseniz, bakiyeniz 5$'ın altına düşerse Zen sizden 20$'dan fazla ücret alabilir. + +--- + +### Kullanımdan kaldırılan modeller + +| Model | Kullanımdan kaldırılma tarihi | +| ---------------- | ----------------------------- | +| Qwen3 Coder 480B | 6 Şub 2026 | +| Kimi K2 Thinking | 6 Mar 2026 | +| Kimi K2 | 6 Mar 2026 | +| MiniMax M2.1 | 15 Mar 2026 | +| GLM 4.7 | 15 Mar 2026 | +| GLM 4.6 | 15 Mar 2026 | --- ## Gizlilik -Tum modellerimiz ABD'de barindiriliyor. Provider'larimiz sifir saklama politikasini izler ve verilerinizi model egitimi icin kullanmaz; asagidaki istisnalar haric: +Tüm modellerimiz ABD'de barındırılmaktadır. Sağlayıcılarımız sıfır saklama politikasını izler ve aşağıdaki istisnalar dışında verilerinizi model eğitimi için kullanmaz: -- Big Pickle: Ucretsiz donemde toplanan veriler modeli iyilestirmek icin kullanilabilir -- GLM 4.7 Free: Ucretsiz donemde toplanan veriler modeli iyilestirmek icin kullanilabilir -- Kimi K2.5 Free: Ucretsiz donemde toplanan veriler modeli iyilestirmek icin kullanilabilir -- MiniMax M2.1 Free: Ucretsiz donemde toplanan veriler modeli iyilestirmek icin kullanilabilir -- OpenAI API'leri: Istekler [OpenAI veri politikalari](https://platform.openai.com/docs/guides/your-data) kapsaminda 30 gun saklanir -- Anthropic API'leri: Istekler [Anthropic veri politikalari](https://docs.anthropic.com/en/docs/claude-code/data-usage) kapsaminda 30 gun saklanir +- Big Pickle: Ücretsiz döneminde toplanan veriler modeli iyileştirmek için kullanılabilir. +- MiniMax M2.5 Free: Ücretsiz döneminde toplanan veriler modeli iyileştirmek için kullanılabilir. +- OpenAI API'leri: İstekler [OpenAI'nin Veri Politikaları](https://platform.openai.com/docs/guides/your-data) uyarınca 30 gün boyunca saklanır. +- Anthropic API'leri: İstekler [Anthropic'in Veri Politikaları](https://docs.anthropic.com/en/docs/claude-code/data-usage) uyarınca 30 gün boyunca saklanır. --- -## Ekipler icin +## Ekipler İçin -Zen ekipler icin de guclu bir cozumdur. Ekip arkadaslarini davet edebilir, roller atayabilir, kullanilacak modelleri yonetebilir ve daha fazlasini yapabilirsiniz. +Zen ekipler için de harika çalışır. Ekip arkadaşlarınızı davet edebilir, roller atayabilir, ekibinizin kullandığı modelleri düzenleyebilir ve daha fazlasını yapabilirsiniz. :::note -Calisma alanlari beta kapsaminda su anda ekipler icin ucretsizdir. +Çalışma alanları şu anda beta'nın bir parçası olarak ekipler için ücretsizdir. ::: -Calisma alani yonetimi su anda beta kapsaminda ucretsizdir. Fiyatlandirma detaylarini yakinda paylasacagiz. +Çalışma alanınızı yönetmek şu anda beta'nın bir parçası olarak ekipler için ücretsizdir. Yakında fiyatlandırma hakkında daha fazla ayrıntı paylaşacağız. --- ### Roller -Calisma alaniniza ekip arkadaslarini davet edip rol atayabilirsiniz: +Ekip arkadaşlarınızı çalışma alanınıza davet edebilir ve roller atayabilirsiniz: -- **Admin**: Modelleri, uyeleri, API anahtarlarini ve faturalandirmayi yonetir -- **Member**: Yalnizca kendi API anahtarlarini yonetir +- **Admin**: Modelleri, üyeleri, API anahtarlarını ve faturalandırmayı yönetin +- **Member**: Yalnızca kendi API anahtarlarını yönetin -Admin'ler maliyet kontrolu icin uye bazinda aylik harcama limitleri de ayarlayabilir. +Yöneticiler, maliyetleri kontrol altında tutmak için her üye için aylık harcama limitleri de belirleyebilir. --- -### Model erisimi +### Model erişimi -Admin'ler calisma alani icin belirli modelleri acip kapatabilir. Devre disi bir modele yapilan istekler hata dondurur. +Yöneticiler çalışma alanı için belirli modelleri etkinleştirebilir veya devre dışı bırakabilir. Devre dışı bırakılmış bir modele yapılan istekler bir hata döndürür. -Bu, veri toplayan bir modelin kullanimini kapatmak istediginiz durumlarda kullanislidir. +Bu, veri toplayan bir modelin kullanımını devre dışı bırakmak istediğiniz durumlarda kullanışlıdır. --- -### Kendi anahtarinizi kullanin +### Kendi anahtarınızı getirin -Zen'deki diger modellere erisirken kendi OpenAI veya Anthropic API anahtarlarinizi da kullanabilirsiniz. +Zen'deki diğer modellere erişmeye devam ederken kendi OpenAI veya Anthropic API anahtarlarınızı kullanabilirsiniz. -Kendi anahtarinizi kullandiginizda token ucreti Zen yerine dogrudan provider tarafindan faturalandirilir. +Kendi anahtarlarınızı kullandığınızda, tokenler Zen tarafından değil, doğrudan sağlayıcı tarafından faturalandırılır. -Ornegin kurulusunuzun zaten OpenAI veya Anthropic anahtari varsa Zen'in sagladigi anahtar yerine onu kullanabilirsiniz. +Örneğin, kuruluşunuzun halihazırda OpenAI veya Anthropic için bir anahtarı olabilir ve Zen'in sağladığı anahtar yerine onu kullanmak isteyebilirsiniz. --- ## Hedefler -OpenCode Zen'i su amaclarla olusturduk: +OpenCode Zen'i şu amaçlarla oluşturduk: -1. Kodlama ajanlari icin en iyi model/provider kombinasyonlarini **benchmark etmek** -2. Performansi dusurmeden veya daha ucuz provider'a yonlendirmeden **en yuksek kaliteye** erismek -3. Maliyetine satarak fiyat dususlerini kullaniciya yansitmak ve yalnizca islem ucretlerini kapsayan pay birakmak -4. Herhangi bir kodlama ajaniyla kullanima izin vererek **kilitlenmeyi onlemek** ve opencode'da diger provider'lari her zaman acik tutmak +1. Kodlama ajanları için en iyi modelleri/sağlayıcıları **kıyaslamak**. +2. **En yüksek kaliteli** seçeneklere erişmek ve performansı düşürmemek veya daha ucuz sağlayıcılara yönlendirmemek. +3. Maliyetine satış yaparak herhangi bir **fiyat düşüşünü** yansıtmak; böylece tek kâr marjı işlem ücretlerimizi karşılamaktır. +4. Başka bir kodlama ajanıyla kullanmanıza izin vererek **kilitlenmeyi önlemek**. Ve her zaman OpenCode ile başka bir sağlayıcıyı kullanmanıza izin vermek. diff --git a/packages/web/src/content/docs/tui.mdx b/packages/web/src/content/docs/tui.mdx index 085eb6169f..010e8328f4 100644 --- a/packages/web/src/content/docs/tui.mdx +++ b/packages/web/src/content/docs/tui.mdx @@ -235,7 +235,7 @@ Share current session. [Learn more](/docs/share). List available themes. ```bash frame="none" -/theme +/themes ``` **Keybind:** `ctrl+x t` @@ -355,24 +355,34 @@ Some editors need command-line arguments to run in blocking mode. The `--wait` f ## Configure -You can customize TUI behavior through your OpenCode config file. +You can customize TUI behavior through `tui.json` (or `tui.jsonc`). -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", - "tui": { - "scroll_speed": 3, - "scroll_acceleration": { - "enabled": true - } - } + "$schema": "https://opencode.ai/tui.json", + "theme": "opencode", + "keybinds": { + "leader": "ctrl+x" + }, + "scroll_speed": 3, + "scroll_acceleration": { + "enabled": true + }, + "diff_style": "auto" } ``` +This is separate from `opencode.json`, which configures server/runtime behavior. + ### Options -- `scroll_acceleration` - Enable macOS-style scroll acceleration for smooth, natural scrolling. When enabled, scroll speed increases with rapid scrolling gestures and stays precise for slower movements. **This setting takes precedence over `scroll_speed` and overrides it when enabled.** -- `scroll_speed` - Controls how fast the TUI scrolls when using scroll commands (minimum: `1`). Defaults to `3`. **Note: This is ignored if `scroll_acceleration.enabled` is set to `true`.** +- `theme` - Sets your UI theme. [Learn more](/docs/themes). +- `keybinds` - Customizes keyboard shortcuts. [Learn more](/docs/keybinds). +- `scroll_acceleration.enabled` - Enable macOS-style scroll acceleration for smooth, natural scrolling. When enabled, scroll speed increases with rapid scrolling gestures and stays precise for slower movements. **This setting takes precedence over `scroll_speed` and overrides it when enabled.** +- `scroll_speed` - Controls how fast the TUI scrolls when using scroll commands (minimum: `0.001`, supports decimal values). Defaults to `3`. **Note: This is ignored if `scroll_acceleration.enabled` is set to `true`.** +- `diff_style` - Controls diff rendering. `"auto"` adapts to terminal width, `"stacked"` always shows a single-column layout. + +Use `OPENCODE_TUI_CONFIG` to load a custom TUI config path. --- diff --git a/packages/web/src/content/docs/zen.mdx b/packages/web/src/content/docs/zen.mdx index 453093206b..330f90014d 100644 --- a/packages/web/src/content/docs/zen.mdx +++ b/packages/web/src/content/docs/zen.mdx @@ -62,45 +62,47 @@ You are charged per request and you can add credits to your account. You can also access our models through the following API endpoints. -| Model | Model ID | Endpoint | AI SDK Package | -| ------------------ | ------------------ | -------------------------------------------------- | --------------------------- | -| GPT 5.2 | gpt-5.2 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | -| GPT 5.2 Codex | gpt-5.2-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | -| GPT 5.1 | gpt-5.1 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | -| GPT 5.1 Codex | gpt-5.1-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | -| GPT 5.1 Codex Max | gpt-5.1-codex-max | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | -| GPT 5.1 Codex Mini | gpt-5.1-codex-mini | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | -| GPT 5 | gpt-5 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | -| GPT 5 Codex | gpt-5-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | -| GPT 5 Nano | gpt-5-nano | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | -| Claude Opus 4.6 | claude-opus-4-6 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| Claude Opus 4.5 | claude-opus-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| Claude Opus 4.1 | claude-opus-4-1 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| Claude Sonnet 4.6 | claude-sonnet-4-6 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| Claude Sonnet 4.5 | claude-sonnet-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| Claude Sonnet 4 | claude-sonnet-4 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| Claude Haiku 4.5 | claude-haiku-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| Claude Haiku 3.5 | claude-3-5-haiku | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| Gemini 3.1 Pro | gemini-3.1-pro | `https://opencode.ai/zen/v1/models/gemini-3.1-pro` | `@ai-sdk/google` | -| Gemini 3 Pro | gemini-3-pro | `https://opencode.ai/zen/v1/models/gemini-3-pro` | `@ai-sdk/google` | -| Gemini 3 Flash | gemini-3-flash | `https://opencode.ai/zen/v1/models/gemini-3-flash` | `@ai-sdk/google` | -| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.5 Free | minimax-m2.5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| MiniMax M2.1 | minimax-m2.1 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM 5 | glm-5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM 5 Free | glm-5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM 4.7 | glm-4.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| GLM 4.6 | glm-4.6 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 Free | kimi-k2.5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2 Thinking | kimi-k2-thinking | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2 | kimi-k2 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Qwen3 Coder 480B | qwen3-coder | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Big Pickle | big-pickle | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Model | Model ID | Endpoint | AI SDK Package | +| ------------------- | ------------------- | -------------------------------------------------- | --------------------------- | +| GPT 5.4 Pro | gpt-5.4-pro | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| GPT 5.4 | gpt-5.4 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| GPT 5.3 Codex | gpt-5.3-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| GPT 5.3 Codex Spark | gpt-5.3-codex-spark | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| GPT 5.2 | gpt-5.2 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| GPT 5.2 Codex | gpt-5.2-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| GPT 5.1 | gpt-5.1 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| GPT 5.1 Codex | gpt-5.1-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| GPT 5.1 Codex Max | gpt-5.1-codex-max | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| GPT 5.1 Codex Mini | gpt-5.1-codex-mini | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| GPT 5 | gpt-5 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| GPT 5 Codex | gpt-5-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| GPT 5 Nano | gpt-5-nano | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| Claude Opus 4.6 | claude-opus-4-6 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Opus 4.5 | claude-opus-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Opus 4.1 | claude-opus-4-1 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Sonnet 4.6 | claude-sonnet-4-6 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Sonnet 4.5 | claude-sonnet-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Sonnet 4 | claude-sonnet-4 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Haiku 4.5 | claude-haiku-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Haiku 3.5 | claude-3-5-haiku | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Gemini 3.1 Pro | gemini-3.1-pro | `https://opencode.ai/zen/v1/models/gemini-3.1-pro` | `@ai-sdk/google` | +| Gemini 3 Pro | gemini-3-pro | `https://opencode.ai/zen/v1/models/gemini-3-pro` | `@ai-sdk/google` | +| Gemini 3 Flash | gemini-3-flash | `https://opencode.ai/zen/v1/models/gemini-3-flash` | `@ai-sdk/google` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.5 Free | minimax-m2.5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.1 | minimax-m2.1 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| GLM 5 | glm-5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| GLM 4.7 | glm-4.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| GLM 4.6 | glm-4.6 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2 Thinking | kimi-k2-thinking | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2 | kimi-k2 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Qwen3 Coder 480B | qwen3-coder | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Big Pickle | big-pickle | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | The [model id](/docs/config/#models) in your OpenCode config -uses the format `opencode/<model-id>`. For example, for GPT 5.2 Codex, you would -use `opencode/gpt-5.2-codex` in your config. +uses the format `opencode/<model-id>`. For example, for GPT 5.3 Codex, you would +use `opencode/gpt-5.3-codex` in your config. --- @@ -118,47 +120,49 @@ https://opencode.ai/zen/v1/models We support a pay-as-you-go model. Below are the prices **per 1M tokens**. -| Model | Input | Output | Cached Read | Cached Write | -| --------------------------------- | ------ | ------ | ----------- | ------------ | -| Big Pickle | Free | Free | Free | - | -| MiniMax M2.5 Free | Free | Free | Free | - | -| MiniMax M2.5 | $0.30 | $1.20 | $0.06 | - | -| MiniMax M2.1 | $0.30 | $1.20 | $0.10 | - | -| GLM 5 Free | Free | Free | Free | - | -| GLM 5 | $1.00 | $3.20 | $0.20 | - | -| GLM 4.7 | $0.60 | $2.20 | $0.10 | - | -| GLM 4.6 | $0.60 | $2.20 | $0.10 | - | -| Kimi K2.5 Free | Free | Free | Free | - | -| Kimi K2.5 | $0.60 | $3.00 | $0.08 | - | -| Kimi K2 Thinking | $0.40 | $2.50 | - | - | -| Kimi K2 | $0.40 | $2.50 | - | - | -| Qwen3 Coder 480B | $0.45 | $1.50 | - | - | -| Claude Opus 4.6 (≤ 200K tokens) | $5.00 | $25.00 | $0.50 | $6.25 | -| Claude Opus 4.6 (> 200K tokens) | $10.00 | $37.50 | $1.00 | $12.50 | -| Claude Opus 4.5 | $5.00 | $25.00 | $0.50 | $6.25 | -| Claude Opus 4.1 | $15.00 | $75.00 | $1.50 | $18.75 | -| Claude Sonnet 4.6 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 | -| Claude Sonnet 4.6 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 | -| Claude Sonnet 4.5 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 | -| Claude Sonnet 4.5 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 | -| Claude Sonnet 4 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 | -| Claude Sonnet 4 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 | -| Claude Haiku 4.5 | $1.00 | $5.00 | $0.10 | $1.25 | -| Claude Haiku 3.5 | $0.80 | $4.00 | $0.08 | $1.00 | -| Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | -| Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | -| Gemini 3 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | -| Gemini 3 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | -| Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | -| GPT 5.2 | $1.75 | $14.00 | $0.175 | - | -| GPT 5.2 Codex | $1.75 | $14.00 | $0.175 | - | -| GPT 5.1 | $1.07 | $8.50 | $0.107 | - | -| GPT 5.1 Codex | $1.07 | $8.50 | $0.107 | - | -| GPT 5.1 Codex Max | $1.25 | $10.00 | $0.125 | - | -| GPT 5.1 Codex Mini | $0.25 | $2.00 | $0.025 | - | -| GPT 5 | $1.07 | $8.50 | $0.107 | - | -| GPT 5 Codex | $1.07 | $8.50 | $0.107 | - | -| GPT 5 Nano | Free | Free | Free | - | +| Model | Input | Output | Cached Read | Cached Write | +| --------------------------------- | ------ | ------- | ----------- | ------------ | +| Big Pickle | Free | Free | Free | - | +| MiniMax M2.5 Free | Free | Free | Free | - | +| MiniMax M2.5 | $0.30 | $1.20 | $0.06 | $0.375 | +| MiniMax M2.1 | $0.30 | $1.20 | $0.10 | - | +| GLM 5 | $1.00 | $3.20 | $0.20 | - | +| GLM 4.7 | $0.60 | $2.20 | $0.10 | - | +| GLM 4.6 | $0.60 | $2.20 | $0.10 | - | +| Kimi K2.5 | $0.60 | $3.00 | $0.10 | - | +| Kimi K2 Thinking | $0.40 | $2.50 | - | - | +| Kimi K2 | $0.40 | $2.50 | - | - | +| Qwen3 Coder 480B | $0.45 | $1.50 | - | - | +| Claude Opus 4.6 (≤ 200K tokens) | $5.00 | $25.00 | $0.50 | $6.25 | +| Claude Opus 4.6 (> 200K tokens) | $10.00 | $37.50 | $1.00 | $12.50 | +| Claude Opus 4.5 | $5.00 | $25.00 | $0.50 | $6.25 | +| Claude Opus 4.1 | $15.00 | $75.00 | $1.50 | $18.75 | +| Claude Sonnet 4.6 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 | +| Claude Sonnet 4.6 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 | +| Claude Sonnet 4.5 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 | +| Claude Sonnet 4.5 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 | +| Claude Sonnet 4 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 | +| Claude Sonnet 4 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 | +| Claude Haiku 4.5 | $1.00 | $5.00 | $0.10 | $1.25 | +| Claude Haiku 3.5 | $0.80 | $4.00 | $0.08 | $1.00 | +| Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | +| Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | +| Gemini 3 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | +| Gemini 3 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | +| Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | +| GPT 5.4 Pro | $30.00 | $180.00 | $30.00 | - | +| GPT 5.4 | $2.50 | $15.00 | $0.25 | - | +| GPT 5.3 Codex Spark | $1.75 | $14.00 | $0.175 | - | +| GPT 5.3 Codex | $1.75 | $14.00 | $0.175 | - | +| GPT 5.2 | $1.75 | $14.00 | $0.175 | - | +| GPT 5.2 Codex | $1.75 | $14.00 | $0.175 | - | +| GPT 5.1 | $1.07 | $8.50 | $0.107 | - | +| GPT 5.1 Codex | $1.07 | $8.50 | $0.107 | - | +| GPT 5.1 Codex Max | $1.25 | $10.00 | $0.125 | - | +| GPT 5.1 Codex Mini | $0.25 | $2.00 | $0.025 | - | +| GPT 5 | $1.07 | $8.50 | $0.107 | - | +| GPT 5 Codex | $1.07 | $8.50 | $0.107 | - | +| GPT 5 Nano | Free | Free | Free | - | You might notice _Claude Haiku 3.5_ in your usage history. This is a [low cost model](/docs/config/#models) that's used to generate the titles of your sessions. @@ -168,8 +172,6 @@ Credit card fees are passed along at cost (4.4% + $0.30 per transaction); we don The free models: -- GLM 5 Free is available on OpenCode for a limited time. The team is using this time to collect feedback and improve the model. -- Kimi K2.5 Free is available on OpenCode for a limited time. The team is using this time to collect feedback and improve the model. - MiniMax M2.5 Free is available on OpenCode for a limited time. The team is using this time to collect feedback and improve the model. - Big Pickle is a stealth model that's free on OpenCode for a limited time. The team is using this time to collect feedback and improve the model. @@ -196,13 +198,24 @@ charging you more than $20 if your balance goes below $5. --- +### Deprecated models + +| Model | Deprecation date | +| ---------------- | ---------------- | +| Qwen3 Coder 480B | Feb 6, 2026 | +| Kimi K2 Thinking | March 6, 2026 | +| Kimi K2 | March 6, 2026 | +| MiniMax M2.1 | March 15, 2026 | +| GLM 4.7 | March 15, 2026 | +| GLM 4.6 | March 15, 2026 | + +--- + ## Privacy All our models are hosted in the US. Our providers follow a zero-retention policy and do not use your data for model training, with the following exceptions: - Big Pickle: During its free period, collected data may be used to improve the model. -- GLM 5 Free: During its free period, collected data may be used to improve the model. -- Kimi K2.5 Free: During its free period, collected data may be used to improve the model. - MiniMax M2.5 Free: During its free period, collected data may be used to improve the model. - OpenAI APIs: Requests are retained for 30 days in accordance with [OpenAI's Data Policies](https://platform.openai.com/docs/guides/your-data). - Anthropic APIs: Requests are retained for 30 days in accordance with [Anthropic's Data Policies](https://docs.anthropic.com/en/docs/claude-code/data-usage). diff --git a/packages/web/src/content/docs/zh-cn/cli.mdx b/packages/web/src/content/docs/zh-cn/cli.mdx index 490d59ca0b..503207ec48 100644 --- a/packages/web/src/content/docs/zh-cn/cli.mdx +++ b/packages/web/src/content/docs/zh-cn/cli.mdx @@ -558,6 +558,7 @@ OpenCode 可以通过环境变量进行配置。 | `OPENCODE_AUTO_SHARE` | boolean | 自动分享会话 | | `OPENCODE_GIT_BASH_PATH` | string | Windows 上 Git Bash 可执行文件的路径 | | `OPENCODE_CONFIG` | string | 配置文件路径 | +| `OPENCODE_TUI_CONFIG` | string | TUI 配置文件路径 | | `OPENCODE_CONFIG_DIR` | string | 配置目录路径 | | `OPENCODE_CONFIG_CONTENT` | string | 内联 JSON 配置内容 | | `OPENCODE_DISABLE_AUTOUPDATE` | boolean | 禁用自动更新检查 | diff --git a/packages/web/src/content/docs/zh-cn/config.mdx b/packages/web/src/content/docs/zh-cn/config.mdx index 8ed3c8fbee..c401bcf121 100644 --- a/packages/web/src/content/docs/zh-cn/config.mdx +++ b/packages/web/src/content/docs/zh-cn/config.mdx @@ -14,10 +14,11 @@ OpenCode 支持 **JSON** 和 **JSONC**(带注释的 JSON)格式。 ```jsonc title="opencode.jsonc" { "$schema": "https://opencode.ai/config.json", - // Theme configuration - "theme": "opencode", "model": "anthropic/claude-sonnet-4-5", "autoupdate": true, + "server": { + "port": 4096, + }, } ``` @@ -33,7 +34,7 @@ OpenCode 支持 **JSON** 和 **JSONC**(带注释的 JSON)格式。 配置文件是合并在一起的,而不是被替换。来自以下配置位置的设置会被合并。后面的配置仅在键冲突时覆盖前面的配置。所有配置中的非冲突设置都会被保留。 -例如,如果您的全局配置设置了 `theme: "opencode"` 和 `autoupdate: true`,而您的项目配置设置了 `model: "anthropic/claude-sonnet-4-5"`,则最终配置将包含所有三个设置。 +例如,如果您的全局配置设置了 `autoupdate: true`,而您的项目配置设置了 `model: "anthropic/claude-sonnet-4-5"`,则最终配置将包含这两个设置。 --- diff --git a/packages/web/src/content/docs/zh-cn/custom-tools.mdx b/packages/web/src/content/docs/zh-cn/custom-tools.mdx index 81a90a2bcb..8b44a0450c 100644 --- a/packages/web/src/content/docs/zh-cn/custom-tools.mdx +++ b/packages/web/src/content/docs/zh-cn/custom-tools.mdx @@ -79,6 +79,32 @@ export const multiply = tool({ --- +#### 与内置工具的名称冲突 + +自定义工具通过工具名称进行索引。如果自定义工具使用了与内置工具相同的名称,则优先使用自定义工具。 + +例如,这个文件取代了内置的bash工具: + +```ts title=".opencode/tools/bash.ts" +import { tool } from "@opencode-ai/plugin" + +export default tool({ + description: "Restricted bash wrapper", + args: { + command: tool.schema.string(), + }, + async execute(args) { + return `blocked: ${args.command}` + }, +}) +``` + +:::note +除非你有意替换内置工具,否则最好用独特的名字。如果你想禁用内置工具但不想覆盖它,使用 [权限](/docs/permissions). +::: + +--- + ### 参数 你可以使用 `tool.schema`(即 [Zod](https://zod.dev))来定义参数类型。 diff --git a/packages/web/src/content/docs/zh-cn/ecosystem.mdx b/packages/web/src/content/docs/zh-cn/ecosystem.mdx index c77cc0542b..d222903d34 100644 --- a/packages/web/src/content/docs/zh-cn/ecosystem.mdx +++ b/packages/web/src/content/docs/zh-cn/ecosystem.mdx @@ -15,38 +15,40 @@ description: 基于 OpenCode 构建的项目与集成。 ## 插件 -| 名称 | 描述 | -| --------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- | -| [opencode-daytona](https://github.com/jamesmurdza/daytona/blob/main/guides/typescript/opencode/README.md) | 在隔离的 Daytona 沙箱中自动运行 OpenCode 会话,支持 git 同步和实时预览 | -| [opencode-helicone-session](https://github.com/H2Shami/opencode-helicone-session) | 自动注入 Helicone 会话头信息,用于请求分组 | -| [opencode-type-inject](https://github.com/nick-vi/opencode-type-inject) | 通过查找工具自动将 TypeScript/Svelte 类型注入到文件读取中 | -| [opencode-openai-codex-auth](https://github.com/numman-ali/opencode-openai-codex-auth) | 使用您的 ChatGPT Plus/Pro 订阅替代 API 额度 | -| [opencode-gemini-auth](https://github.com/jenslys/opencode-gemini-auth) | 使用您现有的 Gemini 套餐替代 API 计费 | -| [opencode-antigravity-auth](https://github.com/NoeFabris/opencode-antigravity-auth) | 使用 Antigravity 的免费模型替代 API 计费 | -| [opencode-devcontainers](https://github.com/athal7/opencode-devcontainers) | 多分支开发容器隔离,支持浅克隆和自动分配端口 | -| [opencode-google-antigravity-auth](https://github.com/shekohex/opencode-google-antigravity-auth) | Google Antigravity OAuth 插件,支持 Google 搜索及更强健的 API 处理 | -| [opencode-dynamic-context-pruning](https://github.com/Tarquinen/opencode-dynamic-context-pruning) | 通过修剪过时的工具输出来优化 Token 使用 | -| [opencode-websearch-cited](https://github.com/ghoulr/opencode-websearch-cited.git) | 为受支持的提供商添加原生网页搜索支持,采用 Google grounded 风格 | -| [opencode-pty](https://github.com/shekohex/opencode-pty.git) | 使 AI 代理能够在 PTY 中运行后台进程,并向其发送交互式输入 | -| [opencode-shell-strategy](https://github.com/JRedeker/opencode-shell-strategy) | 非交互式 shell 命令指令——防止依赖 TTY 的操作导致挂起 | -| [opencode-wakatime](https://github.com/angristan/opencode-wakatime) | 使用 Wakatime 追踪 OpenCode 的使用情况 | -| [opencode-md-table-formatter](https://github.com/franlol/opencode-md-table-formatter/tree/main) | 清理 LLM 生成的 Markdown 表格 | -| [opencode-morph-fast-apply](https://github.com/JRedeker/opencode-morph-fast-apply) | 通过 Morph Fast Apply API 和惰性编辑标记实现 10 倍更快的代码编辑 | -| [oh-my-opencode](https://github.com/code-yeongyu/oh-my-opencode) | 后台代理、预构建的 LSP/AST/MCP 工具、精选代理,兼容 Claude Code | -| [opencode-notificator](https://github.com/panta82/opencode-notificator) | OpenCode 会话的桌面通知和声音提醒 | -| [opencode-notifier](https://github.com/mohak34/opencode-notifier) | 针对权限请求、任务完成和错误事件的桌面通知与声音提醒 | -| [opencode-zellij-namer](https://github.com/24601/opencode-zellij-namer) | 基于 OpenCode 上下文的 AI 驱动自动 Zellij 会话命名 | -| [opencode-skillful](https://github.com/zenobi-us/opencode-skillful) | 允许 OpenCode 代理通过技能发现和注入按需延迟加载提示词 | -| [opencode-supermemory](https://github.com/supermemoryai/opencode-supermemory) | 使用 Supermemory 实现跨会话的持久记忆 | -| [@plannotator/opencode](https://github.com/backnotprop/plannotator/tree/main/apps/opencode-plugin) | 支持可视化标注和私有/离线分享的交互式计划审查 | -| [@openspoon/subtask2](https://github.com/spoons-and-mirrors/subtask2) | 将 OpenCode /commands 扩展为具有精细流程控制的强大编排系统 | -| [opencode-scheduler](https://github.com/different-ai/opencode-scheduler) | 使用 cron 语法通过 launchd (Mac) 或 systemd (Linux) 调度周期性任务 | -| [micode](https://github.com/vtemian/micode) | 结构化的头脑风暴 → 计划 → 实现工作流,支持会话连续性 | -| [octto](https://github.com/vtemian/octto) | 用于 AI 头脑风暴的交互式浏览器 UI,支持多问题表单 | -| [opencode-background-agents](https://github.com/kdcokenny/opencode-background-agents) | Claude Code 风格的后台代理,支持异步委托和上下文持久化 | -| [opencode-notify](https://github.com/kdcokenny/opencode-notify) | OpenCode 的原生操作系统通知——随时了解任务完成情况 | -| [opencode-workspace](https://github.com/kdcokenny/opencode-workspace) | 捆绑式多代理编排套件——16 个组件,一次安装 | -| [opencode-worktree](https://github.com/kdcokenny/opencode-worktree) | OpenCode 的零摩擦 git worktree 管理 | +| 名称 | 描述 | +| -------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- | +| [opencode-daytona](https://github.com/daytonaio/daytona/tree/main/libs/opencode-plugin) | 在隔离的 Daytona 沙箱中自动运行 OpenCode 会话,支持 git 同步和实时预览 | +| [opencode-helicone-session](https://github.com/H2Shami/opencode-helicone-session) | 自动注入 Helicone 会话头信息,用于请求分组 | +| [opencode-type-inject](https://github.com/nick-vi/opencode-type-inject) | 通过查找工具自动将 TypeScript/Svelte 类型注入到文件读取中 | +| [opencode-openai-codex-auth](https://github.com/numman-ali/opencode-openai-codex-auth) | 使用您的 ChatGPT Plus/Pro 订阅替代 API 额度 | +| [opencode-gemini-auth](https://github.com/jenslys/opencode-gemini-auth) | 使用您现有的 Gemini 套餐替代 API 计费 | +| [opencode-antigravity-auth](https://github.com/NoeFabris/opencode-antigravity-auth) | 使用 Antigravity 的免费模型替代 API 计费 | +| [opencode-devcontainers](https://github.com/athal7/opencode-devcontainers) | 多分支开发容器隔离,支持浅克隆和自动分配端口 | +| [opencode-google-antigravity-auth](https://github.com/shekohex/opencode-google-antigravity-auth) | Google Antigravity OAuth 插件,支持 Google 搜索及更强健的 API 处理 | +| [opencode-dynamic-context-pruning](https://github.com/Tarquinen/opencode-dynamic-context-pruning) | 通过修剪过时的工具输出来优化 Token 使用 | +| [opencode-vibeguard](https://github.com/inkdust2021/opencode-vibeguard) | 在调用 LLM 之前将机密/PII 替换为 VibeGuard 风格的占位符;并在本地恢复 | +| [opencode-websearch-cited](https://github.com/ghoulr/opencode-websearch-cited.git) | 为受支持的提供商添加原生网页搜索支持,采用 Google grounded 风格 | +| [opencode-pty](https://github.com/shekohex/opencode-pty.git) | 使 AI 代理能够在 PTY 中运行后台进程,并向其发送交互式输入 | +| [opencode-shell-strategy](https://github.com/JRedeker/opencode-shell-strategy) | 非交互式 shell 命令指令——防止依赖 TTY 的操作导致挂起 | +| [opencode-wakatime](https://github.com/angristan/opencode-wakatime) | 使用 Wakatime 追踪 OpenCode 的使用情况 | +| [opencode-md-table-formatter](https://github.com/franlol/opencode-md-table-formatter/tree/main) | 清理 LLM 生成的 Markdown 表格 | +| [opencode-morph-fast-apply](https://github.com/JRedeker/opencode-morph-fast-apply) | 通过 Morph Fast Apply API 和惰性编辑标记实现 10 倍更快的代码编辑 | +| [oh-my-opencode](https://github.com/code-yeongyu/oh-my-opencode) | 后台代理、预构建的 LSP/AST/MCP 工具、精选代理,兼容 Claude Code | +| [opencode-notificator](https://github.com/panta82/opencode-notificator) | OpenCode 会话的桌面通知和声音提醒 | +| [opencode-notifier](https://github.com/mohak34/opencode-notifier) | 针对权限请求、任务完成和错误事件的桌面通知与声音提醒 | +| [opencode-zellij-namer](https://github.com/24601/opencode-zellij-namer) | 基于 OpenCode 上下文的 AI 驱动自动 Zellij 会话命名 | +| [opencode-skillful](https://github.com/zenobi-us/opencode-skillful) | 允许 OpenCode 代理通过技能发现和注入按需延迟加载提示词 | +| [opencode-supermemory](https://github.com/supermemoryai/opencode-supermemory) | 使用 Supermemory 实现跨会话的持久记忆 | +| [@plannotator/opencode](https://github.com/backnotprop/plannotator/tree/main/apps/opencode-plugin) | 支持可视化标注和私有/离线分享的交互式计划审查 | +| [@openspoon/subtask2](https://github.com/spoons-and-mirrors/subtask2) | 将 OpenCode /commands 扩展为具有精细流程控制的强大编排系统 | +| [opencode-scheduler](https://github.com/different-ai/opencode-scheduler) | 使用 cron 语法通过 launchd (Mac) 或 systemd (Linux) 调度周期性任务 | +| [micode](https://github.com/vtemian/micode) | 结构化的头脑风暴 → 计划 → 实现工作流,支持会话连续性 | +| [octto](https://github.com/vtemian/octto) | 用于 AI 头脑风暴的交互式浏览器 UI,支持多问题表单 | +| [opencode-background-agents](https://github.com/kdcokenny/opencode-background-agents) | Claude Code 风格的后台代理,支持异步委托和上下文持久化 | +| [opencode-notify](https://github.com/kdcokenny/opencode-notify) | OpenCode 的原生操作系统通知——随时了解任务完成情况 | +| [opencode-workspace](https://github.com/kdcokenny/opencode-workspace) | 捆绑式多代理编排套件——16 个组件,一次安装 | +| [opencode-worktree](https://github.com/kdcokenny/opencode-worktree) | OpenCode 的零摩擦 git worktree 管理 | +| [opencode-sentry-monitor](https://github.com/stolinski/opencode-sentry-monitor) | 使用 Sentry AI Monitoring 追踪和调试您的 AI 代理 | --- diff --git a/packages/web/src/content/docs/zh-cn/go.mdx b/packages/web/src/content/docs/zh-cn/go.mdx new file mode 100644 index 0000000000..8bd32a8ad4 --- /dev/null +++ b/packages/web/src/content/docs/zh-cn/go.mdx @@ -0,0 +1,145 @@ +--- +title: Go +description: 低成本的开源编程模型订阅服务。 +--- + +import config from "../../../../config.mjs" +export const console = config.console +export const email = `mailto:${config.email}` + +OpenCode Go 是一项低成本的订阅服务(**$10/月**),为您提供对流行开源编程模型的可靠访问。 + +:::note +OpenCode Go 目前处于测试阶段。 +::: + +Go 的工作方式与 OpenCode 中的其他提供商一样。您订阅 OpenCode Go 并获取 API 密钥。这是**完全可选的**,您不需要它也能使用 OpenCode。 + +它主要为国际用户设计,模型托管在美国、欧盟和新加坡,以确保稳定的全球访问。 + +--- + +## 背景 + +开源模型已经变得非常出色。它们现在在编程任务上的表现接近专有模型。而且因为许多提供商可以竞争性地提供服务,它们通常要便宜得多。 + +然而,获得可靠、低延迟的访问可能很困难。提供商的质量和可用性各不相同。 + +:::tip +我们测试了一组精选的模型和提供商,它们与 OpenCode 配合良好。 +::: + +为了解决这个问题,我们做了一些事情: + +1. 我们测试了一组精选的开源模型,并与他们的团队讨论了如何最好地运行它们。 +2. 然后,我们与几家提供商合作,确保这些模型得到正确的服务。 +3. 最后,我们对模型/提供商的组合进行了基准测试,并得出了一个我们乐于推荐的列表。 + +OpenCode Go 让您可以以 **$10/月** 的价格访问这些模型。 + +--- + +## 工作原理 + +OpenCode Go 的工作方式与 OpenCode 中的其他提供商一样。 + +1. 登录 **<a href={console}>OpenCode Zen</a>**,订阅 Go,并复制您的 API 密钥。 +2. 在 TUI 中运行 `/connect` 命令,选择 `OpenCode Go`,然后粘贴您的 API 密钥。 +3. 在 TUI 中运行 `/models` 以查看通过 Go 可用的模型列表。 + +:::note +每个工作区只有一名成员可以订阅 OpenCode Go。 +::: + +目前的模型列表包括: + +- **GLM-5** +- **Kimi K2.5** +- **MiniMax M2.5** + +随着我们测试和添加新模型,模型列表可能会发生变化。 + +--- + +## 使用限制 + +OpenCode Go 包含以下限制: + +- **5 小时限制** — $12 的使用量 +- **每周限制** — $30 的使用量 +- **每月限制** — $60 的使用量 + +限制是以美元价值定义的。这意味着您的实际请求数量取决于您使用的模型。像 MiniMax M2.5 这样更便宜的模型允许更多的请求,而像 GLM-5 这样成本更高的模型允许的请求较少。 + +下表提供了基于典型 Go 使用模式的估计请求数: + +| | GLM-5 | Kimi K2.5 | MiniMax M2.5 | +| --------------- | ----- | --------- | ------------ | +| 每 5 小时请求数 | 1,150 | 1,850 | 30,000 | +| 每周请求数 | 2,880 | 4,630 | 75,000 | +| 每月请求数 | 5,750 | 9,250 | 150,000 | + +估计值基于观察到的平均请求模式: + +- GLM-5 — 每次请求 700 输入,52,000 缓存,150 输出 token +- Kimi K2.5 — 每次请求 870 输入,55,000 缓存,200 输出 token +- MiniMax M2.5 — 每次请求 300 输入,55,000 缓存,125 输出 token + +您可以在 **<a href={console}>console</a>** 中跟踪当前的用量。 + +:::tip +如果您达到使用限制,您可以继续使用免费模型。 +::: + +随着我们从早期使用和反馈中学习,使用限制可能会发生变化。 + +--- + +### 定价 + +OpenCode Go 是一个 **$10/月** 的订阅计划。以下是**每 1M token** 的价格。 + +| Model | Input | Output | Cached Read | +| ------------ | ----- | ------ | ----------- | +| GLM-5 | $1.00 | $3.20 | $0.20 | +| Kimi K2.5 | $0.60 | $3.00 | $0.10 | +| MiniMax M2.5 | $0.30 | $1.20 | $0.03 | + +--- + +### 超出限制的使用 + +如果您的 Zen 余额中还有信用点数,您可以在控制台中启用 **Use balance**(使用余额)选项。启用后,当您达到使用限制时,Go 将回退到您的 Zen 余额,而不是阻止请求。 + +--- + +## 端点 + +您也可以通过以下 API 端点访问 Go 模型。 + +| Model | Model ID | Endpoint | AI SDK Package | +| ------------ | ------------ | ------------------------------------------------ | --------------------------- | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | + +OpenCode 配置中的 [model id](/docs/config/#models) 使用 `opencode-go/<model-id>` 格式。例如,对于 Kimi K2.5,您将在配置中使用 `opencode-go/kimi-k2.5`。 + +--- + +## 隐私 + +该计划主要为国际用户设计,模型托管在美国、欧盟和新加坡,以确保稳定的全球访问。 + +如有任何问题,请 <a href={email}>联系我们</a>。 + +--- + +## 目标 + +我们要创建 OpenCode Go 以: + +1. 通过低成本订阅让更多人**获得** AI 编程能力。 +2. 提供对最佳开源编程模型的**可靠**访问。 +3. 策划经过**测试和基准测试**的、适合编程代理使用的模型。 +4. **无锁定**,允许您在 OpenCode 中使用任何其他提供商。 diff --git a/packages/web/src/content/docs/zh-cn/keybinds.mdx b/packages/web/src/content/docs/zh-cn/keybinds.mdx index bb1d2c21a7..33f75c6dc8 100644 --- a/packages/web/src/content/docs/zh-cn/keybinds.mdx +++ b/packages/web/src/content/docs/zh-cn/keybinds.mdx @@ -3,11 +3,11 @@ title: 快捷键 description: 自定义您的快捷键。 --- -OpenCode 提供了一系列快捷键,您可以通过 OpenCode 配置进行自定义。 +OpenCode 提供了一系列快捷键,您可以通过 `tui.json` 进行自定义。 -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "keybinds": { "leader": "ctrl+x", "app_exit": "ctrl+c,ctrl+d,<leader>q", @@ -28,6 +28,7 @@ OpenCode 提供了一系列快捷键,您可以通过 OpenCode 配置进行自 "session_unshare": "none", "session_interrupt": "escape", "session_compact": "<leader>c", + "session_child_first": "<leader>down", "session_child_cycle": "<leader>right", "session_child_cycle_reverse": "<leader>left", "session_parent": "<leader>up", @@ -117,11 +118,11 @@ OpenCode 的大多数快捷键使用 `leader`(前导键)。这可以避免 ## 禁用快捷键 -您可以通过在配置中将对应的键值设置为 "none" 来禁用某个快捷键。 +您可以通过将键值添加到 `tui.json` 并设置为 "none" 来禁用某个快捷键。 -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "keybinds": { "session_compact": "none" } diff --git a/packages/web/src/content/docs/zh-cn/lsp.mdx b/packages/web/src/content/docs/zh-cn/lsp.mdx index 57b8121902..59dd7082a1 100644 --- a/packages/web/src/content/docs/zh-cn/lsp.mdx +++ b/packages/web/src/content/docs/zh-cn/lsp.mdx @@ -27,6 +27,7 @@ OpenCode 内置了多种适用于主流语言的 LSP 服务器: | gopls | .go | 需要 `go` 命令可用 | | hls | .hs, .lhs | 需要 `haskell-language-server-wrapper` 命令可用 | | jdtls | .java | 需要已安装 `Java SDK (version 21+)` | +| julials | .jl | 需要安装 `julia` and `LanguageServer.jl` | | kotlin-ls | .kt, .kts | 为 Kotlin 项目自动安装 | | lua-ls | .lua | 为 Lua 项目自动安装 | | nixd | .nix | 需要 `nixd` 命令可用 | diff --git a/packages/web/src/content/docs/zh-cn/plugins.mdx b/packages/web/src/content/docs/zh-cn/plugins.mdx index 0df6d1ee65..e8a8bd70cb 100644 --- a/packages/web/src/content/docs/zh-cn/plugins.mdx +++ b/packages/web/src/content/docs/zh-cn/plugins.mdx @@ -307,6 +307,10 @@ export const CustomToolsPlugin: Plugin = async (ctx) => { 你的自定义工具将与内置工具一起在 OpenCode 中可用。 +:::note +如果插件工具与内置工具使用相同的名称,则优先使用插件工具。 +::: + --- ### 日志记录 diff --git a/packages/web/src/content/docs/zh-cn/providers.mdx b/packages/web/src/content/docs/zh-cn/providers.mdx index ccc2bf7d40..9c1616876d 100644 --- a/packages/web/src/content/docs/zh-cn/providers.mdx +++ b/packages/web/src/content/docs/zh-cn/providers.mdx @@ -131,6 +131,8 @@ OpenCode Zen 是由 OpenCode 团队提供的模型列表,这些模型已经过 2. 使用以下方法之一**配置身份验证**: + *** + #### 环境变量(快速上手) 运行 opencode 时设置以下环境变量之一: @@ -153,6 +155,8 @@ OpenCode Zen 是由 OpenCode 团队提供的模型列表,这些模型已经过 export AWS_REGION=us-east-1 ``` + *** + #### 配置文件(推荐) 如需项目级别或持久化的配置,请使用 `opencode.json`: @@ -180,6 +184,8 @@ OpenCode Zen 是由 OpenCode 团队提供的模型列表,这些模型已经过 配置文件中的选项优先级高于环境变量。 ::: + *** + #### 进阶:VPC 端点 如果你使用 Bedrock 的 VPC 端点: @@ -203,12 +209,16 @@ OpenCode Zen 是由 OpenCode 团队提供的模型列表,这些模型已经过 `endpoint` 选项是通用 `baseURL` 选项的别名,使用了 AWS 特有的术语。如果同时指定了 `endpoint` 和 `baseURL`,则 `endpoint` 优先。 ::: + *** + #### 认证方式 - **`AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY`**:在 AWS 控制台中创建 IAM 用户并生成访问密钥 - **`AWS_PROFILE`**:使用 `~/.aws/credentials` 中的命名配置文件。需要先通过 `aws configure --profile my-profile` 或 `aws sso login` 进行配置 - **`AWS_BEARER_TOKEN_BEDROCK`**:从 Amazon Bedrock 控制台生成长期 API 密钥 - **`AWS_WEB_IDENTITY_TOKEN_FILE` / `AWS_ROLE_ARN`**:适用于 EKS IRSA(服务账户的 IAM 角色)或其他支持 OIDC 联合的 Kubernetes 环境。使用服务账户注解时,Kubernetes 会自动注入这些环境变量。 + *** + #### 认证优先级 Amazon Bedrock 使用以下认证优先级: diff --git a/packages/web/src/content/docs/zh-cn/share.mdx b/packages/web/src/content/docs/zh-cn/share.mdx index 8a7be16dc9..a2b34688e4 100644 --- a/packages/web/src/content/docs/zh-cn/share.mdx +++ b/packages/web/src/content/docs/zh-cn/share.mdx @@ -41,7 +41,7 @@ OpenCode 支持三种分享模式,用于控制对话的共享方式: ```json title="opencode.json" { - "$schema": "https://opncd.ai/config.json", + "$schema": "https://opencode.ai/config.json", "share": "manual" } ``` @@ -54,7 +54,7 @@ OpenCode 支持三种分享模式,用于控制对话的共享方式: ```json title="opencode.json" { - "$schema": "https://opncd.ai/config.json", + "$schema": "https://opencode.ai/config.json", "share": "auto" } ``` @@ -69,7 +69,7 @@ OpenCode 支持三种分享模式,用于控制对话的共享方式: ```json title="opencode.json" { - "$schema": "https://opncd.ai/config.json", + "$schema": "https://opencode.ai/config.json", "share": "disabled" } ``` diff --git a/packages/web/src/content/docs/zh-cn/themes.mdx b/packages/web/src/content/docs/zh-cn/themes.mdx index d1abefed6d..79386fbe99 100644 --- a/packages/web/src/content/docs/zh-cn/themes.mdx +++ b/packages/web/src/content/docs/zh-cn/themes.mdx @@ -61,11 +61,11 @@ OpenCode 自带多个内置主题。 ## 使用主题 -您可以通过 `/theme` 命令调出主题选择界面来选择主题,也可以在[配置](/docs/config)文件中直接指定。 +您可以通过 `/theme` 命令调出主题选择界面来选择主题,也可以在 `tui.json` 文件中直接指定。 -```json title="opencode.json" {3} +```json title="tui.json" {3} { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "theme": "tokyonight" } ``` diff --git a/packages/web/src/content/docs/zh-cn/tui.mdx b/packages/web/src/content/docs/zh-cn/tui.mdx index e34c088cb3..df8ce38fec 100644 --- a/packages/web/src/content/docs/zh-cn/tui.mdx +++ b/packages/web/src/content/docs/zh-cn/tui.mdx @@ -234,7 +234,7 @@ How is auth handled in @packages/functions/src/api/index.ts? 列出可用主题。 ```bash frame="none" -/theme +/themes ``` **快捷键:** `ctrl+x t` diff --git a/packages/web/src/content/docs/zh-cn/zen.mdx b/packages/web/src/content/docs/zh-cn/zen.mdx index 39358c4170..098fb5e35b 100644 --- a/packages/web/src/content/docs/zh-cn/zen.mdx +++ b/packages/web/src/content/docs/zh-cn/zen.mdx @@ -55,6 +55,8 @@ OpenCode Zen 的工作方式与 OpenCode 中的任何其他提供商相同。 | 模型 | 模型 ID | 端点 | AI SDK 包 | | ------------------ | ------------------ | -------------------------------------------------- | --------------------------- | +| GPT 5.4 | gpt-5.4 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| GPT 5.3 Codex | gpt-5.3-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.2 | gpt-5.2 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.2 Codex | gpt-5.2-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.1 | gpt-5.1 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | @@ -64,13 +66,15 @@ OpenCode Zen 的工作方式与 OpenCode 中的任何其他提供商相同。 | GPT 5 | gpt-5 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5 Codex | gpt-5-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5 Nano | gpt-5-nano | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| Claude Opus 4.6 | claude-opus-4-6 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Opus 4.5 | claude-opus-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Opus 4.1 | claude-opus-4-1 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Sonnet 4.6 | claude-sonnet-4-6 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Sonnet 4.5 | claude-sonnet-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Sonnet 4 | claude-sonnet-4 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Haiku 4.5 | claude-haiku-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Haiku 3.5 | claude-3-5-haiku | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| Claude Opus 4.6 | claude-opus-4-6 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| Claude Opus 4.5 | claude-opus-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| Claude Opus 4.1 | claude-opus-4-1 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Gemini 3.1 Pro | gemini-3.1-pro | `https://opencode.ai/zen/v1/models/gemini-3.1-pro` | `@ai-sdk/google` | | Gemini 3 Pro | gemini-3-pro | `https://opencode.ai/zen/v1/models/gemini-3-pro` | `@ai-sdk/google` | | Gemini 3 Flash | gemini-3-flash | `https://opencode.ai/zen/v1/models/gemini-3-flash` | `@ai-sdk/google` | | MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -80,7 +84,6 @@ OpenCode Zen 的工作方式与 OpenCode 中的任何其他提供商相同。 | GLM 4.7 | glm-4.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | GLM 4.6 | glm-4.6 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 Free | kimi-k2.5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2 Thinking | kimi-k2-thinking | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2 | kimi-k2 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Qwen3 Coder 480B | qwen3-coder | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -104,42 +107,47 @@ https://opencode.ai/zen/v1/models 我们支持按量付费模式。以下是**每 100 万 Token** 的价格。 -| 模型 | 输入 | 输出 | 缓存读取 | 缓存写入 | -| -------------------------------- | ------ | ------ | -------- | -------- | -| Big Pickle | 免费 | 免费 | 免费 | - | -| MiniMax M2.5 Free | 免费 | 免费 | 免费 | - | -| MiniMax M2.5 | $0.30 | $1.20 | $0.06 | - | -| MiniMax M2.1 | $0.30 | $1.20 | $0.10 | - | -| GLM 5 | $1.00 | $3.20 | $0.20 | - | -| GLM 4.7 | $0.60 | $2.20 | $0.10 | - | -| GLM 4.6 | $0.60 | $2.20 | $0.10 | - | -| Kimi K2.5 Free | 免费 | 免费 | 免费 | - | -| Kimi K2.5 | $0.60 | $3.00 | $0.08 | - | -| Kimi K2 Thinking | $0.40 | $2.50 | - | - | -| Kimi K2 | $0.40 | $2.50 | - | - | -| Qwen3 Coder 480B | $0.45 | $1.50 | - | - | -| Claude Sonnet 4.5 (≤ 200K Token) | $3.00 | $15.00 | $0.30 | $3.75 | -| Claude Sonnet 4.5 (> 200K Token) | $6.00 | $22.50 | $0.60 | $7.50 | -| Claude Sonnet 4 (≤ 200K Token) | $3.00 | $15.00 | $0.30 | $3.75 | -| Claude Sonnet 4 (> 200K Token) | $6.00 | $22.50 | $0.60 | $7.50 | -| Claude Haiku 4.5 | $1.00 | $5.00 | $0.10 | $1.25 | -| Claude Haiku 3.5 | $0.80 | $4.00 | $0.08 | $1.00 | -| Claude Opus 4.6 (≤ 200K Token) | $5.00 | $25.00 | $0.50 | $6.25 | -| Claude Opus 4.6 (> 200K Token) | $10.00 | $37.50 | $1.00 | $12.50 | -| Claude Opus 4.5 | $5.00 | $25.00 | $0.50 | $6.25 | -| Claude Opus 4.1 | $15.00 | $75.00 | $1.50 | $18.75 | -| Gemini 3 Pro (≤ 200K Token) | $2.00 | $12.00 | $0.20 | - | -| Gemini 3 Pro (> 200K Token) | $4.00 | $18.00 | $0.40 | - | -| Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | -| GPT 5.2 | $1.75 | $14.00 | $0.175 | - | -| GPT 5.2 Codex | $1.75 | $14.00 | $0.175 | - | -| GPT 5.1 | $1.07 | $8.50 | $0.107 | - | -| GPT 5.1 Codex | $1.07 | $8.50 | $0.107 | - | -| GPT 5.1 Codex Max | $1.25 | $10.00 | $0.125 | - | -| GPT 5.1 Codex Mini | $0.25 | $2.00 | $0.025 | - | -| GPT 5 | $1.07 | $8.50 | $0.107 | - | -| GPT 5 Codex | $1.07 | $8.50 | $0.107 | - | -| GPT 5 Nano | 免费 | 免费 | 免费 | - | +| 模型 | 输入 | 输出 | 缓存读取 | 缓存写入 | +| --------------------------------- | ------ | ------ | -------- | -------- | +| Big Pickle | 免费 | 免费 | 免费 | - | +| MiniMax M2.5 Free | 免费 | 免费 | 免费 | - | +| MiniMax M2.5 | $0.30 | $1.20 | $0.06 | - | +| MiniMax M2.1 | $0.30 | $1.20 | $0.10 | - | +| GLM 5 | $1.00 | $3.20 | $0.20 | - | +| GLM 4.7 | $0.60 | $2.20 | $0.10 | - | +| GLM 4.6 | $0.60 | $2.20 | $0.10 | - | +| Kimi K2.5 | $0.60 | $3.00 | $0.08 | - | +| Kimi K2 Thinking | $0.40 | $2.50 | - | - | +| Kimi K2 | $0.40 | $2.50 | - | - | +| Qwen3 Coder 480B | $0.45 | $1.50 | - | - | +| Claude Opus 4.6 (≤ 200K tokens) | $5.00 | $25.00 | $0.50 | $6.25 | +| Claude Opus 4.6 (> 200K tokens) | $10.00 | $37.50 | $1.00 | $12.50 | +| Claude Opus 4.5 | $5.00 | $25.00 | $0.50 | $6.25 | +| Claude Opus 4.1 | $15.00 | $75.00 | $1.50 | $18.75 | +| Claude Sonnet 4.6 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 | +| Claude Sonnet 4.6 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 | +| Claude Sonnet 4.5 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 | +| Claude Sonnet 4.5 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 | +| Claude Sonnet 4 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 | +| Claude Sonnet 4 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 | +| Claude Haiku 4.5 | $1.00 | $5.00 | $0.10 | $1.25 | +| Claude Haiku 3.5 | $0.80 | $4.00 | $0.08 | $1.00 | +| Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | +| Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | +| Gemini 3 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | +| Gemini 3 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - | +| Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | +| GPT 5.4 | $2.50 | $15.00 | $0.25 | - | +| GPT 5.3 Codex | $1.75 | $14.00 | $0.175 | - | +| GPT 5.2 | $1.75 | $14.00 | $0.175 | - | +| GPT 5.2 Codex | $1.75 | $14.00 | $0.175 | - | +| GPT 5.1 | $1.07 | $8.50 | $0.107 | - | +| GPT 5.1 Codex | $1.07 | $8.50 | $0.107 | - | +| GPT 5.1 Codex Max | $1.25 | $10.00 | $0.125 | - | +| GPT 5.1 Codex Mini | $0.25 | $2.00 | $0.025 | - | +| GPT 5 | $1.07 | $8.50 | $0.107 | - | +| GPT 5 Codex | $1.07 | $8.50 | $0.107 | - | +| GPT 5 Nano | 免费 | 免费 | 免费 | - | 你可能会在使用记录中看到 _Claude Haiku 3.5_。这是一个[低成本模型](/docs/config/#models),用于生成会话标题。 @@ -149,7 +157,6 @@ https://opencode.ai/zen/v1/models 免费模型说明: -- Kimi K2.5 Free 在 OpenCode 上限时免费提供。团队正在利用这段时间收集反馈并改进模型。 - MiniMax M2.5 Free 在 OpenCode 上限时免费提供。团队正在利用这段时间收集反馈并改进模型。 - Big Pickle 是一个隐身模型,在 OpenCode 上限时免费提供。团队正在利用这段时间收集反馈并改进模型。 @@ -173,12 +180,24 @@ https://opencode.ai/zen/v1/models --- +### 已弃用模型 + +| 模型 | 弃用日期 | +| ---------------- | ------------------ | +| Qwen3 Coder 480B | 2026 年 2 月 6 日 | +| Kimi K2 Thinking | 2026 年 3 月 6 日 | +| Kimi K2 | 2026 年 3 月 6 日 | +| MiniMax M2.1 | 2026 年 3 月 15 日 | +| GLM 4.7 | 2026 年 3 月 15 日 | +| GLM 4.6 | 2026 年 3 月 15 日 | + +--- + ## 隐私 我们所有的模型都托管在美国。我们的提供商遵循零保留政策,不会将你的数据用于模型训练,但以下情况除外: - Big Pickle:在免费期间,收集的数据可能会被用于改进模型。 -- Kimi K2.5 Free:在免费期间,收集的数据可能会被用于改进模型。 - MiniMax M2.5 Free:在免费期间,收集的数据可能会被用于改进模型。 - OpenAI API:请求会根据 [OpenAI 数据政策](https://platform.openai.com/docs/guides/your-data)保留 30 天。 - Anthropic API:请求会根据 [Anthropic 数据政策](https://docs.anthropic.com/en/docs/claude-code/data-usage)保留 30 天。 diff --git a/packages/web/src/content/docs/zh-tw/cli.mdx b/packages/web/src/content/docs/zh-tw/cli.mdx index f11066dcf5..888740f5be 100644 --- a/packages/web/src/content/docs/zh-tw/cli.mdx +++ b/packages/web/src/content/docs/zh-tw/cli.mdx @@ -558,6 +558,7 @@ OpenCode 可以透過環境變數進行設定。 | `OPENCODE_AUTO_SHARE` | boolean | 自動分享工作階段 | | `OPENCODE_GIT_BASH_PATH` | string | Windows 上 Git Bash 可執行檔的路徑 | | `OPENCODE_CONFIG` | string | 設定檔路徑 | +| `OPENCODE_TUI_CONFIG` | string | TUI 設定檔路徑 | | `OPENCODE_CONFIG_DIR` | string | 設定目錄路徑 | | `OPENCODE_CONFIG_CONTENT` | string | 內嵌 JSON 設定內容 | | `OPENCODE_DISABLE_AUTOUPDATE` | boolean | 停用自動更新檢查 | diff --git a/packages/web/src/content/docs/zh-tw/config.mdx b/packages/web/src/content/docs/zh-tw/config.mdx index 3715dd0c9f..a694823a65 100644 --- a/packages/web/src/content/docs/zh-tw/config.mdx +++ b/packages/web/src/content/docs/zh-tw/config.mdx @@ -14,10 +14,11 @@ OpenCode 支援 **JSON** 和 **JSONC**(帶註解的 JSON)格式。 ```jsonc title="opencode.jsonc" { "$schema": "https://opencode.ai/config.json", - // Theme configuration - "theme": "opencode", "model": "anthropic/claude-sonnet-4-5", "autoupdate": true, + "server": { + "port": 4096, + }, } ``` @@ -33,7 +34,7 @@ OpenCode 支援 **JSON** 和 **JSONC**(帶註解的 JSON)格式。 設定檔是合併在一起的,而不是被替換。來自以下設定位置的設定會被合併。後面的設定僅在鍵衝突時覆寫前面的設定。所有設定中的非衝突設定都會被保留。 -例如,如果您的全域設定設定了 `theme: "opencode"` 和 `autoupdate: true`,而您的專案設定設定了 `model: "anthropic/claude-sonnet-4-5"`,則最終設定將包含所有三個設定。 +例如,如果您的全域設定設定了 `autoupdate: true`,而您的專案設定設定了 `model: "anthropic/claude-sonnet-4-5"`,則最終設定將包含這兩個設定。 --- @@ -171,6 +172,10 @@ opencode run "Hello world" - `scroll_speed` - 自訂捲動速度倍率(預設值:`3`,最小值:`1`)。如果 `scroll_acceleration.enabled` 為 `true`,則忽略此選項。 - `diff_style` - 控制差異呈現方式。`"auto"` 根據終端機寬度自適應,`"stacked"` 始終顯示單列。 +使用 `OPENCODE_TUI_CONFIG` 指向自訂 TUI 設定檔。 + +`opencode.json` 中的舊版 `theme`、`keybinds` 和 `tui` 鍵已被棄用,並將在可能的情況下自動遷移。 + [在此了解更多關於 TUI 的資訊](/docs/tui)。 --- @@ -297,12 +302,12 @@ Bearer Token(`AWS_BEARER_TOKEN_BEDROCK` 或 `/connect`)優先於基於設定 ### 主題 -您可以透過 OpenCode 設定中的 `theme` 選項設定要使用的主題。 +在 `tui.json` 中設定您的 UI 主題。 -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", - "theme": "" + "$schema": "https://opencode.ai/tui.json", + "theme": "tokyonight" } ``` @@ -402,11 +407,11 @@ Bearer Token(`AWS_BEARER_TOKEN_BEDROCK` 或 `/connect`)優先於基於設定 ### 快捷鍵 -您可以透過 `keybinds` 選項自訂快捷鍵。 +在 `tui.json` 中自訂快捷鍵。 -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "keybinds": {} } ``` diff --git a/packages/web/src/content/docs/zh-tw/custom-tools.mdx b/packages/web/src/content/docs/zh-tw/custom-tools.mdx index 3229c6fddf..86c2b0467f 100644 --- a/packages/web/src/content/docs/zh-tw/custom-tools.mdx +++ b/packages/web/src/content/docs/zh-tw/custom-tools.mdx @@ -79,6 +79,32 @@ export const multiply = tool({ --- +#### 與內建工具名稱衝突 + +自訂工具以工具名稱作為鍵值。如果自訂工具使用與內建工具相同的名稱,則自訂工具具有優先權。 + +例如,此檔案將替換內建的 `bash` 工具: + +```ts title=".opencode/tools/bash.ts" +import { tool } from "@opencode-ai/plugin" + +export default tool({ + description: "Restricted bash wrapper", + args: { + command: tool.schema.string(), + }, + async execute(args) { + return `blocked: ${args.command}` + }, +}) +``` + +:::note +除非您有意替換內建工具,否則請使用唯一的名稱。如果您想停用內建工具但不覆寫它,請使用[權限](/docs/permissions)。 +::: + +--- + ### 參數 您可以使用 `tool.schema`(即 [Zod](https://zod.dev))來定義參數型別。 diff --git a/packages/web/src/content/docs/zh-tw/ecosystem.mdx b/packages/web/src/content/docs/zh-tw/ecosystem.mdx index 3a867d1430..b44dfdacfd 100644 --- a/packages/web/src/content/docs/zh-tw/ecosystem.mdx +++ b/packages/web/src/content/docs/zh-tw/ecosystem.mdx @@ -15,38 +15,40 @@ description: 基於 OpenCode 建置的專案與整合。 ## 外掛程式 -| 名稱 | 說明 | -| --------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- | -| [opencode-daytona](https://github.com/jamesmurdza/daytona/blob/main/guides/typescript/opencode/README.md) | 在隔離的 Daytona 沙箱中自動執行 OpenCode 工作階段,支援 git 同步和即時預覽 | -| [opencode-helicone-session](https://github.com/H2Shami/opencode-helicone-session) | 自動注入 Helicone 工作階段標頭資訊,用於請求分組 | -| [opencode-type-inject](https://github.com/nick-vi/opencode-type-inject) | 透過搜尋工具自動將 TypeScript/Svelte 型別注入到檔案讀取中 | -| [opencode-openai-codex-auth](https://github.com/numman-ali/opencode-openai-codex-auth) | 使用您的 ChatGPT Plus/Pro 訂閱替代 API 額度 | -| [opencode-gemini-auth](https://github.com/jenslys/opencode-gemini-auth) | 使用您現有的 Gemini 方案替代 API 計費 | -| [opencode-antigravity-auth](https://github.com/NoeFabris/opencode-antigravity-auth) | 使用 Antigravity 的免費模型替代 API 計費 | -| [opencode-devcontainers](https://github.com/athal7/opencode-devcontainers) | 多分支開發容器隔離,支援淺層複製和自動分配連接埠 | -| [opencode-google-antigravity-auth](https://github.com/shekohex/opencode-google-antigravity-auth) | Google Antigravity OAuth 外掛程式,支援 Google 搜尋及更強健的 API 處理 | -| [opencode-dynamic-context-pruning](https://github.com/Tarquinen/opencode-dynamic-context-pruning) | 透過修剪過時的工具輸出來最佳化 Token 使用 | -| [opencode-websearch-cited](https://github.com/ghoulr/opencode-websearch-cited.git) | 為受支援的供應商新增原生網頁搜尋支援,採用 Google grounded 風格 | -| [opencode-pty](https://github.com/shekohex/opencode-pty.git) | 使 AI 代理能夠在 PTY 中執行背景處理程序,並向其傳送互動式輸入 | -| [opencode-shell-strategy](https://github.com/JRedeker/opencode-shell-strategy) | 非互動式 shell 指令說明——防止依賴 TTY 的操作導致卡住 | -| [opencode-wakatime](https://github.com/angristan/opencode-wakatime) | 使用 Wakatime 追蹤 OpenCode 的使用情況 | -| [opencode-md-table-formatter](https://github.com/franlol/opencode-md-table-formatter/tree/main) | 清理 LLM 生成的 Markdown 表格 | -| [opencode-morph-fast-apply](https://github.com/JRedeker/opencode-morph-fast-apply) | 透過 Morph Fast Apply API 和惰性編輯標記實現 10 倍更快的程式碼編輯 | -| [oh-my-opencode](https://github.com/code-yeongyu/oh-my-opencode) | 背景代理、預建置的 LSP/AST/MCP 工具、精選代理,相容 Claude Code | -| [opencode-notificator](https://github.com/panta82/opencode-notificator) | OpenCode 工作階段的桌面通知和聲音提醒 | -| [opencode-notifier](https://github.com/mohak34/opencode-notifier) | 針對權限請求、任務完成和錯誤事件的桌面通知與聲音提醒 | -| [opencode-zellij-namer](https://github.com/24601/opencode-zellij-namer) | 基於 OpenCode 上下文的 AI 驅動自動 Zellij 工作階段命名 | -| [opencode-skillful](https://github.com/zenobi-us/opencode-skillful) | 允許 OpenCode 代理透過技能發現和注入按需延遲載入提示詞 | -| [opencode-supermemory](https://github.com/supermemoryai/opencode-supermemory) | 使用 Supermemory 實現跨工作階段的持久記憶 | -| [@plannotator/opencode](https://github.com/backnotprop/plannotator/tree/main/apps/opencode-plugin) | 支援視覺化標註和私有/離線分享的互動式計畫審查 | -| [@openspoon/subtask2](https://github.com/spoons-and-mirrors/subtask2) | 將 OpenCode /commands 擴展為具有精細流程控制的強大編排系統 | -| [opencode-scheduler](https://github.com/different-ai/opencode-scheduler) | 使用 cron 語法透過 launchd (Mac) 或 systemd (Linux) 排程週期性任務 | -| [micode](https://github.com/vtemian/micode) | 結構化的腦力激盪 → 計畫 → 實作工作流程,支援工作階段連續性 | -| [octto](https://github.com/vtemian/octto) | 用於 AI 腦力激盪的互動式瀏覽器 UI,支援多問題表單 | -| [opencode-background-agents](https://github.com/kdcokenny/opencode-background-agents) | Claude Code 風格的背景代理,支援非同步委派和上下文持久化 | -| [opencode-notify](https://github.com/kdcokenny/opencode-notify) | OpenCode 的原生作業系統通知——隨時了解任務完成情況 | -| [opencode-workspace](https://github.com/kdcokenny/opencode-workspace) | 捆綁式多代理編排套件——16 個元件,一次安裝 | -| [opencode-worktree](https://github.com/kdcokenny/opencode-worktree) | OpenCode 的零摩擦 git worktree 管理 | +| 名稱 | 說明 | +| -------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- | +| [opencode-daytona](https://github.com/daytonaio/daytona/tree/main/libs/opencode-plugin) | 在隔離的 Daytona 沙箱中自動執行 OpenCode 工作階段,支援 git 同步和即時預覽 | +| [opencode-helicone-session](https://github.com/H2Shami/opencode-helicone-session) | 自動注入 Helicone 工作階段標頭資訊,用於請求分組 | +| [opencode-type-inject](https://github.com/nick-vi/opencode-type-inject) | 透過搜尋工具自動將 TypeScript/Svelte 型別注入到檔案讀取中 | +| [opencode-openai-codex-auth](https://github.com/numman-ali/opencode-openai-codex-auth) | 使用您的 ChatGPT Plus/Pro 訂閱替代 API 額度 | +| [opencode-gemini-auth](https://github.com/jenslys/opencode-gemini-auth) | 使用您現有的 Gemini 方案替代 API 計費 | +| [opencode-antigravity-auth](https://github.com/NoeFabris/opencode-antigravity-auth) | 使用 Antigravity 的免費模型替代 API 計費 | +| [opencode-devcontainers](https://github.com/athal7/opencode-devcontainers) | 多分支開發容器隔離,支援淺層複製和自動分配連接埠 | +| [opencode-google-antigravity-auth](https://github.com/shekohex/opencode-google-antigravity-auth) | Google Antigravity OAuth 外掛程式,支援 Google 搜尋及更強健的 API 處理 | +| [opencode-dynamic-context-pruning](https://github.com/Tarquinen/opencode-dynamic-context-pruning) | 透過修剪過時的工具輸出來最佳化 Token 使用 | +| [opencode-vibeguard](https://github.com/inkdust2021/opencode-vibeguard) | 在呼叫 LLM 之前將秘密/PII 編輯為 VibeGuard 風格的預留位置;並在本地還原 | +| [opencode-websearch-cited](https://github.com/ghoulr/opencode-websearch-cited.git) | 為受支援的供應商新增原生網頁搜尋支援,採用 Google grounded 風格 | +| [opencode-pty](https://github.com/shekohex/opencode-pty.git) | 使 AI 代理能夠在 PTY 中執行背景處理程序,並向其傳送互動式輸入 | +| [opencode-shell-strategy](https://github.com/JRedeker/opencode-shell-strategy) | 非互動式 shell 指令說明——防止依賴 TTY 的操作導致卡住 | +| [opencode-wakatime](https://github.com/angristan/opencode-wakatime) | 使用 Wakatime 追蹤 OpenCode 的使用情況 | +| [opencode-md-table-formatter](https://github.com/franlol/opencode-md-table-formatter/tree/main) | 清理 LLM 生成的 Markdown 表格 | +| [opencode-morph-fast-apply](https://github.com/JRedeker/opencode-morph-fast-apply) | 透過 Morph Fast Apply API 和惰性編輯標記實現 10 倍更快的程式碼編輯 | +| [oh-my-opencode](https://github.com/code-yeongyu/oh-my-opencode) | 背景代理、預建置的 LSP/AST/MCP 工具、精選代理,相容 Claude Code | +| [opencode-notificator](https://github.com/panta82/opencode-notificator) | OpenCode 工作階段的桌面通知和聲音提醒 | +| [opencode-notifier](https://github.com/mohak34/opencode-notifier) | 針對權限請求、任務完成和錯誤事件的桌面通知與聲音提醒 | +| [opencode-zellij-namer](https://github.com/24601/opencode-zellij-namer) | 基於 OpenCode 上下文的 AI 驅動自動 Zellij 工作階段命名 | +| [opencode-skillful](https://github.com/zenobi-us/opencode-skillful) | 允許 OpenCode 代理透過技能發現和注入按需延遲載入提示詞 | +| [opencode-supermemory](https://github.com/supermemoryai/opencode-supermemory) | 使用 Supermemory 實現跨工作階段的持久記憶 | +| [@plannotator/opencode](https://github.com/backnotprop/plannotator/tree/main/apps/opencode-plugin) | 支援視覺化標註和私有/離線分享的互動式計畫審查 | +| [@openspoon/subtask2](https://github.com/spoons-and-mirrors/subtask2) | 將 OpenCode /commands 擴展為具有精細流程控制的強大編排系統 | +| [opencode-scheduler](https://github.com/different-ai/opencode-scheduler) | 使用 cron 語法透過 launchd (Mac) 或 systemd (Linux) 排程週期性任務 | +| [micode](https://github.com/vtemian/micode) | 結構化的腦力激盪 → 計畫 → 實作工作流程,支援工作階段連續性 | +| [octto](https://github.com/vtemian/octto) | 用於 AI 腦力激盪的互動式瀏覽器 UI,支援多問題表單 | +| [opencode-background-agents](https://github.com/kdcokenny/opencode-background-agents) | Claude Code 風格的背景代理,支援非同步委派和上下文持久化 | +| [opencode-notify](https://github.com/kdcokenny/opencode-notify) | OpenCode 的原生作業系統通知——隨時了解任務完成情況 | +| [opencode-workspace](https://github.com/kdcokenny/opencode-workspace) | 捆綁式多代理編排套件——16 個元件,一次安裝 | +| [opencode-worktree](https://github.com/kdcokenny/opencode-worktree) | OpenCode 的零摩擦 git worktree 管理 | +| [opencode-sentry-monitor](https://github.com/stolinski/opencode-sentry-monitor) | 使用 Sentry AI Monitoring 追蹤與除錯您的 AI 代理 | --- diff --git a/packages/web/src/content/docs/zh-tw/go.mdx b/packages/web/src/content/docs/zh-tw/go.mdx new file mode 100644 index 0000000000..0337a3c385 --- /dev/null +++ b/packages/web/src/content/docs/zh-tw/go.mdx @@ -0,0 +1,145 @@ +--- +title: Go +description: 針對開放原始碼程式設計模型的低成本訂閱服務。 +--- + +import config from "../../../../config.mjs" +export const console = config.console +export const email = `mailto:${config.email}` + +OpenCode Go 是一項低成本的 **每月 10 美元** 訂閱服務,讓您可以穩定存取熱門的開放原始碼程式設計模型。 + +:::note +OpenCode Go 目前處於測試階段 (Beta)。 +::: + +Go 的運作方式就像 OpenCode 中的任何其他供應商一樣。您訂閱 OpenCode Go 並取得您的 API key。這是**完全選用**的,您不需要使用它也能使用 OpenCode。 + +主要是為國際使用者設計,模型託管在美國、歐盟和新加坡,以提供穩定的全球存取。 + +--- + +## 背景 + +開放模型已經變得非常優秀。它們現在在程式設計任務上的表現已接近專有模型。而且因為許多供應商都能以具競爭力的方式提供服務,它們通常便宜得多。 + +然而,要獲得穩定且低延遲的存取可能會很困難。供應商的品質和可用性各不相同。 + +:::tip +我們測試了一組精選的模型和供應商,它們與 OpenCode 搭配運作良好。 +::: + +為了解決這個問題,我們做了幾件事: + +1. 我們測試了一組精選的開放模型,並與他們的團隊討論如何最好地運行它們。 +2. 接著我們與幾家供應商合作,確保這些模型能正確地提供服務。 +3. 最後,我們對模型/供應商的組合進行基準測試,並提出了一份我們覺得值得推薦的清單。 + +OpenCode Go 讓您能以 **每月 10 美元** 的價格存取這些模型。 + +--- + +## 運作方式 + +OpenCode Go 的運作方式就像 OpenCode 中的任何其他供應商一樣。 + +1. 您登入 **<a href={console}>OpenCode Zen</a>**,訂閱 Go,並複製您的 API key。 +2. 您在 TUI 中執行 `/connect` 指令,選擇 `OpenCode Go`,並貼上您的 API key。 +3. 在 TUI 中執行 `/models` 以查看透過 Go 可用的模型清單。 + +:::note +每個工作區只能有一位成員訂閱 OpenCode Go。 +::: + +目前的模型清單包括: + +- **GLM-5** +- **Kimi K2.5** +- **MiniMax M2.5** + +模型清單可能會隨著我們測試和新增模型而變動。 + +--- + +## 使用限制 + +OpenCode Go 包含以下限制: + +- **5 小時限制** — 12 美元的使用量 +- **每週限制** — 30 美元的使用量 +- **每月限制** — 60 美元的使用量 + +限制是以美元價值定義的。這意味著您的實際請求次數取決於您使用的模型。較便宜的模型(如 MiniMax M2.5)允許更多請求,而較高成本的模型(如 GLM-5)允許較少請求。 + +下表根據典型的 Go 使用模式提供估計的請求次數: + +| | GLM-5 | Kimi K2.5 | MiniMax M2.5 | +| --------------- | ----- | --------- | ------------ | +| 每 5 小時請求數 | 1,150 | 1,850 | 30,000 | +| 每週請求數 | 2,880 | 4,630 | 75,000 | +| 每月請求數 | 5,750 | 9,250 | 150,000 | + +估計值是根據觀察到的平均請求模式: + +- GLM-5 — 700 輸入, 52,000 快取, 150 輸出 token (每個請求) +- Kimi K2.5 — 870 輸入, 55,000 快取, 200 輸出 token (每個請求) +- MiniMax M2.5 — 300 輸入, 55,000 快取, 125 輸出 token (每個請求) + +您可以在 **<a href={console}>console</a>** 中追蹤目前的使用量。 + +:::tip +如果您達到使用限制,您可以繼續使用免費模型。 +::: + +使用限制可能會隨著我們從早期使用和回饋中學習而變動。 + +--- + +### 定價 + +OpenCode Go 是一個 **每月 10 美元** 的訂閱方案。以下是 **每 100 萬 token** 的價格。 + +| 模型 | 輸入 | 輸出 | 快取讀取 | +| ------------ | ----- | ----- | -------- | +| GLM-5 | $1.00 | $3.20 | $0.20 | +| Kimi K2.5 | $0.60 | $3.00 | $0.10 | +| MiniMax M2.5 | $0.30 | $1.20 | $0.03 | + +--- + +### 超出限制的使用 + +如果您的 Zen 餘額中也有點數,您可以在 console 中啟用 **Use balance** 選項。啟用後,當您達到使用限制時,Go 將會改用您的 Zen 餘額,而不是封鎖請求。 + +--- + +## 端點 + +您也可以透過以下 API 端點存取 Go 模型。 + +| 模型 | Model ID | 端點 | AI SDK 套件 | +| ------------ | ------------ | ------------------------------------------------ | --------------------------- | +| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` | + +您 OpenCode 設定中的 [model id](/docs/config/#models) 使用 `opencode-go/<model-id>` 格式。例如,對於 Kimi K2.5,您會在設定中使用 `opencode-go/kimi-k2.5`。 + +--- + +## 隱私權 + +此方案主要是為國際使用者設計,模型託管在美國、歐盟和新加坡,以提供穩定的全球存取。 + +如果您有任何問題,請 <a href={email}>聯絡我們</a>。 + +--- + +## 目標 + +我們建立 OpenCode Go 是為了: + +1. 透過低成本訂閱,讓更多人能 **輕易取得** AI 程式設計資源。 +2. 提供對最佳開放程式設計模型的 **可靠** 存取。 +3. 策劃經過 **測試和基準測試** 的模型,以供程式設計代理使用。 +4. **沒有鎖定**,允許您在 OpenCode 中同時使用任何其他供應商。 diff --git a/packages/web/src/content/docs/zh-tw/keybinds.mdx b/packages/web/src/content/docs/zh-tw/keybinds.mdx index d1458dfe8c..574404b2fd 100644 --- a/packages/web/src/content/docs/zh-tw/keybinds.mdx +++ b/packages/web/src/content/docs/zh-tw/keybinds.mdx @@ -3,11 +3,11 @@ title: 快捷鍵 description: 自訂您的快捷鍵。 --- -OpenCode 提供了一系列快捷鍵,您可以透過 OpenCode 設定進行自訂。 +OpenCode 提供了一系列快捷鍵,您可以透過 `tui.json` 進行自訂。 -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "keybinds": { "leader": "ctrl+x", "app_exit": "ctrl+c,ctrl+d,<leader>q", @@ -28,6 +28,7 @@ OpenCode 提供了一系列快捷鍵,您可以透過 OpenCode 設定進行自 "session_unshare": "none", "session_interrupt": "escape", "session_compact": "<leader>c", + "session_child_first": "<leader>down", "session_child_cycle": "<leader>right", "session_child_cycle_reverse": "<leader>left", "session_parent": "<leader>up", @@ -117,11 +118,11 @@ OpenCode 的大多數快捷鍵使用 `leader`(前導鍵)。這可以避免 ## 停用快捷鍵 -您可以透過在設定中將對應的鍵值設定為 "none" 來停用某個快捷鍵。 +您可以透過在 `tui.json` 中將對應的鍵值設定為 "none" 來停用某個快捷鍵。 -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "keybinds": { "session_compact": "none" } diff --git a/packages/web/src/content/docs/zh-tw/lsp.mdx b/packages/web/src/content/docs/zh-tw/lsp.mdx index ae419261ff..aa3af32881 100644 --- a/packages/web/src/content/docs/zh-tw/lsp.mdx +++ b/packages/web/src/content/docs/zh-tw/lsp.mdx @@ -27,6 +27,7 @@ OpenCode 內建了多種適用於主流語言的 LSP 伺服器: | gopls | .go | 需要 `go` 指令可用 | | hls | .hs, .lhs | 需要 `haskell-language-server-wrapper` 指令可用 | | jdtls | .java | 需要已安裝 `Java SDK (version 21+)` | +| julials | .jl | 需要已安裝 `julia` 和 `LanguageServer.jl` | | kotlin-ls | .kt, .kts | 為 Kotlin 專案自動安裝 | | lua-ls | .lua | 為 Lua 專案自動安裝 | | nixd | .nix | 需要 `nixd` 指令可用 | diff --git a/packages/web/src/content/docs/zh-tw/plugins.mdx b/packages/web/src/content/docs/zh-tw/plugins.mdx index 5e84f3a353..8163c291e0 100644 --- a/packages/web/src/content/docs/zh-tw/plugins.mdx +++ b/packages/web/src/content/docs/zh-tw/plugins.mdx @@ -307,6 +307,10 @@ export const CustomToolsPlugin: Plugin = async (ctx) => { 您的自訂工具將與內建工具一起在 OpenCode 中可用。 +:::note +如果外掛工具使用與內建工具相同的名稱,則外掛工具具有優先權。 +::: + --- ### 日誌記錄 diff --git a/packages/web/src/content/docs/zh-tw/providers.mdx b/packages/web/src/content/docs/zh-tw/providers.mdx index 12c4ded4e3..b673b1ade5 100644 --- a/packages/web/src/content/docs/zh-tw/providers.mdx +++ b/packages/web/src/content/docs/zh-tw/providers.mdx @@ -55,7 +55,7 @@ OpenCode Zen 是由 OpenCode 團隊提供的模型列表,這些模型已經過 如果您是新使用者,我們建議從 OpenCode Zen 開始。 ::: -1. 在 TUI 中執行 `/connect` 指令,選擇 opencode,然後前往 [opencode.ai/auth](https://opencode.ai/auth)。 +1. 在 TUI 中執行 `/connect` 指令,選擇 `OpenCode Zen`,然後前往 [opencode.ai/auth](https://opencode.ai/zen)。 ```txt /connect @@ -82,6 +82,37 @@ OpenCode Zen 是由 OpenCode 團隊提供的模型列表,這些模型已經過 --- +## OpenCode Go + +OpenCode Go 是一個低成本的訂閱計畫,提供對 OpenCode 團隊提供的流行開放編碼模型的可靠存取,這些模型已經過測試和驗證,能夠與 OpenCode 良好配合使用。 + +1. 在 TUI 中執行 `/connect` 指令,選擇 `OpenCode Go`,然後前往 [opencode.ai/auth](https://opencode.ai/zen)。 + + ```txt + /connect + ``` + +2. 登入後新增帳單資訊,然後複製您的 API 金鑰。 + +3. 貼上您的 API 金鑰。 + + ```txt + ┌ API key + │ + │ + └ enter + ``` + +4. 在 TUI 中執行 `/models` 查看我們推薦的模型列表。 + + ```txt + /models + ``` + +它的使用方式與 OpenCode 中的任何其他提供商相同,且完全可選。 + +--- + ## 目錄 下面我們來詳細了解一些提供商。如果您想將某個提供商新增到列表中,歡迎提交 PR。 diff --git a/packages/web/src/content/docs/zh-tw/share.mdx b/packages/web/src/content/docs/zh-tw/share.mdx index 1512007bc3..58365035b6 100644 --- a/packages/web/src/content/docs/zh-tw/share.mdx +++ b/packages/web/src/content/docs/zh-tw/share.mdx @@ -41,7 +41,7 @@ OpenCode 支援三種分享模式,用於控制對話的共享方式: ```json title="opencode.json" { - "$schema": "https://opncd.ai/config.json", + "$schema": "https://opencode.ai/config.json", "share": "manual" } ``` @@ -54,7 +54,7 @@ OpenCode 支援三種分享模式,用於控制對話的共享方式: ```json title="opencode.json" { - "$schema": "https://opncd.ai/config.json", + "$schema": "https://opencode.ai/config.json", "share": "auto" } ``` @@ -69,7 +69,7 @@ OpenCode 支援三種分享模式,用於控制對話的共享方式: ```json title="opencode.json" { - "$schema": "https://opncd.ai/config.json", + "$schema": "https://opencode.ai/config.json", "share": "disabled" } ``` diff --git a/packages/web/src/content/docs/zh-tw/themes.mdx b/packages/web/src/content/docs/zh-tw/themes.mdx index 513f2c8a77..256b78ccb6 100644 --- a/packages/web/src/content/docs/zh-tw/themes.mdx +++ b/packages/web/src/content/docs/zh-tw/themes.mdx @@ -61,11 +61,11 @@ OpenCode 自帶多個內建主題。 ## 使用主題 -您可以透過 `/theme` 指令調出主題選擇介面來選擇主題,也可以在[設定](/docs/config)檔案中直接指定。 +您可以透過 `/theme` 指令調出主題選擇介面來選擇主題,也可以在 `tui.json` 中直接指定。 -```json title="opencode.json" {3} +```json title="tui.json" {3} { - "$schema": "https://opencode.ai/config.json", + "$schema": "https://opencode.ai/tui.json", "theme": "tokyonight" } ``` diff --git a/packages/web/src/content/docs/zh-tw/tui.mdx b/packages/web/src/content/docs/zh-tw/tui.mdx index 017507f20e..8f46c4c15b 100644 --- a/packages/web/src/content/docs/zh-tw/tui.mdx +++ b/packages/web/src/content/docs/zh-tw/tui.mdx @@ -352,24 +352,34 @@ How is auth handled in @packages/functions/src/api/index.ts? ## 設定 -您可以透過 OpenCode 設定檔自訂 TUI 行為。 +您可以透過 `tui.json`(或 `tui.jsonc`)自訂 TUI 行為。 -```json title="opencode.json" +```json title="tui.json" { - "$schema": "https://opencode.ai/config.json", - "tui": { - "scroll_speed": 3, - "scroll_acceleration": { - "enabled": true - } - } + "$schema": "https://opencode.ai/tui.json", + "theme": "opencode", + "keybinds": { + "leader": "ctrl+x" + }, + "scroll_speed": 3, + "scroll_acceleration": { + "enabled": true + }, + "diff_style": "auto" } ``` +這與設定伺服器/執行時行為的 `opencode.json` 是分開的。 + ### 選項 -- `scroll_acceleration` - 啟用 macOS 風格的捲動加速,實現平滑、自然的捲動體驗。啟用後,快速捲動時速度會增加,慢速移動時保持精確。**此設定優先於 `scroll_speed`,啟用時會覆蓋它。** -- `scroll_speed` - 控制使用捲動指令時 TUI 的捲動速度(最小值:`1`)。預設為 `3`。**注意:如果 `scroll_acceleration.enabled` 設定為 `true`,則此設定會被忽略。** +- `theme` - 設定您的 UI 主題。[了解更多](/docs/themes)。 +- `keybinds` - 自訂鍵盤快速鍵。[了解更多](/docs/keybinds)。 +- `scroll_acceleration.enabled` - 啟用 macOS 風格的捲動加速,實現平滑、自然的捲動體驗。啟用後,快速捲動時速度會增加,慢速移動時保持精確。**此設定優先於 `scroll_speed`,啟用時會覆蓋它。** +- `scroll_speed` - 控制使用捲動指令時 TUI 的捲動速度(最小值:`0.001`,支援小數值)。預設為 `3`。**注意:如果 `scroll_acceleration.enabled` 設定為 `true`,則此設定會被忽略。** +- `diff_style` - 控制差異呈現方式。`"auto"` 根據終端機寬度自適應,`"stacked"` 始終顯示單列。 + +使用 `OPENCODE_TUI_CONFIG` 載入自訂 TUI 設定路徑。 --- diff --git a/packages/web/src/content/docs/zh-tw/zen.mdx b/packages/web/src/content/docs/zh-tw/zen.mdx index 5216194a93..c0ef9d03bd 100644 --- a/packages/web/src/content/docs/zh-tw/zen.mdx +++ b/packages/web/src/content/docs/zh-tw/zen.mdx @@ -55,6 +55,8 @@ OpenCode Zen 的工作方式與 OpenCode 中的任何其他供應商相同。 | 模型 | 模型 ID | 端點 | AI SDK 套件 | | ------------------ | ------------------ | -------------------------------------------------- | --------------------------- | +| GPT 5.4 | gpt-5.4 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| GPT 5.3 Codex | gpt-5.3-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.2 | gpt-5.2 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.2 Codex | gpt-5.2-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5.1 | gpt-5.1 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | @@ -64,13 +66,15 @@ OpenCode Zen 的工作方式與 OpenCode 中的任何其他供應商相同。 | GPT 5 | gpt-5 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5 Codex | gpt-5-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | | GPT 5 Nano | gpt-5-nano | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` | +| Claude Opus 4.6 | claude-opus-4-6 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Opus 4.5 | claude-opus-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Opus 4.1 | claude-opus-4-1 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Sonnet 4.6 | claude-sonnet-4-6 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Sonnet 4.5 | claude-sonnet-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Sonnet 4 | claude-sonnet-4 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Haiku 4.5 | claude-haiku-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Haiku 3.5 | claude-3-5-haiku | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| Claude Opus 4.6 | claude-opus-4-6 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| Claude Opus 4.5 | claude-opus-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | -| Claude Opus 4.1 | claude-opus-4-1 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Gemini 3.1 Pro | gemini-3.1-pro | `https://opencode.ai/zen/v1/models/gemini-3.1-pro` | `@ai-sdk/google` | | Gemini 3 Pro | gemini-3-pro | `https://opencode.ai/zen/v1/models/gemini-3-pro` | `@ai-sdk/google` | | Gemini 3 Flash | gemini-3-flash | `https://opencode.ai/zen/v1/models/gemini-3-flash` | `@ai-sdk/google` | | MiniMax M2.5 | minimax-m2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -80,7 +84,6 @@ OpenCode Zen 的工作方式與 OpenCode 中的任何其他供應商相同。 | GLM 4.7 | glm-4.7 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | GLM 4.6 | glm-4.6 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2.5 Free | kimi-k2.5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2 Thinking | kimi-k2-thinking | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Kimi K2 | kimi-k2 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Qwen3 Coder 480B | qwen3-coder | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | @@ -113,24 +116,29 @@ https://opencode.ai/zen/v1/models | GLM 5 | $1.00 | $3.20 | $0.20 | - | | GLM 4.7 | $0.60 | $2.20 | $0.10 | - | | GLM 4.6 | $0.60 | $2.20 | $0.10 | - | -| Kimi K2.5 Free | 免費 | 免費 | 免費 | - | | Kimi K2.5 | $0.60 | $3.00 | $0.08 | - | | Kimi K2 Thinking | $0.40 | $2.50 | - | - | | Kimi K2 | $0.40 | $2.50 | - | - | | Qwen3 Coder 480B | $0.45 | $1.50 | - | - | +| Claude Opus 4.6 (≤ 200K Token) | $5.00 | $25.00 | $0.50 | $6.25 | +| Claude Opus 4.6 (> 200K Token) | $10.00 | $37.50 | $1.00 | $12.50 | +| Claude Opus 4.5 | $5.00 | $25.00 | $0.50 | $6.25 | +| Claude Opus 4.1 | $15.00 | $75.00 | $1.50 | $18.75 | +| Claude Sonnet 4.6 (≤ 200K Token) | $3.00 | $15.00 | $0.30 | $3.75 | +| Claude Sonnet 4.6 (> 200K Token) | $6.00 | $22.50 | $0.60 | $7.50 | | Claude Sonnet 4.5 (≤ 200K Token) | $3.00 | $15.00 | $0.30 | $3.75 | | Claude Sonnet 4.5 (> 200K Token) | $6.00 | $22.50 | $0.60 | $7.50 | | Claude Sonnet 4 (≤ 200K Token) | $3.00 | $15.00 | $0.30 | $3.75 | | Claude Sonnet 4 (> 200K Token) | $6.00 | $22.50 | $0.60 | $7.50 | | Claude Haiku 4.5 | $1.00 | $5.00 | $0.10 | $1.25 | | Claude Haiku 3.5 | $0.80 | $4.00 | $0.08 | $1.00 | -| Claude Opus 4.6 (≤ 200K Token) | $5.00 | $25.00 | $0.50 | $6.25 | -| Claude Opus 4.6 (> 200K Token) | $10.00 | $37.50 | $1.00 | $12.50 | -| Claude Opus 4.5 | $5.00 | $25.00 | $0.50 | $6.25 | -| Claude Opus 4.1 | $15.00 | $75.00 | $1.50 | $18.75 | +| Gemini 3.1 Pro (≤ 200K Token) | $2.00 | $12.00 | $0.20 | - | +| Gemini 3.1 Pro (> 200K Token) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Pro (≤ 200K Token) | $2.00 | $12.00 | $0.20 | - | | Gemini 3 Pro (> 200K Token) | $4.00 | $18.00 | $0.40 | - | | Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - | +| GPT 5.4 | $2.50 | $15.00 | $0.25 | - | +| GPT 5.3 Codex | $1.75 | $14.00 | $0.175 | - | | GPT 5.2 | $1.75 | $14.00 | $0.175 | - | | GPT 5.2 Codex | $1.75 | $14.00 | $0.175 | - | | GPT 5.1 | $1.07 | $8.50 | $0.107 | - | @@ -149,7 +157,6 @@ https://opencode.ai/zen/v1/models 免費模型說明: -- Kimi K2.5 Free 在 OpenCode 上限時免費提供。團隊正在利用這段時間收集回饋並改進模型。 - MiniMax M2.5 Free 在 OpenCode 上限時免費提供。團隊正在利用這段時間收集回饋並改進模型。 - Big Pickle 是一個隱身模型,在 OpenCode 上限時免費提供。團隊正在利用這段時間收集回饋並改進模型。 @@ -173,12 +180,24 @@ https://opencode.ai/zen/v1/models --- +### 已棄用的模型 + +| 模型 | 棄用日期 | +| ---------------- | ------------------ | +| Qwen3 Coder 480B | 2026 年 2 月 6 日 | +| Kimi K2 Thinking | 2026 年 3 月 6 日 | +| Kimi K2 | 2026 年 3 月 6 日 | +| MiniMax M2.1 | 2026 年 3 月 15 日 | +| GLM 4.7 | 2026 年 3 月 15 日 | +| GLM 4.6 | 2026 年 3 月 15 日 | + +--- + ## 隱私 我們所有的模型都託管在美國。我們的供應商遵循零保留政策,不會將你的資料用於模型訓練,但以下情況除外: - Big Pickle:在免費期間,收集的資料可能會被用於改進模型。 -- Kimi K2.5 Free:在免費期間,收集的資料可能會被用於改進模型。 - MiniMax M2.5 Free:在免費期間,收集的資料可能會被用於改進模型。 - OpenAI API:請求會根據 [OpenAI 資料政策](https://platform.openai.com/docs/guides/your-data)保留 30 天。 - Anthropic API:請求會根據 [Anthropic 資料政策](https://docs.anthropic.com/en/docs/claude-code/data-usage)保留 30 天。 diff --git a/script/beta.ts b/script/beta.ts index a5fb027e63..b0e6c2dcc1 100755 --- a/script/beta.ts +++ b/script/beta.ts @@ -30,6 +30,52 @@ Please resolve this issue to include this PR in the next beta release.` } } +async function conflicts() { + const out = await $`git diff --name-only --diff-filter=U`.text().catch(() => "") + return out + .split("\n") + .map((x) => x.trim()) + .filter(Boolean) +} + +async function cleanup() { + try { + await $`git merge --abort` + } catch {} + try { + await $`git checkout -- .` + } catch {} + try { + await $`git clean -fd` + } catch {} +} + +async function fix(pr: PR, files: string[]) { + console.log(` Trying to auto-resolve ${files.length} conflict(s) with opencode...`) + const prompt = [ + `Resolve the current git merge conflicts while merging PR #${pr.number} into the beta branch.`, + `Only touch these files: ${files.join(", ")}.`, + "Keep the merge in progress, do not abort the merge, and do not create a commit.", + "When done, leave the working tree with no unmerged files.", + ].join("\n") + + try { + await $`opencode run -m opencode/gpt-5.3-codex ${prompt}` + } catch (err) { + console.log(` opencode failed: ${err}`) + return false + } + + const left = await conflicts() + if (left.length > 0) { + console.log(` Conflicts remain: ${left.join(", ")}`) + return false + } + + console.log(" Conflicts resolved with opencode") + return true +} + async function main() { console.log("Fetching open PRs with beta label...") @@ -69,19 +115,22 @@ async function main() { try { await $`git merge --no-commit --no-ff pr/${pr.number}` } catch { - console.log(" Failed to merge (conflicts)") - try { - await $`git merge --abort` - } catch {} - try { - await $`git checkout -- .` - } catch {} - try { - await $`git clean -fd` - } catch {} - failed.push({ number: pr.number, title: pr.title, reason: "Merge conflicts" }) - await commentOnPR(pr.number, "Merge conflicts with dev branch") - continue + const files = await conflicts() + if (files.length > 0) { + console.log(" Failed to merge (conflicts)") + if (!(await fix(pr, files))) { + await cleanup() + failed.push({ number: pr.number, title: pr.title, reason: "Merge conflicts" }) + await commentOnPR(pr.number, "Merge conflicts with dev branch") + continue + } + } else { + console.log(" Failed to merge") + await cleanup() + failed.push({ number: pr.number, title: pr.title, reason: "Merge failed" }) + await commentOnPR(pr.number, "Merge failed") + continue + } } try { diff --git a/script/publish.ts b/script/publish.ts index 8aa921daa8..3889845fa6 100755 --- a/script/publish.ts +++ b/script/publish.ts @@ -1,7 +1,8 @@ #!/usr/bin/env bun -import { $ } from "bun" import { Script } from "@opencode-ai/script" +import { $ } from "bun" +import { fileURLToPath } from "url" const highlightsTemplate = ` <!-- @@ -46,7 +47,7 @@ for (const file of pkgjsons) { await Bun.file(file).write(pkg) } -const extensionToml = new URL("../packages/extensions/zed/extension.toml", import.meta.url).pathname +const extensionToml = fileURLToPath(new URL("../packages/extensions/zed/extension.toml", import.meta.url)) let toml = await Bun.file(extensionToml).text() toml = toml.replace(/^version = "[^"]+"/m, `version = "${Script.version}"`) toml = toml.replaceAll(/releases\/download\/v[^/]+\//g, `releases/download/v${Script.version}/`) @@ -66,6 +67,9 @@ if (Script.release) { await new Promise((resolve) => setTimeout(resolve, 5_000)) } + await import(`../packages/desktop/scripts/finalize-latest-json.ts`) + await import(`../packages/desktop-electron/scripts/finalize-latest-yml.ts`) + await $`gh release edit v${Script.version} --draft=false --repo ${process.env.GH_REPO}` } @@ -78,5 +82,5 @@ await import(`../packages/sdk/js/script/publish.ts`) console.log("\n=== plugin ===\n") await import(`../packages/plugin/script/publish.ts`) -const dir = new URL("..", import.meta.url).pathname +const dir = fileURLToPath(new URL("..", import.meta.url)) process.chdir(dir) diff --git a/sdks/vscode/package.json b/sdks/vscode/package.json index 2e2807923e..6eedb0d751 100644 --- a/sdks/vscode/package.json +++ b/sdks/vscode/package.json @@ -2,7 +2,7 @@ "name": "opencode", "displayName": "opencode", "description": "opencode for VS Code", - "version": "1.2.10", + "version": "1.2.24", "publisher": "sst-dev", "repository": { "type": "git", diff --git a/specs/session-composer-refactor-plan.md b/specs/session-composer-refactor-plan.md deleted file mode 100644 index 08fb0d8323..0000000000 --- a/specs/session-composer-refactor-plan.md +++ /dev/null @@ -1,240 +0,0 @@ -# Session Composer Refactor Plan - -## Goal - -Improve structure, ownership, and reuse for the bottom-of-session composer area without changing user-visible behavior. - -Scope: - -- `packages/ui/src/components/dock-prompt.tsx` -- `packages/app/src/components/session-todo-dock.tsx` -- `packages/app/src/components/question-dock.tsx` -- `packages/app/src/pages/session/session-prompt-dock.tsx` -- related shared UI in `packages/app/src/components/prompt-input.tsx` - -## Decisions Up Front - -1. **`session-prompt-dock` should stay route-scoped.** - It is session-page orchestration, so it belongs under `pages/session`, not global `src/components`. - -2. **The orchestrator should keep blocking ownership.** - A single component should decide whether to show blockers (`question`/`permission`) or the regular prompt input. This avoids drift and duplicate logic. - -3. **Current component does too much.** - Split state derivation, permission actions, and rendering into smaller units while preserving behavior. - -4. **There is style duplication worth addressing.** - The prompt top shell and lower tray (`prompt-input.tsx`) visually overlap with dock shells/footers and todo containers. We should extract reusable dock surface primitives. - ---- - -## Phase 0 (Mandatory Gate): Baseline E2E Coverage - -No refactor work starts until this phase is complete and green locally. - -### 0.1 Deterministic test harness - -Add a test-only way to put a session into exact dock states, so tests do not rely on model/tool nondeterminism. - -Proposed implementation: - -- Add a guarded e2e route in backend (enabled only when a dedicated env flag is set by e2e-local runner). - - New route file: `packages/opencode/src/server/routes/e2e.ts` - - Mount from: `packages/opencode/src/server/server.ts` - - Gate behind env flag (for example `OPENCODE_E2E=1`) so this route is never exposed in normal runs. -- Add seed helpers in app e2e layer: - - `packages/app/e2e/actions.ts` (or `fixtures.ts`) helpers to: - - seed question request for a session - - seed permission request for a session - - seed/update todos for a session - - clear seeded blockers/todos -- Update e2e-local runner to set the flag: - - `packages/app/script/e2e-local.ts` - -### 0.2 New e2e spec - -Create a focused spec: - -- `packages/app/e2e/session/session-composer-dock.spec.ts` - -Test matrix (minimum required): - -1. **Default prompt dock** - - no blocker state - - assert prompt input is visible and focusable - - assert blocker cards are absent - -2. **Blocked question flow** - - seed question request for session - - assert question dock renders - - assert prompt input is not shown/active - - answer and submit - - assert unblock and prompt input returns - -3. **Blocked permission flow** - - seed permission request with patterns + optional description - - assert permission dock renders expected actions - - assert prompt input is not shown/active - - test each response path (`once`, `always`, `reject`) across tests - - assert unblock behavior - -4. **Todo dock transitions and collapse behavior** - - seed todos with `pending`/`in_progress` - - assert todo dock appears above prompt and can collapse/expand - - update todos to all completed/cancelled - - assert close animation path and eventual hide - -5. **Keyboard focus behavior while blocked** - - with blocker active, typing from document context must not focus prompt input - - blocker actions remain keyboard reachable - -Notes: - -- Prefer stable selectors (`data-component`, `data-slot`, role/name). -- Extend `packages/app/e2e/selectors.ts` as needed. -- Use `expect.poll` for async transitions. - -### 0.3 Gate commands (must pass before Phase 1) - -Run from `packages/app` (never from repo root): - -```bash -bun test:e2e:local -- e2e/session/session-composer-dock.spec.ts -bun test:e2e:local -- e2e/prompt/prompt.spec.ts e2e/prompt/prompt-multiline.spec.ts e2e/commands/input-focus.spec.ts -bun test:e2e:local -``` - -If any fail, stop and fix before refactor. - ---- - -## Phase 1: Structural Refactor (No Intended Behavior Changes) - -### 1.1 Colocate session-composer files - -Create a route-local composer folder: - -```txt -packages/app/src/pages/session/composer/ - session-composer-region.tsx # rename/move from session-prompt-dock.tsx - session-composer-state.ts # derived state + actions - session-permission-dock.tsx # extracted from inline JSX - session-question-dock.tsx # moved from src/components/question-dock.tsx - session-todo-dock.tsx # moved from src/components/session-todo-dock.tsx - index.ts -``` - -Import updates: - -- `packages/app/src/pages/session.tsx` imports `SessionComposerRegion` from `pages/session/composer`. - -### 1.2 Split responsibilities - -- Keep `session-composer-region.tsx` focused on rendering orchestration: - - blocker mode vs normal mode - - relative stacking (todo above prompt) - - handoff fallback rendering -- Move side-effect/business pieces into `session-composer-state.ts`: - - derive `questionRequest`, `permissionRequest`, `blocked`, todo visibility state - - permission response action + in-flight state - - todo close/open animation state - -### 1.3 Remove duplicate blocked logic in `session.tsx` - -Current `session.tsx` computes `blocked` independently. Make the composer state the single source for blocker status consumed by both: - -- page-level keydown autofocus guard -- composer rendering guard - -### 1.4 Keep prompt gating in orchestrator - -`session-composer-region` should remain responsible for choosing whether `PromptInput` renders when blocked. - -Rationale: - -- this is layout-mode orchestration, not prompt implementation detail -- keeps blocker and prompt transitions coordinated in one place - -### 1.5 Phase 1 acceptance criteria - -- No intentional behavior deltas. -- Phase 0 suite remains green. -- `session-prompt-dock` no longer exists as a large mixed-responsibility component. -- Session composer files are colocated under `pages/session/composer`. - ---- - -## Phase 2: Reuse + Styling Maintainability - -### 2.1 Extract shared dock surface primitives - -Create reusable shell/tray wrappers to remove repeated visual scaffolding: - -- primary elevated surface (prompt top shell / dock body) -- secondary tray surface (prompt bottom bar / dock footer / todo shell) - -Proposed targets: - -- `packages/ui/src/components` for shared primitives if reused by both app and ui components -- or `packages/app/src/pages/session/composer` first, then promote to ui after proving reuse - -### 2.2 Apply primitives to current components - -Adopt in: - -- `packages/app/src/components/prompt-input.tsx` -- `packages/app/src/pages/session/composer/session-todo-dock.tsx` -- `packages/ui/src/components/dock-prompt.tsx` (where appropriate) - -Focus on deduping patterns seen in: - -- prompt elevated shell styles (`prompt-input.tsx` form container) -- prompt lower tray (`prompt-input.tsx` bottom panel) -- dock prompt footer/body and todo dock container - -### 2.3 De-risk style ownership - -- Move dock-specific styling out of overly broad files (for example, avoid keeping new dock-specific rules buried in unrelated message-part styling files). -- Keep slot names stable unless tests are updated in the same PR. - -### 2.4 Optional follow-up (if low risk) - -Evaluate extracting shared question/permission presentational pieces used by: - -- `packages/app/src/pages/session/composer/session-question-dock.tsx` -- `packages/ui/src/components/message-part.tsx` - -Only do this if behavior parity is protected by tests and the change is still reviewable. - -### 2.5 Phase 2 acceptance criteria - -- Reduced duplicated shell/tray styling code. -- No regressions in blocker/todo/prompt transitions. -- Phase 0 suite remains green. - ---- - -## Implementation Sequence (single branch) - -1. **Step A - Baseline safety net** - - Add e2e harness + new session composer dock spec + selector/helpers. - - Must pass locally before any refactor work proceeds. - -2. **Step B - Phase 1 colocation/splitting** - - Move/rename files, extract state and permission component, keep behavior. - -3. **Step C - Phase 1 dedupe blocked source** - - Remove duplicate blocked derivation and wire page autofocus guard to shared source. - -4. **Step D - Phase 2 style primitives** - - Introduce shared surface primitives and migrate prompt/todo/dock usage. - -5. **Step E (optional) - shared question/permission presentational extraction** - ---- - -## Rollback Strategy - -- Keep each step logically isolated and easy to revert. -- If regressions occur, revert the latest completed step first and rerun the Phase 0 suite. -- If style extraction destabilizes behavior, keep structural Phase 1 changes and revert only Phase 2 styling commits. diff --git a/sst-env.d.ts b/sst-env.d.ts index 6b3ec54dee..c8622a5a9a 100644 --- a/sst-env.d.ts +++ b/sst-env.d.ts @@ -145,10 +145,6 @@ declare module "sst" { "type": "sst.cloudflare.StaticSite" "url": string } - "ZEN_BLACK_LIMITS": { - "type": "sst.sst.Secret" - "value": string - } "ZEN_BLACK_PRICE": { "plan100": string "plan20": string @@ -156,6 +152,15 @@ declare module "sst" { "product": string "type": "sst.sst.Linkable" } + "ZEN_LIMITS": { + "type": "sst.sst.Secret" + "value": string + } + "ZEN_LITE_PRICE": { + "price": string + "product": string + "type": "sst.sst.Linkable" + } "ZEN_MODELS1": { "type": "sst.sst.Secret" "value": string diff --git a/turbo.json b/turbo.json index f06ddb0e8b..57e4f11953 100644 --- a/turbo.json +++ b/turbo.json @@ -1,11 +1,11 @@ { - "$schema": "https://turborepo.com/schema.json", + "$schema": "https://v2-8-13.turborepo.dev/schema.json", "globalEnv": ["CI", "OPENCODE_DISABLE_SHARE"], "globalPassThroughEnv": ["CI", "OPENCODE_DISABLE_SHARE"], "tasks": { "typecheck": {}, "build": { - "dependsOn": ["^build"], + "dependsOn": [], "outputs": ["dist/**"] }, "opencode#test": {